From ddd6d2e9e936457706582a300ed786020028bb3c Mon Sep 17 00:00:00 2001 From: ChenYi <296215406@outlook.com> Date: Wed, 18 Mar 2026 17:26:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E6=94=B6=E4=B8=9A=E5=8A=A1=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=B0=83=E7=94=A8=E8=AE=BE=E5=A4=87=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dto/CallDeviceServiceRequestInfoDto.cs | 15 ++ .../IBusinessSystemAggregationService.cs | 9 +- .../BusinessSystemAggregationService.cs | 156 ++++++++++++++++-- 3 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/Dto/CallDeviceServiceRequestInfoDto.cs diff --git a/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/Dto/CallDeviceServiceRequestInfoDto.cs b/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/Dto/CallDeviceServiceRequestInfoDto.cs new file mode 100644 index 0000000..ad3cf46 --- /dev/null +++ b/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/Dto/CallDeviceServiceRequestInfoDto.cs @@ -0,0 +1,15 @@ +using JiShe.ServicePro.Dto; + +namespace JiShe.IoT.BusinessSystemAggregation +{ + /// + /// 业务系统调用设备服务请求参数 + /// + public class CallDeviceServiceRequestInfoDto: ReceiveCommandInfoDto + { + /// + /// 服务名称 + /// + public string ServiceName { get; set; } + } +} diff --git a/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/IBusinessSystemAggregationService.cs b/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/IBusinessSystemAggregationService.cs index 4b9cc54..8518177 100644 --- a/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/IBusinessSystemAggregationService.cs +++ b/src/JiShe.IoT.Application.Contracts/BusinessSystemAggregation/IBusinessSystemAggregationService.cs @@ -1,5 +1,6 @@ using JiShe.ServicePro; using JiShe.ServicePro.ApacheIoTDB.Provider.Model; +using Microsoft.AspNetCore.Authorization; using System; using System.Collections.Generic; using System.Linq; @@ -46,6 +47,12 @@ namespace JiShe.IoT.BusinessSystemAggregation /// /// /// - Task BatchCreateDeviceInfoAsync(OpenApiRequest input); + Task BatchCreateDeviceInfoAsync(OpenApiRequest input); + + + /// + /// 接收业务系统调用设备服务信息,Msg 字段为 CallDeviceServiceRequestInfoDto 实体 + /// + Task>> CallDeviceServiceToOneNETForApiAsync(OpenApiRequest input); } } diff --git a/src/JiShe.IoT.Application/BusinessSystemAggregation/BusinessSystemAggregationService.cs b/src/JiShe.IoT.Application/BusinessSystemAggregation/BusinessSystemAggregationService.cs index fd5d392..adf618d 100644 --- a/src/JiShe.IoT.Application/BusinessSystemAggregation/BusinessSystemAggregationService.cs +++ b/src/JiShe.IoT.Application/BusinessSystemAggregation/BusinessSystemAggregationService.cs @@ -96,7 +96,7 @@ namespace JiShe.IoT.BusinessSystemAggregation } List actionTypes = new List() { - DeviceTelemetryCommandTypeEnum.OperateBreaker, + DeviceTelemetryCommandTypeEnum.OperateService, DeviceTelemetryCommandTypeEnum.RoutineOperationSet, }; @@ -118,7 +118,7 @@ namespace JiShe.IoT.BusinessSystemAggregation { return HttpDataResultExtensions.Failed("设备不存在", -1041, ResponeResultEnum.Fail); } - + //将指令存储IoTDB数据库和Redis发布通道 if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.OneNET) { @@ -136,7 +136,7 @@ namespace JiShe.IoT.BusinessSystemAggregation var tempPlatformThingModelInfo = platformThingModelInfo.Where(d => d.IoTPlatformRawFieldName == item.Key).FirstOrDefault(); if (tempPlatformThingModelInfo == null) { - _logger.LogError($"业务系统推送指令时设备设备{deviceInfo.DeviceAddress}平台端物模型信息不存在属性标识符{item.Key}。"); + _logger.LogError($"业务系统推送指令时设备{deviceInfo.DeviceAddress}平台端物模型信息不存在属性标识符{item.Key}。"); messageBody.Commands.RemoveAll(d => d.Key == item.Key); continue; } @@ -213,14 +213,14 @@ namespace JiShe.IoT.BusinessSystemAggregation return HttpDataResultExtensions.Failed>("获取数据失败,设备属性值不能为空", -102, ResponeResultEnum.Fail); } - var restrictionKey = string.Format(RedisConst.CacheDeviceOpenApiRestrictionKey,nameof(ReceiveGetCommandInfoAsync), messageBody.DeviceAddress); - var openApiDeviceRequest = FreeRedisProvider.Instance.Get(restrictionKey); + var restrictionKey = string.Format(RedisConst.CacheDeviceOpenApiRestrictionKey, nameof(ReceiveGetCommandInfoAsync), messageBody.DeviceAddress); + var openApiDeviceRequest = FreeRedisProvider.Instance.Get(restrictionKey); if (openApiDeviceRequest != null) { return HttpDataResultExtensions.Failed>("获取数据失败,设备请求被限制", -103, ResponeResultEnum.Fail); } - FreeRedisProvider.Instance.Set(restrictionKey,"1",TimeSpan.FromSeconds(5)); + FreeRedisProvider.Instance.Set(restrictionKey, "1", TimeSpan.FromSeconds(5)); //限定来源类型必须为业务系统 if (messageBody.SourceType != DeviceTelemetrySourceTypeEnum.BusinessSystem) @@ -240,7 +240,7 @@ namespace JiShe.IoT.BusinessSystemAggregation { return HttpDataResultExtensions.Failed>("设备不存在", -106, ResponeResultEnum.Fail); } - + //将指令存储IoTDB数据库和Redis发布通道 if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.OneNET) { @@ -263,7 +263,7 @@ namespace JiShe.IoT.BusinessSystemAggregation messageBody.Commands.RemoveAll(d => d.Key == item.Key); continue; } - + if (deviceInfo.IsNeedConfigDeviceModel && deviceInfo.DeviceThingModelDataId.HasValue && item.Key.ToLowerInvariant() == ThingModelFixedTypeConst.SpecialCommand.ToLowerInvariant()) { _logger.LogError($"业务系统推送指令时设备{deviceInfo.DeviceAddress}平台端物模型属性标识符{item.Key}是特殊指令操作,被禁止。"); @@ -278,7 +278,7 @@ namespace JiShe.IoT.BusinessSystemAggregation messageBody.Commands.RemoveAll(d => d.Key == item.Key); continue; } - commands.Add(tempPlatformThingModelInfo.IoTPlatformRawFieldName,item.Key); + commands.Add(tempPlatformThingModelInfo.IoTPlatformRawFieldName, item.Key); } if (commands == null || commands.Count <= 0) @@ -292,7 +292,7 @@ namespace JiShe.IoT.BusinessSystemAggregation //数据写入遥测任务数据存储通道 await ioTDBDataChannelManageService.DeviceTelemetryTaskWriterAsync(DataChannelManage.DeviceTelemetryTaskDataChannel.Writer, (DistributedMessageCenterConst.OneNETCommandIssuedEventName, packetTaskInfo)); - + var queryResult = await DevicePropertyValueToOneNET(deviceInfo, new DevicePropertyValueForApiInput() { PropertyList = commands.Select(d => d.Key).ToList() }); if (queryResult == null || queryResult.Count <= 0) @@ -616,5 +616,141 @@ namespace JiShe.IoT.BusinessSystemAggregation !deviceAddress.Contains("*") && !deviceAddress.Contains("~"); } + + /// + /// 接收业务系统调用设备服务信息,Msg 字段为 CallDeviceServiceRequestInfoDto 实体 + /// + [AllowAnonymous] + public async Task>> CallDeviceServiceToOneNETForApiAsync(OpenApiRequest input) + { + try + { + var handleResult = HandleOpenApiRequest(input, serverApplicationOptions); + if (handleResult.Success == false) + { + return HttpDataResultExtensions.Failed>("获取数据失败,签名校验异常", -101); + } + var messageBody = handleResult.Data; + if (messageBody == null || messageBody.Commands == null || messageBody.Commands.Count <= 0 || string.IsNullOrWhiteSpace(messageBody.DeviceAddress) || string.IsNullOrWhiteSpace(messageBody.ServiceName)) + { + return HttpDataResultExtensions.Failed>("服务调用失败,服务调用参数不能为空", -102, ResponeResultEnum.Fail); + } + + var restrictionKey = string.Format(RedisConst.CacheDeviceOpenApiRestrictionKey, nameof(ReceiveGetCommandInfoAsync), messageBody.DeviceAddress); + var openApiDeviceRequest = FreeRedisProvider.Instance.Get(restrictionKey); + if (openApiDeviceRequest != null) + { + return HttpDataResultExtensions.Failed>("服务调用失败,设备请求被限制", -103, ResponeResultEnum.Fail); + } + + FreeRedisProvider.Instance.Set(restrictionKey, "1", TimeSpan.FromSeconds(5)); + + //限定来源类型必须为业务系统 + if (messageBody.SourceType != DeviceTelemetrySourceTypeEnum.BusinessSystem) + { + return HttpDataResultExtensions.Failed>("服务调用失败,来源类型错误,业务系统传固定值2", -104, ResponeResultEnum.Fail); + } + + //限定操作类型必须为设备服务调用类型 + if (messageBody.TelemetryCommandType != DeviceTelemetryCommandTypeEnum.OperateService) + { + return HttpDataResultExtensions.Failed>("服务调用失败,指令操作类型错误", -105, ResponeResultEnum.Fail); + } + + var deviceInfo = await deviceAppService.FindByDeviceAddressAsync(messageBody.DeviceAddress); + + if (deviceInfo == null) + { + return HttpDataResultExtensions.Failed>("设备不存在", -106, ResponeResultEnum.Fail); + } + + //将指令存储IoTDB数据库和Redis发布通道 + if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.OneNET) + { + //获取设备对应的平台端物模型信息,校验前端传入的属性标识集合是否存在不合法的属性标识符 + + var platformThingModelInfo = await platformThingModelInfoAppService.FindByPlatformProductIdAsync(new IdInput() { Id = deviceInfo.IoTPlatformProductId }); + + if (platformThingModelInfo == null) + { + return HttpDataResultExtensions.Failed>($"业务系统设备服务调时,{deviceInfo.DeviceAddress}的平台端物模型信息不存在。", -107, ResponeResultEnum.Fail); + } + + Dictionary commands = new Dictionary(); + foreach (var item in messageBody.Commands) + { + var tempPlatformThingModelInfo = platformThingModelInfo.Where(d => d.StandardFieldName == item.Key).FirstOrDefault(); + if (tempPlatformThingModelInfo == null) + { + _logger.LogError($"业务系统设备服务调时{deviceInfo.DeviceAddress}平台端物模型信息不存在属性标识符{item.Key}。"); + messageBody.Commands.RemoveAll(d => d.Key == item.Key); + continue; + } + + + //排除指令 + if (exitCommands.Contains(tempPlatformThingModelInfo.StandardFieldName.ToLowerInvariant())) + { + _logger.LogError($"业务系统设备服务调时{deviceInfo.DeviceAddress}平台端物模型属性标识符{item.Key}是升级指令操作,被禁止。"); + messageBody.Commands.RemoveAll(d => d.Key == item.Key); + continue; + } + commands.Add(tempPlatformThingModelInfo.IoTPlatformRawFieldName, item.Key); + } + + if (commands == null || commands.Count <= 0) + { + _logger.LogError($"业务系统设备服务调时{deviceInfo.DeviceAddress}未匹配到具体数据模型,被禁止。"); + return HttpDataResultExtensions.Failed>("业务系统设备服务调失败,未匹配到具体数据模型", -108); + } + + + var packetTaskInfo = GetDeviceTelemetryPacketTaskInfo(ioTDBOptions, input, deviceInfo.Adapt(), commands.Serialize()); + + //数据写入遥测任务数据存储通道 + await ioTDBDataChannelManageService.DeviceTelemetryTaskWriterAsync(DataChannelManage.DeviceTelemetryTaskDataChannel.Writer, (DistributedMessageCenterConst.OneNETCommandIssuedEventName, packetTaskInfo)); + + var queryResult = await CallDeviceServiceToOneNET(deviceInfo, new CallDeviceServiceForApiInput() + { + ServiceParams = messageBody.Commands, + ServiceName = messageBody.ServiceName, + }); + + if (queryResult == null || queryResult.Count <= 0) + { + return HttpDataResultExtensions.Failed>("业务系统设备服务调失败,OneNET平台未返回数据", -109); + } + + Dictionary result = new Dictionary(); + foreach (var item in commands) + { + result.Add(item.Value, queryResult[item.Key]); + } + + return HttpDataResultExtensions.Success>(result); + + } + else if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.CTWing) + { + //await redisPubSubService.PublishReliableAsync(DistributedMessageCenterConst.CTWingAepCommandIssuedEventName, input); + } + else + { + return HttpDataResultExtensions.Failed>("指令处理失败,当前设备平台类型异常", -110); + } + + return HttpDataResultExtensions.Success>("指令下发成功"); + } + catch (UserFriendlyException ex) + { + _logger.LogError(ex, "接收业务系统指令信息时发生异常"); + return HttpDataResultExtensions.Failed>("设备属性数据获取失败,发送异常", -111); + } + catch (Exception ex) + { + _logger.LogError(ex, "接收业务系统指令信息时发生异常"); + return HttpDataResultExtensions.Failed>("设备属性数据获取失败,发送异常", -112); + } + } } } \ No newline at end of file