设备固件信息服务、设备升级记录服务,设备聚合服务优化

This commit is contained in:
ChenYi 2025-12-30 17:26:28 +08:00
parent 8839ab1896
commit 0b3b4a7c70
5 changed files with 313 additions and 28 deletions

View File

@ -0,0 +1,31 @@
using JiShe.ServicePro.Core;
using JiShe.ServicePro.Enums;
using System.ComponentModel.DataAnnotations;
namespace JiShe.IoT.DeviceAggregation
{
/// <summary>
/// 设备升级
/// </summary>
public class DeviceUpgradeForApiInput : IdInput
{
/// <summary>
/// 物联网平台类型,默认没有指定
/// </summary>
[Required]
public IoTPlatformTypeEnum IoTPlatform { get; set; }
/// <summary>
/// 物联网平台中对应的产品Id
/// </summary>
[Required]
public string IoTPlatformProductId { get; set; }
/// <summary>
/// 固件版本信息
/// </summary>
[Required]
public Guid NowFirmwareVersionDataId { get; set; }
}
}

View File

@ -2,7 +2,9 @@
using JiShe.ServicePro;
using JiShe.ServicePro.Core;
using JiShe.ServicePro.DeviceManagement.DeviceInfos;
using JiShe.ServicePro.FileManagement.Files;
using Volo.Abp;
using Volo.Abp.Content;
namespace JiShe.IoT.DeviceAggregation
{
@ -46,6 +48,18 @@ namespace JiShe.IoT.DeviceAggregation
/// <returns></returns>
Task<bool> DeviceCommandForApiAsync(DeviceCommandForApiInput input);
/// <summary>
/// 发送设备升级指令信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
Task<bool> DeviceUpgradeForApiAsync(DeviceUpgradeForApiInput input);
/// <summary>
/// 下载设备固件文件
/// </summary>
Task<RemoteStreamContent> DownloadFirmwareInfoAsync(IdInput input);
/// <summary>
/// 获取设备属性最新值
/// </summary>

View File

@ -6,6 +6,7 @@ using JiShe.ServicePro.ApacheIoTDB.Provider.Options;
using JiShe.ServicePro.Core;
using JiShe.ServicePro.DataChannelManages;
using JiShe.ServicePro.DeviceManagement.DeviceInfos;
using JiShe.ServicePro.DeviceManagement.ThingModels;
using JiShe.ServicePro.Dto;
using JiShe.ServicePro.Encrypt;
using JiShe.ServicePro.Enums;
@ -16,6 +17,7 @@ using Mapster;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using Volo.Abp;
using Volo.Abp.Auditing;
namespace JiShe.IoT.BusinessSystemAggregation
@ -24,7 +26,7 @@ namespace JiShe.IoT.BusinessSystemAggregation
/// 业务系统聚合服务
/// </summary>
[DisableAuditing]
public class BusinessSystemAggregationService(IOptions<ServerApplicationOptions> options, IReliableRedisPubSubService redisPubSubService, IDeviceAppService deviceAppService, IIoTDBDataChannelManageService ioTDBDataChannelManageService, IOptions<IoTDBOptions> _ioTDBOptions, ITreeModelService treeModelService, IDeviceAggregationService deviceAggregationService, ILogger<BusinessSystemAggregationService> _logger) : IoTAppService, IBusinessSystemAggregationService
public class BusinessSystemAggregationService(IOptions<ServerApplicationOptions> options, IReliableRedisPubSubService redisPubSubService, IDeviceAppService deviceAppService, IIoTDBDataChannelManageService ioTDBDataChannelManageService, IOptions<IoTDBOptions> _ioTDBOptions, ITreeModelService treeModelService, IDeviceAggregationService deviceAggregationService, ILogger<BusinessSystemAggregationService> _logger, IIoTPlatformThingModelInfoAppService platformThingModelInfoAppService) : IoTAppService, IBusinessSystemAggregationService
{
ServerApplicationOptions serverOptions = options.Value;
IoTDBOptions ioTDBOptions = _ioTDBOptions.Value;
@ -68,6 +70,37 @@ namespace JiShe.IoT.BusinessSystemAggregation
//将指令存储IoTDB数据库和Redis发布通道
if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.OneNET)
{
//获取设备对应的平台端物模型信息,校验前端传入的属性标识集合是否存在不合法的属性标识符
var platformThingModelInfo = await platformThingModelInfoAppService.FindByPlatformProductIdAsync(new IdInput<string>() { Id = deviceInfo.IoTPlatformProductId });
if (platformThingModelInfo == null)
{
throw new UserFriendlyException($"业务系统推送指令时设备{deviceInfo.DeviceAddress}的平台端物模型信息不存在。");
}
foreach (var item in messageBody.Commands)
{
var tempPlatformThingModelInfo = platformThingModelInfo.Where(d => d.IoTPlatformRawFieldName == item.Key).FirstOrDefault();
if (tempPlatformThingModelInfo == null)
{
throw new UserFriendlyException($"业务系统推送指令时设备设备{deviceInfo.DeviceAddress}平台端物模型信息不存在属性标识符{item.Key}。");
}
//排除升级指令
if (tempPlatformThingModelInfo.StandardFieldName.ToLowerInvariant() == ThingModelFixedTypeConst.FIRMWARE_UPGRADE.ToLowerInvariant())
{
throw new UserFriendlyException($"业务系统推送指令时设备{deviceInfo.DeviceAddress}平台端物模型属性标识符{item.Key}是升级指令操作,被禁止。");
}
if (deviceInfo.IsNeedConfigDevicMdoel && deviceInfo.DeviceThingModelDataId.HasValue && item.Key.ToLowerInvariant() == ThingModelFixedTypeConst.SpecialCommand.ToLowerInvariant())
{
throw new UserFriendlyException($"业务系统推送指令时设备{deviceInfo.DeviceAddress}平台端物模型属性标识符{item.Key}是特殊指令操作,被禁止。");
}
}
//数据写入遥测任务数据存储通道
await ioTDBDataChannelManageService.DeviceTelemetryTaskWriterAsync(DataChannelManage.DeviceTelemetryTaskDataChannel.Writer, (DistributedMessageCenterConst.OneNETCommandIssuedEventName, packetTaskInfo));

View File

@ -9,6 +9,7 @@ using JiShe.ServicePro.DeviceManagement.Permissions;
using JiShe.ServicePro.DeviceManagement.ThingModels;
using JiShe.ServicePro.Dto;
using JiShe.ServicePro.Enums;
using JiShe.ServicePro.FileManagement.Files;
using JiShe.ServicePro.FreeRedisProvider;
using JiShe.ServicePro.IoTDBManagement.DataChannels;
using JiShe.ServicePro.IoTDBManagement.TableModels;
@ -18,6 +19,7 @@ using Mapster;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp;
using Volo.Abp.Content;
namespace JiShe.IoT.DeviceAggregation
{
@ -32,7 +34,11 @@ namespace JiShe.IoT.DeviceAggregation
/// <param name="_ioTDBOptions">IoTDBOptions</param>
/// <param name="oneNETProductService">OneNET产品服务</param>
/// <param name="deviceThingModelService">设备端物模型服务</param>
public class DeviceAggregationService(ILogger<DeviceAggregationService> logger, IDeviceAppService deviceAppService, IOneNETDeviceService oneNETDeviceService, IReliableRedisPubSubService redisPubSubService, IIoTDBDataChannelManageService ioTDBDataChannelManageService,IOptions<IoTDBOptions> _ioTDBOptions, IOneNETProductService oneNETProductService, IDeviceThingModelManagementAppService deviceThingModelService) : IoTAppService, IDeviceAggregationService
/// <param name="platformThingModelInfoAppService">平台端端物模型服务</param>
/// <param name="deviceFirmwareInfoService">设备固件服务</param>
/// <param name="deviceUpgradeRecordService">设备升级记录服务</param>
/// <param name="fileAppService">文件管理服务</param>
public class DeviceAggregationService(ILogger<DeviceAggregationService> logger, IDeviceAppService deviceAppService, IOneNETDeviceService oneNETDeviceService, IReliableRedisPubSubService redisPubSubService, IIoTDBDataChannelManageService ioTDBDataChannelManageService, IOptions<IoTDBOptions> _ioTDBOptions, IOneNETProductService oneNETProductService, IDeviceThingModelManagementAppService deviceThingModelService, IIoTPlatformThingModelInfoAppService platformThingModelInfoAppService, IDeviceFirmwareInfoService deviceFirmwareInfoService, IDeviceUpgradeRecordService deviceUpgradeRecordService,IFileAppService fileAppService) : IoTAppService, IDeviceAggregationService
{
IoTDBOptions ioTDBOptions = _ioTDBOptions.Value;
@ -255,14 +261,17 @@ namespace JiShe.IoT.DeviceAggregation
/// 更新设备信息并处理缓存
/// </summary>
/// <param name="input"></param>
/// <param name="pushResult"></param>
/// <param name="pushResult">推送结果原始信息</param>
/// <param name="securityKey">设备接入鉴权key</param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
private async Task<DeviceManagementInfoDto> DeviceUpdateHandler(DeviceManagementInfoDto input, HttpDataResult pushResult)
private async Task<DeviceManagementInfoDto> DeviceUpdateHandler(DeviceManagementInfoDto input, HttpDataResult pushResult, string securityKey = null)
{
UpdateDeviceInput updateDeviceInput = input.Adapt<UpdateDeviceInput>();
updateDeviceInput.IoTPlatformResponse = pushResult.Serialize();
updateDeviceInput.IsPlatformPushSuccess = true;
updateDeviceInput.SecurityKey = securityKey;
var updateResult = await deviceAppService.UpdateAsync(updateDeviceInput);
if (updateResult == null)
@ -301,7 +310,6 @@ namespace JiShe.IoT.DeviceAggregation
{
throw new UserFriendlyException($"设备不存在");
}
//将指令存储
var receiveCommandInfoDto = new ReceiveCommandInfoDto()
{
@ -334,6 +342,68 @@ namespace JiShe.IoT.DeviceAggregation
}
}
/// <summary>
/// 发送设备升级指令信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
public async Task<bool> DeviceUpgradeForApiAsync(DeviceUpgradeForApiInput input)
{
try
{
var deviceInfo = await deviceAppService.FindByIdAsync(input);
if (deviceInfo == null)
{
throw new UserFriendlyException($"设备不存在");
}
//将指令存储
var receiveCommandInfoDto = new ReceiveCommandInfoDto()
{
DeviceAddress = deviceInfo.DeviceAddress,
DeviceType = deviceInfo.DeviceType,
SourceType = DeviceTelemetrySourceTypeEnum.AdminSystem,
IoTPlatform = deviceInfo.IoTPlatform,
};
//固件信息
var deviceFirmwareVersionInfo = await deviceFirmwareInfoService.FindByIdAsync(new IdInput() { Id = input.NowFirmwareVersionDataId });
var fileInfo = await fileAppService.DeleteAsync(new IdInput() { Id = fileInfo.Id });
//数据写入遥测任务数据存储通道
if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.OneNET)
{
return await DeviceUpgradeCommandToOneNET(deviceInfo, receiveCommandInfoDto, deviceFirmwareVersionInfo);
}
else if (deviceInfo.IoTPlatform == IoTPlatformTypeEnum.CTWing)
{
//await redisPubSubService.PublishReliableAsync(DistributedMessageCenterConst.CTWingAepCommandIssuedEventName,commandRequest);
//return true;
throw new UserFriendlyException($"发送设备升级指令信息失败CTWing暂未实现。");
}
else
{
throw new UserFriendlyException($"发送设备升级指令信息失败,未找到对应的产品配置信息。");
}
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 下载设备固件文件
/// </summary>
[AllowAnonymous]
public async Task<RemoteStreamContent> DownloadFirmwareInfoAsync(IdInput input)
{
return await fileAppService.AllowDownloadAsync(input);
}
/// <summary>
/// 获取设备属性最新值
@ -468,13 +538,13 @@ namespace JiShe.IoT.DeviceAggregation
Description = input.DeviceAddress,
});
if (pushResult == null || pushResult.Code != ServicePro.Enums.ResponeResultEnum.Success)
if (pushResult == null || pushResult.Code != ServicePro.Enums.ResponeResultEnum.Success || pushResult.Data == null)
{
logger.LogError($"{nameof(CreateDeviceForApiAsync)} 推送设备信息失败:{pushResult.Serialize()}");
return false;
}
await DeviceUpdateHandler(insertResult, pushResult);
await DeviceUpdateHandler(insertResult, pushResult, pushResult.Data.SecurityKey);
return true;
}
@ -556,7 +626,7 @@ namespace JiShe.IoT.DeviceAggregation
var successEntity = pushResult.Data.Successlist.Where(d => d.DeviceName == item.IoTPlatformDeviceOpenInfo).FirstOrDefault();
if (successEntity != null)
{
await DeviceUpdateHandler(item, HttpDataResultExtensions.Success(successEntity));
await DeviceUpdateHandler(item, HttpDataResultExtensions.Success(successEntity), successEntity.SecurityKey);
}
}
@ -602,14 +672,14 @@ namespace JiShe.IoT.DeviceAggregation
Description = input.DeviceAddress,
});
if (pushResult == null || pushResult.Code != ServicePro.Enums.ResponeResultEnum.Success)
if (pushResult == null || pushResult.Code != ServicePro.Enums.ResponeResultEnum.Success || pushResult.Data == null)
{
logger.LogError($"{nameof(CreateDeviceForApiAsync)} 推送设备信息失败:{pushResult.Serialize()}");
throw new UserFriendlyException($"平台请求失败。");
}
return await DeviceUpdateHandler(input, pushResult);
return await DeviceUpdateHandler(input, pushResult, pushResult.Data.SecurityKey);
}
catch (Exception)
{
@ -665,10 +735,35 @@ namespace JiShe.IoT.DeviceAggregation
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public async Task<bool> DeviceCommandInfoToOneNET(DeviceManagementInfoDto deviceInfo, ReceiveCommandInfoDto input)
protected async Task<bool> DeviceCommandInfoToOneNET(DeviceManagementInfoDto deviceInfo, ReceiveCommandInfoDto input)
{
try
{
//获取设备对应的平台端物模型信息,校验前端传入的属性标识集合是否存在不合法的属性标识符
var platformThingModelInfo = await platformThingModelInfoAppService.FindByPlatformProductIdAsync(new IdInput<string>() { Id = deviceInfo.IoTPlatformProductId });
if (platformThingModelInfo == null)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}的平台端物模型信息不存在。");
}
foreach (var item in input.Commands)
{
var tempPlatformThingModelInfo = platformThingModelInfo.Where(d => d.IoTPlatformRawFieldName == item.Key).FirstOrDefault();
if (tempPlatformThingModelInfo == null)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}平台端物模型信息不存在属性标识符{item.Key}。");
}
//排除升级指令
if (tempPlatformThingModelInfo.StandardFieldName.ToLowerInvariant() == ThingModelFixedTypeConst.FIRMWARE_UPGRADE.ToLowerInvariant())
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}平台端物模型属性标识符{item.Key}是升级指令,此处不允许下发。");
}
}
//检查设备是否有配置设备端物模型信息
//如果有配置就检查指令字典中是否有SpecialCommand标识符
//如果有就需要构建 SpecialCommand 的特别指令
@ -723,6 +818,92 @@ namespace JiShe.IoT.DeviceAggregation
}
}
/// <summary>
/// 发送OneNET平台设备升级指令
/// </summary>
/// <param name="deviceInfo"></param>
/// <param name="input"></param>
/// <param name="deviceFirmwareInfo">固件数据Id</param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
protected async Task<bool> DeviceUpgradeCommandToOneNET(DeviceManagementInfoDto deviceInfo, ReceiveCommandInfoDto input, DeviceFirmwareInfoDto deviceFirmwareInfo)
{
try
{
if (deviceInfo == null || deviceFirmwareInfo == null)
{
throw new UserFriendlyException($"{nameof(DeviceUpgradeCommandToOneNET)}设备或固件信息不能为空");
}
if (deviceInfo.IoTPlatformProductId != deviceFirmwareInfo.IoTPlatformProductId)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}平台产品Id固件信息中不一致");
}
//获取设备对应的平台端物模型信息,校验前端传入的属性标识集合是否存在不合法的属性标识符
var platformThingModelInfo = await platformThingModelInfoAppService.FindByPlatformProductIdAsync(new IdInput<string>() { Id = deviceInfo.IoTPlatformProductId });
if (platformThingModelInfo == null)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}的平台端物模型信息不存在。");
}
var upgradeProperty = platformThingModelInfo.Where(d => d.StandardFieldName == ThingModelFixedTypeConst.FIRMWARE_UPGRADE).FirstOrDefault();
if (upgradeProperty == null)
{
throw new UserFriendlyException($"设备{deviceInfo.DeviceAddress}平台端物模型信息不存在升级属性标识符{ThingModelFixedTypeConst.FIRMWARE_UPGRADE}。");
}
//构建升级指令《文件MD5值+OneNET产品KEY+升级标识符+文件大小》=>MD5计算获得签名值
var upgradeRecordInput = new CreateDeviceUpgradeRecordInput()
{
DeviceName = deviceInfo.DeviceName,
DeviceAddress = deviceInfo.DeviceAddress,
OldFirmwareVersion = deviceInfo.FirmwareVersion,
NowFirmwareVersion = deviceFirmwareInfo.FirmwareVersion,
UpgradeSource = DeviceUpgradeSourceTypeEnum.AdminSystem,
UpgradeIdentifier = Yitter.IdGenerator.YitIdHelper.NextId(),
};
var insertResult = await deviceUpgradeRecordService.CreateAsync(upgradeRecordInput);
var commandRequest = new OpenApiRequest()
{
Message = input.Serialize(),
};
var packetTaskInfo = GetDeviceTelemetryPacketTaskInfo(ioTDBOptions, commandRequest, deviceInfo.Adapt<DeviceCacheInfos>(), input.Commands.Serialize());
await ioTDBDataChannelManageService.DeviceTelemetryTaskWriterAsync(DataChannelManage.DeviceTelemetryTaskDataChannel.Writer, (DistributedMessageCenterConst.OneNETCommandIssuedEventName, packetTaskInfo));
//检查下设备是否在线
var deviceOnlineStatus = await oneNETDeviceService.DeviceInfoDetailAsync(new DeviceInfoDetailInput()
{
DeviceName = deviceInfo.IoTPlatformDeviceOpenInfo,
OneNETAccountId = deviceInfo.IoTPlatformAccountId,
ProductId = deviceInfo.IoTPlatformProductId,
});
if (deviceOnlineStatus == null || deviceOnlineStatus.Code != ResponeResultEnum.Success)
{
throw new UserFriendlyException("获取平台设备信息失败");
}
if (deviceOnlineStatus.Data.Status != 1)
{
throw new UserFriendlyException("设备不在线");
}
await redisPubSubService.PublishReliableAsync(DistributedMessageCenterConst.OneNETCommandIssuedEventName, packetTaskInfo);
return true;
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// 抄读OneNET平台设备属性数据
/// </summary>
@ -730,7 +911,7 @@ namespace JiShe.IoT.DeviceAggregation
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="UserFriendlyException"></exception>
public async Task<Dictionary<string, object>> DevicePropertyValueToOneNET(DeviceManagementInfoDto deviceInfo, DevicePropertyValueForApiInput input)
protected async Task<Dictionary<string, object>> DevicePropertyValueToOneNET(DeviceManagementInfoDto deviceInfo, DevicePropertyValueForApiInput input)
{
try
{

View File

@ -3,6 +3,7 @@ using JiShe.IoT.DeviceAggregation.Dto;
using JiShe.ServicePro;
using JiShe.ServicePro.Core;
using JiShe.ServicePro.DeviceManagement.DeviceInfos;
using Volo.Abp.Content;
namespace JiShe.IoT.Controllers
{
@ -99,5 +100,30 @@ namespace JiShe.IoT.Controllers
return _deviceAggregationService.GetDevicePropertyValueForApiAsync(input);
}
/// <summary>
/// 发送设备升级指令信息
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost(nameof(DeviceUpgradeForApiAsync))]
[SwaggerOperation(summary: "发送设备升级指令信息", Tags = new[] { "AggregationDevice" })]
public Task<bool> DeviceUpgradeForApiAsync(DeviceUpgradeForApiInput input)
{
return _deviceAggregationService.DeviceUpgradeForApiAsync(input);
}
/// <summary>
/// 下载设备固件文件
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
[HttpPost("DownloadFirmware")]
[HttpGet("DownloadFirmware")]
[SwaggerOperation(summary: "下载设备固件文件", Tags = new[] { "AggregationDevice" })]
public Task<RemoteStreamContent> DownloadFirmwareInfoAsync(IdInput input)
{
return _deviceAggregationService.DownloadFirmwareInfoAsync(input);
}
}
}