From 8e459d0ccd52140b43daffbc8be1e6fea424730d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B5=B5=E6=AD=A3=E6=98=93?= Date: Sun, 21 Sep 2025 13:52:06 +0800 Subject: [PATCH] =?UTF-8?q?feat(mqtt):=20=E6=B7=BB=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E6=95=B0=E6=8D=AE=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=8F=8A=E7=9B=B8=E5=85=B3=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 实现设备数据通过MQTT上传功能,包括: 1. 新增DeviceUploadData实体及DTO 2. 添加MQTT服务处理设备消息 3. 实现设备数据存储逻辑 4. 创建相关控制器和服务接口 --- .../mes/dc/DeviceUploadDataController.cs | 105 ++++++++++++++ .../Controllers/mqtt/MqttController.cs | 1 + ZR.Admin.WebApi/Program.cs | 1 + .../Generatecode/ZrAdmin.NET--0921123904.zip | Bin 0 -> 8511 bytes ZR.Common/ZR.Common.csproj | 1 + ZR.Model/MES/dc/DeviceUploadData.cs | 114 ++++++++++++++++ ZR.Model/MES/dc/Dto/DeviceUploadDataDto.cs | 129 ++++++++++++++++++ ZR.Service/ZR.Service.csproj | 1 - ZR.Service/mes/dc/DeviceUploadDataService.cs | 89 ++++++++++++ .../dc/IService/IDeviceUploadDataService.cs | 21 +++ ZR.Service/mes/qc/backend/QcBackEndService.cs | 1 + .../mqtt}/MqttService.cs | 123 +++++++++++++---- 12 files changed, 560 insertions(+), 26 deletions(-) create mode 100644 ZR.Admin.WebApi/Controllers/mes/dc/DeviceUploadDataController.cs create mode 100644 ZR.Admin.WebApi/wwwroot/Generatecode/ZrAdmin.NET--0921123904.zip create mode 100644 ZR.Model/MES/dc/DeviceUploadData.cs create mode 100644 ZR.Model/MES/dc/Dto/DeviceUploadDataDto.cs create mode 100644 ZR.Service/mes/dc/DeviceUploadDataService.cs create mode 100644 ZR.Service/mes/dc/IService/IDeviceUploadDataService.cs rename {ZR.Common/MqttHelper => ZR.Service/mqtt}/MqttService.cs (74%) diff --git a/ZR.Admin.WebApi/Controllers/mes/dc/DeviceUploadDataController.cs b/ZR.Admin.WebApi/Controllers/mes/dc/DeviceUploadDataController.cs new file mode 100644 index 00000000..a3808d96 --- /dev/null +++ b/ZR.Admin.WebApi/Controllers/mes/dc/DeviceUploadDataController.cs @@ -0,0 +1,105 @@ +using Microsoft.AspNetCore.Mvc; +using ZR.Model.Dto; +using ZR.Model.Business; +using ZR.Service.Business.IBusinessService; +using ZR.Admin.WebApi.Extensions; +using ZR.Admin.WebApi.Filters; +using ZR.Service.MES.dc.IService; +using ZR.Model.dc; + +//创建时间:2025-09-21 +namespace ZR.Admin.WebApi.Controllers +{ + /// + /// 设备数据上传 + /// + [Route("business/DeviceUploadData")] + public class DeviceUploadDataController : BaseController + { + /// + /// 接口 + /// + private readonly IDeviceUploadDataService _DeviceUploadDataService; + + public DeviceUploadDataController(IDeviceUploadDataService DeviceUploadDataService) + { + _DeviceUploadDataService = DeviceUploadDataService; + } + + /// + /// 查询列表 + /// + /// + /// + [HttpGet("list")] + public IActionResult QueryDeviceUploadData([FromQuery] DeviceUploadDataQueryDto parm) + { + var response = _DeviceUploadDataService.GetList(parm); + return SUCCESS(response); + } + + + /// + /// 查询详情 + /// + /// + /// + [HttpGet("{Id}")] + public IActionResult GetDeviceUploadData(long Id) + { + var response = _DeviceUploadDataService.GetInfo(Id); + + var info = response.Adapt(); + return SUCCESS(info); + } + + /// + /// 添加 + /// + /// + [HttpPost] + [Log(Title = "", BusinessType = BusinessType.INSERT)] + public IActionResult AddDeviceUploadData([FromBody] DeviceUploadDataDto parm) + { + var modal = parm.Adapt().ToCreate(HttpContext); + + var response = _DeviceUploadDataService.AddDeviceUploadData(modal); + + return SUCCESS(response); + } + + /// + /// 更新 + /// + /// + [HttpPut] + [Log(Title = "", BusinessType = BusinessType.UPDATE)] + public IActionResult UpdateDeviceUploadData([FromBody] DeviceUploadDataDto parm) + { + var modal = parm.Adapt().ToUpdate(HttpContext); + var response = _DeviceUploadDataService.UpdateDeviceUploadData(modal); + + return ToResponse(response); + } + + /// + /// 删除 + /// + /// + [HttpDelete("{ids}")] + [Log(Title = "", BusinessType = BusinessType.DELETE)] + public IActionResult DeleteDeviceUploadData(string ids) + { + int[] idsArr = Tools.SpitIntArrary(ids); + if (idsArr.Length <= 0) { return ToResponse(ApiResult.Error($"删除失败Id 不能为空")); } + + var response = _DeviceUploadDataService.Delete(idsArr); + + return ToResponse(response); + } + + + + + } +} \ No newline at end of file diff --git a/ZR.Admin.WebApi/Controllers/mqtt/MqttController.cs b/ZR.Admin.WebApi/Controllers/mqtt/MqttController.cs index f829864c..6b882511 100644 --- a/ZR.Admin.WebApi/Controllers/mqtt/MqttController.cs +++ b/ZR.Admin.WebApi/Controllers/mqtt/MqttController.cs @@ -1,6 +1,7 @@ using Microsoft.AspNetCore.Mvc; using MQTTnet.Protocol; using ZR.Common.MqttHelper; +using ZR.Service.mqtt; namespace ZR.Admin.WebApi.Controllers { diff --git a/ZR.Admin.WebApi/Program.cs b/ZR.Admin.WebApi/Program.cs index 53f6ea0e..13cdaf64 100644 --- a/ZR.Admin.WebApi/Program.cs +++ b/ZR.Admin.WebApi/Program.cs @@ -12,6 +12,7 @@ using ZR.Admin.WebApi.Hubs; using ZR.Admin.WebApi.Middleware; using ZR.Common.Cache; using ZR.Common.MqttHelper; +using ZR.Service.mqtt; var builder = WebApplication.CreateBuilder(args); // Add services to the container. diff --git a/ZR.Admin.WebApi/wwwroot/Generatecode/ZrAdmin.NET--0921123904.zip b/ZR.Admin.WebApi/wwwroot/Generatecode/ZrAdmin.NET--0921123904.zip new file mode 100644 index 0000000000000000000000000000000000000000..090d4c4f8f6018221f87f3569583ce5b49ccde69 GIT binary patch literal 8511 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 + diff --git a/ZR.Model/MES/dc/DeviceUploadData.cs b/ZR.Model/MES/dc/DeviceUploadData.cs new file mode 100644 index 00000000..e50e6149 --- /dev/null +++ b/ZR.Model/MES/dc/DeviceUploadData.cs @@ -0,0 +1,114 @@ + +namespace ZR.Model.dc +{ + /// + /// + /// + [SugarTable("device_upload_data")] + public class DeviceUploadData + { + /// + /// 主键 + /// + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public long Id { get; set; } + + /// + /// 工厂 + /// + [SugarColumn(ColumnName = "factory_code")] + public string FactoryCode { get; set; } + + /// + /// 车间 + /// + [SugarColumn(ColumnName = "workshop_code")] + public string WorkshopCode { get; set; } + + /// + /// 线别 + /// + [SugarColumn(ColumnName = "line_code")] + public string LineCode { get; set; } + + /// + /// 设备 + /// + [SugarColumn(ColumnName = "device_code")] + public string DeviceCode { get; set; } + + /// + /// 字典编号 + /// + [SugarColumn(ColumnName = "dict_code")] + public string DictCode { get; set; } + + /// + /// 备注 + /// + public string Remark { get; set; } + + /// + /// 底漆循环温度DB1014.444 + /// + public string Value01 { get; set; } + + /// + /// 底漆循环湿度DB1014.498 + /// + public string Value02 { get; set; } + + /// + /// 色漆循环温度DB1014.552 + /// + public string Value03 { get; set; } + + /// + /// 色漆循环湿度DB1014.610 + /// + public string Value04 { get; set; } + + /// + /// 清漆循环温度DB1014.664 + /// + public string Value05 { get; set; } + + /// + /// 清漆循环湿度DB1014.722 + /// + public string Value06 { get; set; } + + /// + /// 纯水电导率DB1012.220 + /// + public string Value07 { get; set; } + + /// + /// 水份烘干温度DB1014.776 + /// + public string Value08 { get; set; } + + /// + /// 清漆烘干温度DB1014.892 + /// + public string Value09 { get; set; } + + /// + /// Value10 + /// + public string Value10 { get; set; } + + /// + /// 上传时间 + /// + [SugarColumn(ColumnName = "upload_time")] + public DateTime UploadTime { get; set; } = DateTime.Now; + + /// + /// 采集时间 + /// + [SugarColumn(ColumnName = "collection_time")] + public DateTime CollectionTime { get; set; } = DateTime.Now; + + } +} \ No newline at end of file diff --git a/ZR.Model/MES/dc/Dto/DeviceUploadDataDto.cs b/ZR.Model/MES/dc/Dto/DeviceUploadDataDto.cs new file mode 100644 index 00000000..18be1f49 --- /dev/null +++ b/ZR.Model/MES/dc/Dto/DeviceUploadDataDto.cs @@ -0,0 +1,129 @@ +using System.ComponentModel.DataAnnotations; +using System.Text.Json.Serialization; + +namespace ZR.Model.Dto +{ + /// + /// 查询对象 + /// + public class DeviceUploadDataQueryDto : PagerInfo + { + } + // 网关发来数据 + public class DeviceUploadDataGatWayDto + { + [JsonPropertyName("time")] + public long Time { get; set; } + [JsonPropertyName("params")] + public DeviceUploadDataParamsDto DeviceParams { get; set; } + } + /// + /// 传来参数对象 + /// + public class DeviceUploadDataParamsDto + { + /// + /// 底漆循环温度DB1014.444 + /// + [JsonPropertyName("Value01")] + public decimal Value01 { get; set; } + + /// + /// 底漆循环湿度DB1014.498 + /// + [JsonPropertyName("Value02")] + public decimal Value02 { get; set; } + + /// + /// 色漆循环温度DB1014.552 + /// + [JsonPropertyName("Value03")] + public decimal Value03 { get; set; } + + /// + /// 色漆循环湿度DB1014.610 + /// + [JsonPropertyName("Value04")] + public decimal Value04 { get; set; } + + /// + /// 清漆循环温度DB1014.664 + /// + [JsonPropertyName("Value05")] + public decimal Value05 { get; set; } + + /// + /// 清漆循环湿度DB1014.722 + /// + [JsonPropertyName("Value06")] + public decimal Value06 { get; set; } + + /// + /// 纯水电导率DB1012.220 + /// + [JsonPropertyName("Value07")] + public decimal Value07 { get; set; } + + /// + /// 水份烘干温度DB1014.776 + /// + [JsonPropertyName("Value08")] + public decimal Value08 { get; set; } + + /// + /// 清漆烘干温度DB1014.892 + /// + [JsonPropertyName("Value09")] + public decimal Value09 { get; set; } + + /// + /// Value10 + /// + [JsonPropertyName("Value10")] + public decimal Value10 { get; set; } + } + + /// + /// 输入输出对象 + /// + public class DeviceUploadDataDto + { + [Required(ErrorMessage = "主键不能为空")] + public long Id { get; set; } + + public string FactoryCode { get; set; } + + public string WorkshopCode { get; set; } + + public string LineCode { get; set; } + + public string DeviceCode { get; set; } + + public string DictCode { get; set; } + + public string Remark { get; set; } + + public string Value01 { get; set; } + + public string Value02 { get; set; } + + public string Value03 { get; set; } + + public string Value04 { get; set; } + + public string Value05 { get; set; } + + public string Value06 { get; set; } + + public string Value07 { get; set; } + + public string Value08 { get; set; } + + public string Value09 { get; set; } + + public string Value10 { get; set; } + + + + } +} \ No newline at end of file diff --git a/ZR.Service/ZR.Service.csproj b/ZR.Service/ZR.Service.csproj index 5d766791..dcda7a1c 100644 --- a/ZR.Service/ZR.Service.csproj +++ b/ZR.Service/ZR.Service.csproj @@ -23,7 +23,6 @@ - diff --git a/ZR.Service/mes/dc/DeviceUploadDataService.cs b/ZR.Service/mes/dc/DeviceUploadDataService.cs new file mode 100644 index 00000000..830229f5 --- /dev/null +++ b/ZR.Service/mes/dc/DeviceUploadDataService.cs @@ -0,0 +1,89 @@ +using Infrastructure.Attribute; +using SqlSugar; +using ZR.Model; +using ZR.Model.dc; +using ZR.Model.Dto; +using ZR.Repository; +using ZR.Service.MES.dc.IService; + +namespace ZR.Service.Business +{ + /// + /// Service业务层处理 + /// + [AppService(ServiceType = typeof(IDeviceUploadDataService), ServiceLifetime = LifeTime.Transient)] + public class DeviceUploadDataService : BaseService, IDeviceUploadDataService + { + /// + /// 查询列表 + /// + /// + /// + public PagedInfo GetList(DeviceUploadDataQueryDto parm) + { + var predicate = Expressionable.Create(); + + var response = Queryable() + .Where(predicate.ToExpression()) + .ToPage(parm); + + return response; + } + + + /// + /// 获取详情 + /// + /// + /// + public DeviceUploadData GetInfo(long Id) + { + var response = Queryable() + .Where(x => x.Id == Id) + .First(); + + return response; + } + + /// + /// 添加 + /// + /// + /// + public DeviceUploadData AddDeviceUploadData(DeviceUploadData model) + { + return Context.Insertable(model).ExecuteReturnEntity(); + } + + /// + /// 修改 + /// + /// + /// + public int UpdateDeviceUploadData(DeviceUploadData model) + { + //var response = Update(w => w.Id == model.Id, it => new DeviceUploadData() + //{ + // FactoryCode = model.FactoryCode, + // WorkshopCode = model.WorkshopCode, + // LineCode = model.LineCode, + // DeviceCode = model.DeviceCode, + // DictCode = model.DictCode, + // Remark = model.Remark, + // Value01 = model.Value01, + // Value02 = model.Value02, + // Value03 = model.Value03, + // Value04 = model.Value04, + // Value05 = model.Value05, + // Value06 = model.Value06, + // Value07 = model.Value07, + // Value08 = model.Value08, + // Value09 = model.Value09, + // Value10 = model.Value10, + //}); + //return response; + return Update(model, true); + } + + } +} \ No newline at end of file diff --git a/ZR.Service/mes/dc/IService/IDeviceUploadDataService.cs b/ZR.Service/mes/dc/IService/IDeviceUploadDataService.cs new file mode 100644 index 00000000..353df758 --- /dev/null +++ b/ZR.Service/mes/dc/IService/IDeviceUploadDataService.cs @@ -0,0 +1,21 @@ +using ZR.Model; +using ZR.Model.dc; +using ZR.Model.Dto; + +namespace ZR.Service.MES.dc.IService +{ + /// + /// service接口 + /// + public interface IDeviceUploadDataService : IBaseService + { + PagedInfo GetList(DeviceUploadDataQueryDto parm); + + DeviceUploadData GetInfo(long Id); + + DeviceUploadData AddDeviceUploadData(DeviceUploadData parm); + + int UpdateDeviceUploadData(DeviceUploadData parm); + + } +} diff --git a/ZR.Service/mes/qc/backend/QcBackEndService.cs b/ZR.Service/mes/qc/backend/QcBackEndService.cs index 881aa94a..802dab2f 100644 --- a/ZR.Service/mes/qc/backend/QcBackEndService.cs +++ b/ZR.Service/mes/qc/backend/QcBackEndService.cs @@ -11,6 +11,7 @@ using ZR.Model.Business; using ZR.Model.Dto; using ZR.Model.MES.wms; using ZR.Service.Business.IBusinessService; +using ZR.Service.mqtt; namespace ZR.Service.Business { diff --git a/ZR.Common/MqttHelper/MqttService.cs b/ZR.Service/mqtt/MqttService.cs similarity index 74% rename from ZR.Common/MqttHelper/MqttService.cs rename to ZR.Service/mqtt/MqttService.cs index da71e4e1..310a558d 100644 --- a/ZR.Common/MqttHelper/MqttService.cs +++ b/ZR.Service/mqtt/MqttService.cs @@ -1,19 +1,24 @@ -using Microsoft.Extensions.Configuration; +using Infrastructure.Extensions; +using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using MQTTnet; using MQTTnet.Client; using MQTTnet.Protocol; using System; -using System.Collections.Generic; using System.Linq; using System.Text; +using System.Text.Json; using System.Threading; using System.Threading.Tasks; +using ZR.Common.MqttHelper; +using ZR.Model.dc; +using ZR.Model.Dto; +using ZR.Model.mes.md; -namespace ZR.Common.MqttHelper +namespace ZR.Service.mqtt { - public class MqttService : IHostedService, IDisposable + public class MqttService :BaseService, IHostedService, IDisposable { private readonly ILogger _logger; private readonly IConfiguration _configuration; @@ -168,15 +173,9 @@ namespace ZR.Common.MqttHelper { _logger.LogInformation($"MQTT连接已建立,会话是否存在: {e.ConnectResult.IsSessionPresent}"); - // 仅在会话不存在时订阅(首次连接或会话失效) - if (!e.ConnectResult.IsSessionPresent) - { - await SubscribeToTopicsAsync(); - } - else - { - _logger.LogInformation("会话已存在,服务器保留订阅状态,跳过订阅"); - } + // 无论会话是否存在,都检查并确保订阅配置的主题 + // 这解决了配置文件修改后重启服务不订阅新主题的问题 + await SubscribeToTopicsAsync(); } private async Task OnDisconnectedAsync(MqttClientDisconnectedEventArgs e) @@ -220,7 +219,7 @@ namespace ZR.Common.MqttHelper // 这里可以根据主题路由消息到不同的处理程序 switch (topic) { - case string t when t.StartsWith("devices/"): + case string t when t.StartsWith("shgx_tz/device/"): await HandleDeviceMessage(topic, payload); break; case "system/alert": @@ -256,17 +255,71 @@ namespace ZR.Common.MqttHelper // 提取需要订阅的主题 var topicsToSubscribe = subscribeOptions.TopicFilters.Select(f => f.Topic).ToList(); + var topicFilters = subscribeOptions.TopicFilters.ToList(); - // 检查是否已订阅所有主题,避免重复 - if (_subscribedTopics.SetEquals(topicsToSubscribe)) + // 获取当前已订阅的主题 + HashSet currentlySubscribedTopics; + lock (_subscribedTopics) { - _logger.LogInformation("所有主题已订阅,跳过订阅操作"); + currentlySubscribedTopics = new HashSet(_subscribedTopics); + } + + // 检查是否有新的主题需要订阅 + var newTopics = topicsToSubscribe.Except(currentlySubscribedTopics).ToList(); + var removedTopics = currentlySubscribedTopics.Except(topicsToSubscribe).ToList(); + + if (!newTopics.Any() && !removedTopics.Any()) + { + _logger.LogInformation("所有主题已正确订阅,无需变更"); return; } - // 执行订阅并更新本地状态 - _logger.LogInformation($"订阅主题: {string.Join(", ", topicsToSubscribe)}"); - var result = await _mqttClient.SubscribeAsync(subscribeOptions); + // 处理新增的主题 + if (newTopics.Any()) + { + var newTopicFilters = topicFilters.Where(f => newTopics.Contains(f.Topic)).ToList(); + if (newTopicFilters.Any()) + { + var newSubscribeOptionsBuilder = new MqttClientSubscribeOptionsBuilder(); + + foreach (var topicFilter in newTopicFilters) + { + newSubscribeOptionsBuilder.WithTopicFilter(topicFilter); + } + + var newSubscribeOptions = newSubscribeOptionsBuilder.Build(); + + _logger.LogInformation($"订阅新主题: {string.Join(", ", newTopics)}"); + var result = await _mqttClient.SubscribeAsync(newSubscribeOptions); + + foreach (var item in result.Items) + { + _logger.LogInformation($"订阅结果:{item.TopicFilter.Topic} -> {item.ResultCode}"); + } + } + } + + // 处理移除的主题(可选,根据业务需求决定是否取消订阅) + if (removedTopics.Any()) + { + _logger.LogInformation($"配置中移除的主题: {string.Join(", ", removedTopics)}"); + // 注意:这里没有执行取消订阅操作,因为有些场景下可能希望保留历史订阅 + // 如果需要取消订阅,请取消注释下面的代码 + + // 使用构建器模式创建取消订阅选项 + var unsubscribeOptionsBuilder = new MqttClientUnsubscribeOptionsBuilder(); + + // 为每个要取消订阅的主题调用WithTopic方法 + foreach (var topic in removedTopics) + { + unsubscribeOptionsBuilder.WithTopicFilter(topic); + } + + var unsubscribeOptions = unsubscribeOptionsBuilder.Build(); + await _mqttClient.UnsubscribeAsync(unsubscribeOptions); + _logger.LogInformation($"已取消订阅: {string.Join(", ", removedTopics)}"); + + } // 更新本地已订阅主题列表 lock (_subscribedTopics) @@ -274,11 +327,6 @@ namespace ZR.Common.MqttHelper _subscribedTopics.Clear(); _subscribedTopics.UnionWith(topicsToSubscribe); } - - foreach (var item in result.Items) - { - _logger.LogInformation($"订阅结果:{item.TopicFilter.Topic} -> {item.ResultCode}"); - } } private void ScheduleReconnect() @@ -320,7 +368,32 @@ namespace ZR.Common.MqttHelper private Task HandleDeviceMessage(string topic, string payload) { _logger.LogInformation($"处理设备消息: {topic} - {payload}"); + + DeviceUploadDataGatWayDto deviceUploadDataGatWayDto = JsonSerializer.Deserialize(payload); // 这里添加设备消息处理逻辑 + string deviceCode = topic.Split("/")[2]; + DeviceUploadData deviceUploadData = new() + { + FactoryCode = "上海干巷", + WorkshopCode = "涂装车间", + LineCode = "涂装生产线", + DeviceCode = deviceCode, + DictCode = "device_dict_plc_001", + Remark = "网关采集设备数据", + UploadTime = DateTime.Now, + CollectionTime = DateTimeOffset.FromUnixTimeMilliseconds(deviceUploadDataGatWayDto.Time).LocalDateTime, + Value01 = deviceUploadDataGatWayDto.DeviceParams.Value01.ToString(), + Value02 = deviceUploadDataGatWayDto.DeviceParams.Value02.ToString(), + Value03 = deviceUploadDataGatWayDto.DeviceParams.Value03.ToString(), + Value04 = deviceUploadDataGatWayDto.DeviceParams.Value04.ToString(), + Value05 = deviceUploadDataGatWayDto.DeviceParams.Value05.ToString(), + Value06 = deviceUploadDataGatWayDto.DeviceParams.Value06.ToString(), + Value07 = deviceUploadDataGatWayDto.DeviceParams.Value07.ToString(), + Value08 = deviceUploadDataGatWayDto.DeviceParams.Value08.ToString(), + Value09 = deviceUploadDataGatWayDto.DeviceParams.Value09.ToString(), + Value10 = deviceUploadDataGatWayDto.DeviceParams.Value10.ToString() + }; + Context.Insertable(deviceUploadData).ExecuteCommand(); return Task.CompletedTask; }