2025-06-03 11:58:17 +08:00
|
|
|
|
using JiShe.CollectBus.Common;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Consts;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
using JiShe.CollectBus.Common.DeviceBalanceControl;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Enums;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Extensions;
|
2025-04-16 17:36:46 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Models;
|
2025-05-08 22:44:01 +08:00
|
|
|
|
using JiShe.CollectBus.DataChannels;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.GatherItem;
|
2025-04-23 16:17:29 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.Ammeters;
|
2025-04-25 14:23:06 +08:00
|
|
|
|
using JiShe.CollectBus.Protocol.Interfaces;
|
2025-05-08 22:44:01 +08:00
|
|
|
|
using JiShe.CollectBus.Protocol.Models;
|
2025-06-03 23:01:46 +08:00
|
|
|
|
using JiShe.ServicePro.Core;
|
|
|
|
|
|
using JiShe.ServicePro.Encrypt;
|
2025-05-13 14:51:38 +08:00
|
|
|
|
using Mapster;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2025-04-17 13:54:18 +08:00
|
|
|
|
using Microsoft.Extensions.Options;
|
2025-04-09 23:11:36 +08:00
|
|
|
|
using System.Diagnostics;
|
2025-05-14 14:40:34 +08:00
|
|
|
|
using Volo.Abp.Guids;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-14 14:38:08 +08:00
|
|
|
|
namespace JiShe.CollectBus.ScheduledMeterReading
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 定时采集服务
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract class BasicScheduledMeterReadingService : CollectBusAppService, IScheduledMeterReadingService
|
|
|
|
|
|
{
|
|
|
|
|
|
private readonly ILogger<BasicScheduledMeterReadingService> _logger;
|
2025-06-03 11:58:17 +08:00
|
|
|
|
private readonly IoTDBSessionPoolProvider _dbProvider;
|
2025-04-30 12:36:54 +08:00
|
|
|
|
private readonly IDataChannelManageService _dataChannelManage;
|
2025-04-16 17:36:46 +08:00
|
|
|
|
private readonly IRedisDataCacheService _redisDataCacheService;
|
2025-04-24 17:48:20 +08:00
|
|
|
|
private readonly IProtocolService _protocolService;
|
2025-04-30 12:36:54 +08:00
|
|
|
|
private readonly KafkaOptionConfig _kafkaOptions;
|
2025-04-30 15:57:14 +08:00
|
|
|
|
private readonly ServerApplicationOptions _applicationOptions;
|
2025-05-15 23:59:10 +08:00
|
|
|
|
private readonly IGuidGenerator _guidGenerator;
|
2025-04-24 17:48:20 +08:00
|
|
|
|
|
2025-04-29 23:48:47 +08:00
|
|
|
|
int pageSize = 10000;
|
2025-04-14 16:41:41 +08:00
|
|
|
|
|
2025-03-17 14:23:48 +08:00
|
|
|
|
public BasicScheduledMeterReadingService(
|
|
|
|
|
|
ILogger<BasicScheduledMeterReadingService> logger,
|
2025-04-30 12:36:54 +08:00
|
|
|
|
IDataChannelManageService dataChannelManage,
|
2025-04-16 17:36:46 +08:00
|
|
|
|
IRedisDataCacheService redisDataCacheService,
|
2025-06-03 11:58:17 +08:00
|
|
|
|
IoTDBSessionPoolProvider dbProvider,
|
2025-04-24 17:48:20 +08:00
|
|
|
|
IProtocolService protocolService,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
IGuidGenerator guidGenerator,
|
2025-04-25 09:28:20 +08:00
|
|
|
|
IOptions<KafkaOptionConfig> kafkaOptions,
|
|
|
|
|
|
IOptions<ServerApplicationOptions> applicationOptions)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger = logger;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
_dbProvider = dbProvider;
|
2025-04-30 12:36:54 +08:00
|
|
|
|
_dataChannelManage = dataChannelManage;
|
2025-04-16 17:36:46 +08:00
|
|
|
|
_redisDataCacheService = redisDataCacheService;
|
2025-04-24 17:48:20 +08:00
|
|
|
|
_protocolService = protocolService;
|
2025-04-22 17:58:14 +08:00
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
_kafkaOptions = kafkaOptions.Value;
|
2025-04-30 15:57:14 +08:00
|
|
|
|
_applicationOptions = applicationOptions.Value;
|
2025-04-30 12:36:54 +08:00
|
|
|
|
|
2025-05-14 14:40:34 +08:00
|
|
|
|
_guidGenerator = guidGenerator;
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 系统类型
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract string SystemType { get; }
|
|
|
|
|
|
|
2025-04-09 17:29:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 应用服务器部署标记
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public abstract string ServerTagName { get; }
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
///电表日冻结采集项
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected List<string> DayFreezeCodes = new List<string>() { "0D_3", "0D_4", "0D_161", "0D_162", "0D_163", "0D_164", "0D_165", "0D_166", "0D_167", "0D_168", "0C_149", };
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 电表月冻结采集项
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
protected List<string> MonthFreezeCodes = new List<string>() { "0D_177", "0D_178", "0D_179", "0D_180", "0D_181", "0D_182", "0D_183", "0D_184", "0D_193", "0D_195", };
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取采集项列表
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual Task<List<GatherItemInfo>> GetGatherItemByDataTypes()
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(GetGatherItemByDataTypes)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建待处理的下发指令任务处理
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task CreateToBeIssueTasks()
|
2025-04-14 21:56:24 +08:00
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisCacheKey = $"{RedisConst.CacheBasicDirectoryKey}{SystemType}:{ServerTagName}:TaskInfo:*";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
var taskInfos = await FreeRedisProvider.Instance.KeysAsync(redisCacheKey);
|
|
|
|
|
|
if (taskInfos == null || taskInfos.Length <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"{nameof(CreateToBeIssueTasks)} 构建待处理的下发指令任务处理时没有缓存数据,-101");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-04-18 17:46:24 +08:00
|
|
|
|
var currentTime = DateTime.Now;
|
2025-04-30 15:57:14 +08:00
|
|
|
|
|
2025-04-25 09:28:20 +08:00
|
|
|
|
|
|
|
|
|
|
//定时抄读
|
2025-03-18 15:58:37 +08:00
|
|
|
|
foreach (var item in taskInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tasksToBeIssueModel = await FreeRedisProvider.Instance.GetAsync<TasksToBeIssueModel>(item);
|
|
|
|
|
|
if (tasksToBeIssueModel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"{nameof(CreateToBeIssueTasks)} 构建待处理的下发指令任务处理时Key=>{item}没有缓存数据,102");
|
|
|
|
|
|
continue;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
2025-04-14 16:41:41 +08:00
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
//item 为 CacheTasksToBeIssuedKey 对应的缓存待下发的指令生产任务数据Redis Key tempArryay[0]=>CollectBus,tempArryay[1]=>SystemTypeConst,tempArryay[2]=>ServerTagName,tempArryay[3]=>TaskInfo,tempArryay[4]=>表计类别,tempArryay[5]=>采集频率
|
2025-04-14 16:41:41 +08:00
|
|
|
|
var tempArryay = item.Split(":");
|
2025-04-14 23:42:18 +08:00
|
|
|
|
string meteryType = tempArryay[4];//表计类别
|
|
|
|
|
|
int timeDensity = Convert.ToInt32(tempArryay[5]);//采集频率
|
2025-05-22 17:29:54 +08:00
|
|
|
|
|
2025-04-25 12:01:15 +08:00
|
|
|
|
//电表定时广播校时,一天一次。
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
2025-05-20 21:55:48 +08:00
|
|
|
|
if (string.Equals(currentTimeStr, _applicationOptions.AutomaticVerificationTime, StringComparison.CurrentCultureIgnoreCase))//自动校时
|
|
|
|
|
|
{
|
|
|
|
|
|
//_logger.LogInformation($"{nameof(AmmeterScheduledAutomaticVerificationTime)} 电表自动校时,非自动校时时间");
|
|
|
|
|
|
//return;
|
|
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-05-20 21:55:48 +08:00
|
|
|
|
timeDensity: timeDensity,
|
|
|
|
|
|
nextTaskTime: currentTime,
|
|
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
|
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempTask = await AmmeterScheduledAutomaticVerificationTime(timeDensity, data, groupIndex, timestamps);
|
|
|
|
|
|
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"电表自动校时 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerOtherIssuedEventName, tempTask));
|
2025-05-20 21:55:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (string.Equals(currentTimeStr, _applicationOptions.AutomaticTerminalVersionTime, StringComparison.CurrentCultureIgnoreCase))//集中器版本号读取
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-05-20 21:55:48 +08:00
|
|
|
|
timeDensity: timeDensity,
|
|
|
|
|
|
nextTaskTime: currentTime,
|
|
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
|
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempTask = await ConcentratorScheduledAutomaticGetTerminalVersion(timeDensity, data, groupIndex, timestamps);
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"集中器终端版本信息 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerOtherIssuedEventName, tempTask));
|
2025-05-20 21:55:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (string.Equals(currentTimeStr, _applicationOptions.AutomaticTelematicsModuleTime, StringComparison.CurrentCultureIgnoreCase))//SIM卡读取
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-05-20 21:55:48 +08:00
|
|
|
|
timeDensity: timeDensity,
|
|
|
|
|
|
nextTaskTime: currentTime,
|
|
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
|
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempTask = await ConcentratorScheduledAutomaticGetTelematicsModule(timeDensity, data, groupIndex, timestamps);
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"集中器SIM卡读取 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerOtherIssuedEventName, tempTask));
|
2025-05-20 21:55:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (string.Equals(currentTimeStr, _applicationOptions.AutomaticMonthFreezeTime, StringComparison.CurrentCultureIgnoreCase))//月冻结
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-05-20 21:55:48 +08:00
|
|
|
|
timeDensity: timeDensity,
|
|
|
|
|
|
nextTaskTime: currentTime,
|
|
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
|
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempTask = await AmmeterScheduledGetAutomaticMonthFreezeData(timeDensity, data, groupIndex, timestamps);
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"电表月冻结 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerOtherIssuedEventName, tempTask));
|
2025-05-20 21:55:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (string.Equals(currentTimeStr, _applicationOptions.AutomaticDayFreezeTime, StringComparison.CurrentCultureIgnoreCase))//日冻结
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-05-20 21:55:48 +08:00
|
|
|
|
timeDensity: timeDensity,
|
|
|
|
|
|
nextTaskTime: currentTime,
|
|
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
|
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
2025-05-20 16:41:58 +08:00
|
|
|
|
{
|
2025-05-20 21:55:48 +08:00
|
|
|
|
var tempTask = await AmmeterScheduledGetAutomaticDayFreezeData(timeDensity, data, groupIndex, timestamps);
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"电表日冻结 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerOtherIssuedEventName, tempTask));
|
2025-05-20 21:55:48 +08:00
|
|
|
|
});
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInformation($"{nameof(CreateToBeIssueTasks)} 不是自动校时、采集终端信息等时间,继续处理其他");
|
|
|
|
|
|
}
|
2025-05-21 10:14:33 +08:00
|
|
|
|
|
2025-04-14 10:20:48 +08:00
|
|
|
|
//检查任务时间节点,由于定时任务10秒钟运行一次,需要判定当前时间是否在任务时间节点内,不在则跳过
|
2025-04-29 23:48:47 +08:00
|
|
|
|
var currentTaskTime = tasksToBeIssueModel.LastTaskTime.CalculateNextCollectionTime(timeDensity);//程序启动缓存电表的时候,NextTaskTime需要格式化到下一个采集点时间。
|
2025-05-12 10:14:08 +08:00
|
|
|
|
if (!IsTaskTime(currentTaskTime, timeDensity))//todo 如果时间超过两个采集频率周期,就一直处理,直到追加到下一个采集频率周期。
|
2025-04-14 10:20:48 +08:00
|
|
|
|
{
|
2025-04-14 16:41:41 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(CreateToBeIssueTasks)} 构建待处理的下发指令任务处理时Key=>{item}时间节点不在当前时间范围内,103");
|
2025-04-14 10:20:48 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-04-17 15:49:57 +08:00
|
|
|
|
|
2025-04-14 16:41:41 +08:00
|
|
|
|
var meterTypes = EnumExtensions.ToEnumDictionary<MeterTypeEnum>();
|
2025-05-21 10:14:33 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meteryType == MeterTypeEnum.Ammeter.ToString())
|
|
|
|
|
|
{
|
2025-05-22 17:29:54 +08:00
|
|
|
|
//电表最大采集频率为15分钟
|
|
|
|
|
|
if (timeDensity > 15)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeDensity = 15;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-04-18 17:46:24 +08:00
|
|
|
|
timeDensity: timeDensity,
|
2025-04-22 17:58:14 +08:00
|
|
|
|
nextTaskTime: currentTaskTime,
|
2025-04-18 17:46:24 +08:00
|
|
|
|
meterType: MeterTypeEnum.Ammeter,
|
2025-04-24 17:48:20 +08:00
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
2025-04-15 09:43:51 +08:00
|
|
|
|
{
|
2025-04-24 17:48:20 +08:00
|
|
|
|
var tempTask = await AmmerterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
2025-04-21 22:57:49 +08:00
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
2025-05-21 10:14:33 +08:00
|
|
|
|
_logger.LogWarning($"电表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerFifteenMinuteIssuedEventName, tempTask));
|
2025-04-18 17:46:24 +08:00
|
|
|
|
});
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (meteryType == MeterTypeEnum.WaterMeter.ToString())
|
|
|
|
|
|
{
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = CreateMeterPublishTask<DeviceCacheInfo>(
|
2025-04-18 17:46:24 +08:00
|
|
|
|
timeDensity: timeDensity,
|
2025-04-22 17:58:14 +08:00
|
|
|
|
nextTaskTime: currentTaskTime,
|
2025-04-23 11:13:59 +08:00
|
|
|
|
meterType: MeterTypeEnum.WaterMeter,
|
2025-04-24 17:48:20 +08:00
|
|
|
|
taskCreateAction: async (timeDensity, data, groupIndex, timestamps) =>
|
2025-04-18 17:46:24 +08:00
|
|
|
|
{
|
2025-04-24 17:48:20 +08:00
|
|
|
|
var tempTask = await WatermeterCreatePublishTaskAction(timeDensity, data, groupIndex, timestamps);
|
2025-04-23 09:42:09 +08:00
|
|
|
|
|
|
|
|
|
|
if (tempTask == null || tempTask.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"水表 {data.Name} 任务数据构建失败:{data.Serialize()}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.WatermeterSubscriberWorkerAutoReadingIssuedEventName, tempTask));
|
2025-04-18 17:46:24 +08:00
|
|
|
|
});
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-04-14 10:20:48 +08:00
|
|
|
|
_logger.LogError($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建失败,没有获取到缓存信息,-106");
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建完成");
|
|
|
|
|
|
|
2025-04-14 16:41:41 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-04-13 21:26:27 +08:00
|
|
|
|
//根据当前的采集频率和类型,重新更新下一个任务点,把任务的创建源固定在当前逻辑,避免任务处理的逻辑异常导致任务创建失败。
|
2025-04-22 17:58:14 +08:00
|
|
|
|
tasksToBeIssueModel.LastTaskTime = currentTaskTime;
|
|
|
|
|
|
tasksToBeIssueModel.NextTaskTime = currentTaskTime.CalculateNextCollectionTime(timeDensity);
|
2025-04-27 17:27:04 +08:00
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(item, tasksToBeIssueModel);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
2025-04-25 09:28:20 +08:00
|
|
|
|
|
2025-05-18 17:14:30 +08:00
|
|
|
|
////电表定时阀控任务处理。
|
|
|
|
|
|
//var autoValveControlTask = await AmmeterScheduledAutoValveControl();
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
2025-05-18 17:14:30 +08:00
|
|
|
|
//if (autoValveControlTask == null || autoValveControlTask.Count <= 0)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// _logger.LogWarning($"{nameof(AmmeterScheduledAutoValveControl)}电表定时阀控没有可操作的任务");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
//}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
//_ = _dataChannelManage.ScheduledMeterTaskWriterAsync(DataChannelManage.TaskDataChannel.Writer, (KafkaTopicConsts.AmmeterSubscriberWorkerAutoValveControlIssuedEventName, autoValveControlTask));
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
#region 电表采集处理
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取电表信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual Task<List<DeviceCacheInfo>> GetAmmeterInfoList(string gatherCode = "")
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(GetAmmeterInfoList)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化电表缓存数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task InitAmmeterCacheData(string gatherCode = "")
|
|
|
|
|
|
{
|
2025-05-15 23:59:10 +08:00
|
|
|
|
//return;
|
2025-05-08 10:28:23 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建取消令牌源
|
2025-05-26 11:20:32 +08:00
|
|
|
|
//var cts = new CancellationTokenSource();
|
2025-05-21 17:11:27 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
_ = _dataChannelManage.ScheduledMeterTaskReadingAsync(DataChannelManage.TaskDataChannel.Reader);
|
2025-04-30 12:36:54 +08:00
|
|
|
|
|
2025-05-15 23:59:10 +08:00
|
|
|
|
// //此处代码不要删除
|
|
|
|
|
|
//#if DEBUG
|
2025-06-03 11:58:17 +08:00
|
|
|
|
// var redisCacheDeviceCacheInfoHashKeyTemp = $"CollectBus:Energy:JiSheCollectBus2:DeviceCacheInfo";
|
2025-05-15 23:59:10 +08:00
|
|
|
|
|
|
|
|
|
|
// var timer1 = Stopwatch.StartNew();
|
2025-06-03 11:58:17 +08:00
|
|
|
|
// Dictionary<string, List<DeviceCacheInfo>> keyValuePairsTemps = FreeRedisProvider.Instance.HGetAll<List<DeviceCacheInfo>>(redisCacheDeviceCacheInfoHashKeyTemp);
|
|
|
|
|
|
// List<DeviceCacheInfo> meterInfos = new List<DeviceCacheInfo>();
|
2025-05-15 23:59:10 +08:00
|
|
|
|
// List<string> focusAddressDataLista = new List<string>();
|
|
|
|
|
|
// foreach (var item in keyValuePairsTemps)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// foreach (var subItem in item.Value)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (subItem.MeterType == MeterTypeEnum.Ammeter && subItem.TimeDensity == 15)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// meterInfos.Add(subItem);
|
|
|
|
|
|
// focusAddressDataLista.Add(subItem.MeterId.ToString());
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// timer1.Stop();
|
|
|
|
|
|
// _logger.LogError($"电表初始化读取数据总共花费时间{timer1.ElapsedMilliseconds}毫秒");
|
|
|
|
|
|
// DeviceGroupBalanceControl.InitializeCache(focusAddressDataLista, _kafkaOptions.NumPartitions);
|
|
|
|
|
|
// return;
|
|
|
|
|
|
//#else
|
|
|
|
|
|
// var meterInfos = await GetAmmeterInfoList(gatherCode);
|
|
|
|
|
|
//#endif
|
2025-05-14 11:33:31 +08:00
|
|
|
|
var meterInfos = await GetAmmeterInfoList(gatherCode);
|
2025-05-13 14:51:38 +08:00
|
|
|
|
if (meterInfos == null || meterInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,电表数据为空");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
_logger.LogError($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,读取数据成功");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//获取采集项类型数据
|
|
|
|
|
|
var gatherItemInfos = await GetGatherItemByDataTypes();
|
|
|
|
|
|
if (gatherItemInfos == null || gatherItemInfos.Count <= 0)
|
2025-04-18 17:46:24 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
_logger.LogError($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,采集项类型数据为空");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
var timer = Stopwatch.StartNew();
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
List<string> deviceIds = new List<string>();//用于处理Kafka主题分区数据的分发和处理。
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//根据采集频率分组,获得采集频率分组
|
|
|
|
|
|
var meterInfoGroupByTimeDensity = meterInfos.Select(d => d.TimeDensity).GroupBy(d => d);
|
|
|
|
|
|
var currentTaskTime = DateTime.Now;
|
|
|
|
|
|
if (_applicationOptions.FirstCollectionTime.HasValue == false)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
_applicationOptions.FirstCollectionTime = currentTaskTime;
|
|
|
|
|
|
}
|
|
|
|
|
|
//先处理采集频率任务缓存
|
|
|
|
|
|
foreach (var item in meterInfoGroupByTimeDensity)
|
|
|
|
|
|
{
|
|
|
|
|
|
TasksToBeIssueModel nextTask = new TasksToBeIssueModel()
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
LastTaskTime = _applicationOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),
|
|
|
|
|
|
TimeDensity = item.Key,
|
|
|
|
|
|
};
|
|
|
|
|
|
nextTask.NextTaskTime = nextTask.LastTaskTime.CalculateNextCollectionTime(item.Key);
|
|
|
|
|
|
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
|
|
|
|
|
|
|
|
|
|
|
var taskRedisCacheKey = string.Format(RedisConst.CacheTasksToBeIssuedKey, SystemType, ServerTagName, MeterTypeEnum.Ammeter, item.Key);
|
|
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(taskRedisCacheKey, nextTask);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//设备hash缓存key
|
2025-06-03 11:58:17 +08:00
|
|
|
|
string redisCacheDeviceCacheInfoHashKey = $"{string.Format(RedisConst.CacheDeviceInfoHashKey, SystemType, ServerTagName)}";
|
2025-04-23 16:17:29 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//设备分组集合key
|
|
|
|
|
|
string redisCacheDeviceGroupSetIndexKey = $"{string.Format(RedisConst.CacheDeviceGroupSetIndexKey, SystemType, ServerTagName)}";
|
|
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
Dictionary<string, List<DeviceCacheInfo>> keyValuePairs = new Dictionary<string, List<DeviceCacheInfo>>();
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
|
|
|
|
|
//处理设备缓存信息
|
|
|
|
|
|
foreach (var ammeter in meterInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
deviceIds.Add(ammeter.MeterId.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
//处理ItemCode
|
2025-05-22 17:29:54 +08:00
|
|
|
|
if (ammeter.ItemCodes == null && !string.IsNullOrWhiteSpace(ammeter.DataTypes))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-22 17:29:54 +08:00
|
|
|
|
ammeter.ItemCodes = new List<string>();
|
|
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
var itemArr = ammeter.DataTypes.Split(',').ToList();
|
2025-04-23 11:13:59 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
#region 拼接采集项
|
|
|
|
|
|
List<string> itemCodeList = new List<string>();
|
|
|
|
|
|
foreach (var dataType in itemArr)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
var excludeItemCode = "10_98,10_94";//TODO 排除透明转发:尖峰平谷时段、跳合闸,特殊电表
|
|
|
|
|
|
var gatherItem = gatherItemInfos.FirstOrDefault(f => f.DataType.Equals(dataType));
|
|
|
|
|
|
if (gatherItem != null)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
if (!excludeItemCode.Contains(gatherItem.ItemCode))
|
2025-03-17 11:34:30 +08:00
|
|
|
|
{
|
2025-05-22 17:29:54 +08:00
|
|
|
|
itemCodeList.Add(gatherItem.ItemCode.Replace("WAVE_109", "10_109"));
|
2025-03-17 11:34:30 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-17 11:34:30 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
#region 特殊电表采集项编号处理
|
|
|
|
|
|
if (itemArr.Exists(e => e.Equals("95"))) //德力西DTS
|
|
|
|
|
|
{
|
|
|
|
|
|
itemCodeList.Add("10_95");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (itemArr.Exists(e => e.Equals("109")))//WAVE_109
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
itemCodeList.Add("10_109");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-05-13 14:51:38 +08:00
|
|
|
|
#endregion
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-05-13 14:51:38 +08:00
|
|
|
|
#endregion
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-05-12 23:18:02 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
ammeter.ItemCodes = itemCodeList;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
//var tempItemCodeList = new List<string>() { "10_97" };
|
|
|
|
|
|
//ammeter.ItemCodes = tempItemCodeList.Serialize();
|
2025-05-18 16:04:23 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
if (!keyValuePairs.ContainsKey(ammeter.FocusAddress))
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
keyValuePairs[ammeter.FocusAddress] = new List<DeviceCacheInfo>() { ammeter.Adapt<DeviceCacheInfo>() };
|
2025-05-13 14:51:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
keyValuePairs[ammeter.FocusAddress].Add(ammeter.Adapt<DeviceCacheInfo>());
|
2025-05-13 14:51:38 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
await _redisDataCacheService.BatchInsertDataAsync<DeviceCacheInfo>(
|
2025-05-13 14:51:38 +08:00
|
|
|
|
redisCacheDeviceGroupSetIndexKey,
|
2025-06-03 11:58:17 +08:00
|
|
|
|
redisCacheDeviceCacheInfoHashKey,
|
2025-05-13 14:51:38 +08:00
|
|
|
|
keyValuePairs);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//初始化设备组负载控制
|
|
|
|
|
|
if (deviceIds == null || deviceIds.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(InitAmmeterCacheData)} 初始化设备组负载控制失败,没有找到对应的设备信息");
|
2025-04-10 14:12:14 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
DeviceGroupBalanceControl.InitializeCache(deviceIds, _kafkaOptions.NumPartitions);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
timer.Stop();
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogWarning($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据完成,耗时{timer.ElapsedMilliseconds}毫秒");
|
2025-04-10 14:12:14 +08:00
|
|
|
|
}
|
2025-05-13 14:51:38 +08:00
|
|
|
|
catch (Exception ex)
|
2025-04-10 14:12:14 +08:00
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
_logger.LogError(ex, $"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据异常");
|
|
|
|
|
|
throw ex;
|
2025-04-10 14:12:14 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <summary>
|
2025-04-18 17:46:24 +08:00
|
|
|
|
/// 创建电表待发送的任务数据
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// </summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
2025-04-18 17:46:24 +08:00
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
2025-04-17 11:29:26 +08:00
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
2025-04-21 22:57:49 +08:00
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
private async Task<List<MeterReadingTelemetryPacketInfo>> AmmerterCreatePublishTaskAction(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
2025-04-18 11:31:23 +08:00
|
|
|
|
|
2025-04-24 17:48:20 +08:00
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 创建电表待发送的任务数据{currentTime}没有找到对应的协议组件,-105");
|
2025-04-29 23:48:47 +08:00
|
|
|
|
return null;
|
2025-04-24 17:48:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
if (ammeterInfo.ItemCodes == null || ammeterInfo.ItemCodes.Count <=0)
|
2025-04-14 21:56:24 +08:00
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}数据采集指令生成失败,采集项为空,-101");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//载波的不处理
|
|
|
|
|
|
if (ammeterInfo.MeteringPort == (int)MeterLinkProtocolEnum.Carrierwave)
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}数据采集指令生成失败,载波不处理,-102");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
2025-04-14 17:38:34 +08:00
|
|
|
|
|
2025-04-14 21:56:24 +08:00
|
|
|
|
if (ammeterInfo.State.Equals(2))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTaskAction)} {ammeterInfo.Name} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}状态为禁用,不处理");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////排除1天未在线的集中器生成指令 或 排除集中器配置为自动上报的集中器
|
|
|
|
|
|
//if (!IsGennerateCmd(ammeter.LastTime, -1))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// _logger.LogInformation($"{nameof(CreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name},采集时间:{ammeter.LastTime},已超过1天未在线,不生成指令");
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
//}
|
2025-04-14 17:38:34 +08:00
|
|
|
|
|
2025-04-14 21:56:24 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeterInfo.AreaCode))
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 表ID:{ammeterInfo.MeterId},集中器通信区号为空");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeterInfo.Address))
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 表ID:{ammeterInfo.MeterId},集中器通信地址为空");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (Convert.ToInt32(ammeterInfo.Address) > 65535)
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 表ID:{ammeterInfo.MeterId},集中器通信地址无效,确保大于65535");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (ammeterInfo.MeteringCode <= 0 || ammeterInfo.MeteringCode > 33)
|
|
|
|
|
|
{
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//_logger.LogError($"{nameof(AmmerterCreatePublishTaskAction)} 表ID:{ammeterInfo.MeterId},非有效测量点号({ammeterInfo.MeteringCode})");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
List<string> tempCodes = ammeterInfo.ItemCodes!;
|
2025-04-14 21:56:24 +08:00
|
|
|
|
|
|
|
|
|
|
//TODO:自动上报数据只主动采集1类数据。
|
|
|
|
|
|
if (ammeterInfo.AutomaticReport.Equals(1))
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempSubCodes = new List<string>();
|
|
|
|
|
|
if (tempCodes.Contains("0C_49"))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-14 21:56:24 +08:00
|
|
|
|
tempSubCodes.Add("0C_49");
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 21:56:24 +08:00
|
|
|
|
if (tempSubCodes.Contains("0C_149"))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-14 21:56:24 +08:00
|
|
|
|
tempSubCodes.Add("0C_149");
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 21:56:24 +08:00
|
|
|
|
if (ammeterInfo.ItemCodes.Contains("10_97"))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-14 21:56:24 +08:00
|
|
|
|
tempSubCodes.Add("10_97");
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 21:56:24 +08:00
|
|
|
|
if (tempSubCodes == null || tempSubCodes.Count <= 0)
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-15 15:49:51 +08:00
|
|
|
|
//_logger.LogInformation($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}自动上报数据主动采集1类数据时数据类型为空");
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return null;
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
2025-04-14 21:56:24 +08:00
|
|
|
|
else
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
2025-04-14 21:56:24 +08:00
|
|
|
|
tempCodes = tempSubCodes;
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
2025-04-14 21:56:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-17 11:29:26 +08:00
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
2025-04-14 21:56:24 +08:00
|
|
|
|
|
|
|
|
|
|
foreach (var tempItem in tempCodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
//排除已发送日冻结和月冻结采集项配置
|
|
|
|
|
|
if (DayFreezeCodes.Contains(tempItem))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-04-14 21:56:24 +08:00
|
|
|
|
|
|
|
|
|
|
if (MonthFreezeCodes.Contains(tempItem))
|
2025-04-14 17:38:34 +08:00
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-24 17:48:20 +08:00
|
|
|
|
//var itemCodeArr = tempItem.Split('_');
|
|
|
|
|
|
//var aFNStr = itemCodeArr[0];
|
|
|
|
|
|
//var aFN = (AFN)aFNStr.HexToDec();
|
|
|
|
|
|
//var fn = int.Parse(itemCodeArr[1]);
|
2025-04-14 17:38:34 +08:00
|
|
|
|
|
2025-05-20 16:41:58 +08:00
|
|
|
|
//特殊编码映射
|
2025-05-15 23:59:10 +08:00
|
|
|
|
var itemCodeInfo = T37612012PacketItemCodeConst.MappingItemCodeTo645SubCodeRelationship(tempItem);
|
|
|
|
|
|
|
2025-04-24 17:48:20 +08:00
|
|
|
|
//TODO:特殊表
|
2025-04-24 23:39:39 +08:00
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
2025-04-24 17:48:20 +08:00
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
2025-05-20 16:41:58 +08:00
|
|
|
|
Pn = itemCodeInfo.Item1 == T37612012PacketItemCodeConst.AFN10HFN01H ? 0 : ammeterInfo.MeteringCode,
|
2025-05-15 23:59:10 +08:00
|
|
|
|
ItemCode = itemCodeInfo.Item1,
|
2025-04-30 17:11:09 +08:00
|
|
|
|
DataTimeMark = new Protocol.DataTimeMark()
|
|
|
|
|
|
{
|
2025-05-11 21:53:55 +08:00
|
|
|
|
Density = ammeterInfo.TimeDensity.GetFocusDensity(),//转换成协议的值
|
2025-04-30 17:11:09 +08:00
|
|
|
|
Point = 1,
|
|
|
|
|
|
DataTime = timestamps,
|
2025-05-15 23:59:10 +08:00
|
|
|
|
},
|
|
|
|
|
|
SubProtocolRequest = new SubProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
MeterAddress = ammeterInfo.MeterAddress,
|
|
|
|
|
|
Password = ammeterInfo.Password,
|
|
|
|
|
|
MeteringPort = ammeterInfo.MeteringPort,
|
|
|
|
|
|
Baudrate = ammeterInfo.Baudrate,
|
|
|
|
|
|
ItemCode = itemCodeInfo.Item2, //10_97 => 11_02_80_00_02
|
2025-04-30 17:11:09 +08:00
|
|
|
|
}
|
2025-04-24 17:48:20 +08:00
|
|
|
|
});
|
2025-04-18 11:31:23 +08:00
|
|
|
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
2025-04-14 21:56:24 +08:00
|
|
|
|
{
|
2025-04-15 15:49:51 +08:00
|
|
|
|
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}未能正确获取报文。");
|
2025-04-14 21:56:24 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-04-14 17:38:34 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
|
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: DateTimeOffset.Now.ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
2025-05-20 16:41:58 +08:00
|
|
|
|
itemCode: itemCodeInfo.Item1,
|
|
|
|
|
|
subItemCode: itemCodeInfo.Item2,
|
2025-04-29 23:48:47 +08:00
|
|
|
|
pendingCopyReadTime: timestamps,
|
2025-04-29 10:02:10 +08:00
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: (TelemetryPacketTypeEnum)timeDensity,
|
|
|
|
|
|
_guidGenerator);
|
2025-04-17 11:29:26 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
2025-04-14 17:38:34 +08:00
|
|
|
|
}
|
2025-04-15 09:43:51 +08:00
|
|
|
|
|
2025-04-21 22:57:49 +08:00
|
|
|
|
return taskList;
|
2025-04-15 15:49:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-23 16:17:29 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取电表阀控配置
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="currentTime">阀控的时间</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual Task<List<AmmeterAutoValveControlSetting>> GetAmmeterAutoValveControlSetting(string currentTime)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(GetAmmeterInfoList)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 电表自动阀控
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2025-04-30 12:36:54 +08:00
|
|
|
|
public virtual Task<List<MeterReadingTelemetryPacketInfo>> AmmeterScheduledAutoValveControl()
|
2025-04-23 16:17:29 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(AmmeterScheduledAutoValveControl)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-25 12:01:15 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 电表自动校时
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual async Task<List<MeterReadingTelemetryPacketInfo>> AmmeterScheduledAutomaticVerificationTime(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-25 12:01:15 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
|
#else
|
2025-04-25 12:01:15 +08:00
|
|
|
|
//判断是否是自动校时时间
|
2025-04-27 17:27:04 +08:00
|
|
|
|
if (!string.Equals(currentTimeStr, _applicationOptions.AutomaticVerificationTime, StringComparison.CurrentCultureIgnoreCase))
|
2025-04-25 12:01:15 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledAutomaticVerificationTime)} 电表自动校时,非自动校时时间");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-25 12:01:15 +08:00
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#endif
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
2025-04-25 12:01:15 +08:00
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
|
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
var itemCode = T37612012PacketItemCodeConst.AFN10HFN01H;
|
|
|
|
|
|
var subItemCode = T6452007PacketItemCodeConst.C08;
|
2025-04-25 12:01:15 +08:00
|
|
|
|
|
|
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有找到对应的协议组件,-105");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-25 12:01:15 +08:00
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
|
2025-04-25 12:01:15 +08:00
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
2025-04-27 09:40:31 +08:00
|
|
|
|
ItemCode = itemCode,
|
2025-04-25 12:01:15 +08:00
|
|
|
|
SubProtocolRequest = new SubProtocolBuildRequest()
|
|
|
|
|
|
{
|
2025-05-13 14:51:38 +08:00
|
|
|
|
MeterAddress = ammeterInfo.MeterAddress,
|
2025-04-25 12:01:15 +08:00
|
|
|
|
Password = ammeterInfo.Password,
|
2025-04-27 09:40:31 +08:00
|
|
|
|
ItemCode = subItemCode,
|
2025-04-25 12:01:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
|
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: itemCode,
|
|
|
|
|
|
subItemCode: subItemCode,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
2025-04-29 10:02:10 +08:00
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: TelemetryPacketTypeEnum.AmmeterAutomaticVerificationTime,
|
|
|
|
|
|
_guidGenerator);
|
2025-04-25 12:01:15 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
|
|
|
|
|
|
|
|
|
|
|
if (taskList == null || taskList.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有自动阀控任务生成,-106");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-25 12:01:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-25 12:01:15 +08:00
|
|
|
|
|
|
|
|
|
|
//todo 阀控记录入库,推送到新的服务
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 日冻结抄读
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual async Task<List<MeterReadingTelemetryPacketInfo>> AmmeterScheduledGetAutomaticDayFreezeData(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
|
#else
|
|
|
|
|
|
//判断是否是日冻结抄读时间
|
|
|
|
|
|
if (!string.Equals(currentTimeStr, _applicationOptions.AutomaticDayFreezeTime, StringComparison.CurrentCultureIgnoreCase))
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledGetAutomaticDayFreezeData)} 非电表日冻结抄读时间,暂不处理");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#endif
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 电表日冻结抄读运行时间{currentTime}没有找到对应的协议组件,-105");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
2025-04-29 10:02:10 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
foreach (var item in DayFreezeCodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
2025-05-20 21:55:48 +08:00
|
|
|
|
ItemCode = item,
|
|
|
|
|
|
DataTimeMark = new Protocol.DataTimeMark()
|
|
|
|
|
|
{
|
|
|
|
|
|
Density = ammeterInfo.TimeDensity.GetFocusDensity(),//转换成协议的值
|
|
|
|
|
|
Point = 1,
|
|
|
|
|
|
DataTime = currentTime.AddDays(-1),//日冻结抄读时间为昨天
|
|
|
|
|
|
},
|
2025-04-27 17:27:04 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
|
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: item,
|
|
|
|
|
|
subItemCode: null,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
2025-04-29 10:02:10 +08:00
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: TelemetryPacketTypeEnum.AmmeterDayFreeze,
|
|
|
|
|
|
_guidGenerator);
|
2025-04-27 17:27:04 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
|
|
|
|
|
}
|
2025-04-29 10:02:10 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
if (taskList == null || taskList.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 日冻结抄读时间{currentTime}没有任务生成,-106");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return taskList;
|
2025-04-29 10:02:10 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 月冻结数据抄读
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual async Task<List<MeterReadingTelemetryPacketInfo>> AmmeterScheduledGetAutomaticMonthFreezeData(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
2025-05-20 21:55:48 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
#else
|
2025-05-20 21:55:48 +08:00
|
|
|
|
//需要检查是不是每月1号抄读上个月的数据
|
|
|
|
|
|
if (currentTime.Date != currentTime.FirstDayOfMonth().Date)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledGetAutomaticMonthFreezeData)} 非月冻结数据抄读时间,暂不处理");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
timestamps = currentTime.LastDayOfPrdviousMonth();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-20 16:41:58 +08:00
|
|
|
|
//判断是否是月冻结数据抄读
|
|
|
|
|
|
if (!string.Equals(currentTimeStr, _applicationOptions.AutomaticMonthFreezeTime, StringComparison.CurrentCultureIgnoreCase))
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledAutomaticVerificationTime)} 非电表月冻结抄读时间,暂不处理");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#endif
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 电表月冻结抄读时间{currentTime}没有找到对应的协议组件,-105");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-20 21:55:48 +08:00
|
|
|
|
foreach (var item in MonthFreezeCodes)
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
|
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
2025-05-20 21:55:48 +08:00
|
|
|
|
ItemCode = item,
|
|
|
|
|
|
DataTimeMark = new Protocol.DataTimeMark()
|
|
|
|
|
|
{
|
|
|
|
|
|
Density = ammeterInfo.TimeDensity.GetFocusDensity(),//转换成协议的值
|
|
|
|
|
|
Point = 1,
|
|
|
|
|
|
#if DEBUG
|
|
|
|
|
|
DataTime = currentTime.AddMonths(-1),//月冻结抄读时间为上个月
|
|
|
|
|
|
#else
|
|
|
|
|
|
DataTime = timestamps,//月冻结抄读时间为上个月
|
|
|
|
|
|
#endif
|
|
|
|
|
|
},
|
2025-04-27 17:27:04 +08:00
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
|
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: item,
|
|
|
|
|
|
subItemCode: null,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
2025-04-29 10:02:10 +08:00
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: TelemetryPacketTypeEnum.AmmeterMonthFreeze,
|
|
|
|
|
|
_guidGenerator);
|
2025-04-27 17:27:04 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (taskList == null || taskList.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 日冻结抄读时间{currentTime}没有任务生成,-106");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return taskList;
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-29 09:16:48 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 电表监控重试抄读任务
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="retryReadingEnum"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task AmmeterScheduledRetryReading(RetryReadingEnum retryReadingEnum)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 根据任务获取不同的锁
|
|
|
|
|
|
var tryLock = FreeRedisProvider.Instance.Lock(retryReadingEnum.ToString(), 10);
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-04-29 23:48:47 +08:00
|
|
|
|
if (tryLock != null)
|
2025-04-29 09:16:48 +08:00
|
|
|
|
{
|
|
|
|
|
|
// 轮询IotDB未成果下发电表数据
|
|
|
|
|
|
var conditions = new List<QueryCondition>();
|
|
|
|
|
|
// 下次发布时间小于等于当前时间
|
|
|
|
|
|
conditions.Add(new QueryCondition()
|
|
|
|
|
|
{
|
|
|
|
|
|
Field = "NextSendTime",
|
|
|
|
|
|
Operator = "<",
|
|
|
|
|
|
IsNumber = false,
|
|
|
|
|
|
Value = DateTime.Now
|
|
|
|
|
|
});
|
|
|
|
|
|
// 重试次数少于3次
|
|
|
|
|
|
conditions.Add(new QueryCondition()
|
|
|
|
|
|
{
|
|
|
|
|
|
Field = "SendNum",
|
|
|
|
|
|
Operator = "<",
|
|
|
|
|
|
IsNumber = true,
|
|
|
|
|
|
Value = 3
|
|
|
|
|
|
});
|
|
|
|
|
|
//已发布的
|
|
|
|
|
|
conditions.Add(new QueryCondition()
|
|
|
|
|
|
{
|
|
|
|
|
|
Field = "IsSend",
|
|
|
|
|
|
Operator = "=",
|
|
|
|
|
|
IsNumber = false,
|
|
|
|
|
|
Value = true
|
|
|
|
|
|
});
|
|
|
|
|
|
// 未响应
|
|
|
|
|
|
conditions.Add(new QueryCondition()
|
|
|
|
|
|
{
|
|
|
|
|
|
Field = "IsReceived",
|
|
|
|
|
|
Operator = "=",
|
|
|
|
|
|
IsNumber = false,
|
|
|
|
|
|
Value = false
|
|
|
|
|
|
});
|
2025-06-03 11:58:17 +08:00
|
|
|
|
//await CreateMeterKafkaTaskMessage<MeterReadingTelemetryPacketInfo>(KafkaTopicConsts.AmmeterSubscriberWorkerRetryEventName, new IoTDBQueryOptions()
|
2025-04-30 12:36:54 +08:00
|
|
|
|
//{
|
|
|
|
|
|
// TableNameOrTreePath = DevicePathBuilder.GetTableName<MeterReadingTelemetryPacketInfo>(),
|
|
|
|
|
|
// PageIndex = 1,
|
|
|
|
|
|
// PageSize = pageSize,
|
|
|
|
|
|
// Conditions = conditions,
|
|
|
|
|
|
//});
|
2025-04-29 09:16:48 +08:00
|
|
|
|
// 释放锁
|
|
|
|
|
|
tryLock.Unlock();
|
|
|
|
|
|
}
|
2025-04-29 23:48:47 +08:00
|
|
|
|
|
2025-04-29 09:16:48 +08:00
|
|
|
|
}
|
2025-04-29 23:48:47 +08:00
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 释放锁
|
|
|
|
|
|
tryLock.Unlock();
|
|
|
|
|
|
throw;
|
2025-04-29 09:16:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-05-20 21:55:48 +08:00
|
|
|
|
#endregion
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 水表采集处理
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取水表信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual Task<List<DeviceCacheInfo>> GetWatermeterInfoList(string gatherCode = "")
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(GetWatermeterInfoList)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化水表缓存数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task InitWatermeterCacheData(string gatherCode = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
var meterInfos = await GetWatermeterInfoList(gatherCode);
|
|
|
|
|
|
if (meterInfos == null || meterInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NullReferenceException($"{nameof(InitWatermeterCacheData)} 初始化水表缓存数据时,水表数据为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取采集项类型数据
|
|
|
|
|
|
var gatherItemInfos = await GetGatherItemByDataTypes();
|
|
|
|
|
|
if (gatherItemInfos == null || gatherItemInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NullReferenceException($"{nameof(InitAmmeterCacheData)} 初始化水表缓存数据时,采集项类型数据为空");
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
if (meterInfos != null && meterInfos.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in meterInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
if (item.MeterTypeName.Equals("水表") && (item.Protocol.Equals((int)MeterLinkProtocol.CJT_188_2018) || item.Protocol.Equals((int)MeterLinkProtocol.DLT_645_1997) || item.Protocol.Equals((int)MeterLinkProtocol.DLT_645_2007)))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.BrandType.Contains("炬华有线"))
|
|
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN0CHFN188H };
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN0CHFN129H };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-23 14:19:57 +08:00
|
|
|
|
else if (item.MeterTypeName.Equals("流量计") && item.BrandType.Trim().Equals("西恩超声波流量计"))
|
2025-05-22 17:29:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN09HFN01H };
|
|
|
|
|
|
}
|
2025-05-23 14:19:57 +08:00
|
|
|
|
else if (item.MeterTypeName.Equals("流量计") && item.BrandType.Trim().Equals("江苏华海涡街流量计积算仪"))
|
2025-05-22 17:29:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN09HFN01H };
|
|
|
|
|
|
}
|
2025-05-23 14:19:57 +08:00
|
|
|
|
else if (item.MeterTypeName.Equals("流量计") && item.BrandType.Trim().Equals("V880BR涡街流量计"))
|
2025-05-22 17:29:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN09HFN01H };
|
|
|
|
|
|
}
|
2025-05-23 14:19:57 +08:00
|
|
|
|
else if (item.MeterTypeName.Equals("流量计") && item.BrandType.Trim().Equals("拓思特涡街流量计H880BR"))
|
2025-05-22 17:29:54 +08:00
|
|
|
|
{
|
|
|
|
|
|
item.ItemCodes = new List<string>() { T37612012PacketItemCodeConst.AFN09HFN01H };
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-23 11:13:59 +08:00
|
|
|
|
List<string> deviceIds = new List<string>();//用于处理Kafka主题分区数据的分发和处理。
|
2025-04-23 09:42:09 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//根据采集频率分组,获得采集频率分组
|
2025-05-15 23:59:10 +08:00
|
|
|
|
var meterInfoGroupByTimeDensity = meterInfos.Select(d => d.TimeDensity).GroupBy(d => d);
|
2025-04-29 23:48:47 +08:00
|
|
|
|
var currentTime = DateTime.Now;
|
2025-04-25 09:28:20 +08:00
|
|
|
|
if (_applicationOptions.FirstCollectionTime.HasValue == false)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-29 23:48:47 +08:00
|
|
|
|
_applicationOptions.FirstCollectionTime = currentTime;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//先处理采集频率任务缓存
|
|
|
|
|
|
foreach (var item in meterInfoGroupByTimeDensity)
|
|
|
|
|
|
{
|
|
|
|
|
|
TasksToBeIssueModel nextTask = new TasksToBeIssueModel()
|
|
|
|
|
|
{
|
2025-04-29 23:48:47 +08:00
|
|
|
|
LastTaskTime = _applicationOptions.FirstCollectionTime.Value.CalculateNextCollectionTime(item.Key),
|
2025-04-30 12:36:54 +08:00
|
|
|
|
TimeDensity = item.Key,
|
2025-04-23 09:42:09 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-04-29 23:48:47 +08:00
|
|
|
|
nextTask.NextTaskTime = nextTask.LastTaskTime.CalculateNextCollectionTime(item.Key);//使用首次采集时间作为下一次采集时间
|
|
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
//todo 首次采集时间节点到目前运行时间中漏采的时间点,可以考虑使用IoTDB的存储,利用时间序列处理。
|
|
|
|
|
|
|
|
|
|
|
|
var taskRedisCacheKey = string.Format(RedisConst.CacheTasksToBeIssuedKey, SystemType, ServerTagName, MeterTypeEnum.WaterMeter, item.Key);
|
|
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(taskRedisCacheKey, nextTask);
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//设备hash缓存key
|
2025-06-03 11:58:17 +08:00
|
|
|
|
string redisCacheDeviceCacheInfoHashKey = $"{string.Format(RedisConst.CacheDeviceInfoHashKey, SystemType, ServerTagName)}";
|
2025-04-23 09:42:09 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//设备分组集合key
|
|
|
|
|
|
string redisCacheDeviceGroupSetIndexKey = $"{string.Format(RedisConst.CacheDeviceGroupSetIndexKey, SystemType, ServerTagName)}";
|
2025-04-23 11:13:59 +08:00
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
Dictionary<string, List<DeviceCacheInfo>> keyValuePairs = new Dictionary<string, List<DeviceCacheInfo>>();
|
2025-05-13 14:51:38 +08:00
|
|
|
|
foreach (var subItem in meterInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
deviceIds.Add(subItem.MeterId.ToString());
|
2025-04-23 09:42:09 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
if (!keyValuePairs.ContainsKey(subItem.FocusAddress))
|
|
|
|
|
|
{
|
2025-06-03 11:58:17 +08:00
|
|
|
|
keyValuePairs[subItem.FocusAddress] = new List<DeviceCacheInfo>() { subItem };
|
2025-05-13 14:51:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
keyValuePairs[subItem.FocusAddress].Add(subItem);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
await _redisDataCacheService.BatchInsertDataAsync<DeviceCacheInfo>(
|
2025-05-13 14:51:38 +08:00
|
|
|
|
redisCacheDeviceGroupSetIndexKey,
|
2025-06-03 11:58:17 +08:00
|
|
|
|
redisCacheDeviceCacheInfoHashKey,
|
2025-05-13 14:51:38 +08:00
|
|
|
|
keyValuePairs);
|
|
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
//初始化设备组负载控制
|
2025-04-23 11:13:59 +08:00
|
|
|
|
if (deviceIds == null || deviceIds.Count <= 0)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(InitAmmeterCacheData)} 初始化设备组负载控制失败,没有找到对应的设备信息");
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-04-23 11:13:59 +08:00
|
|
|
|
DeviceGroupBalanceControl.InitializeCache(deviceIds, _kafkaOptions.NumPartitions);
|
2025-03-17 11:34:30 +08:00
|
|
|
|
}
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(InitAmmeterCacheData)} 初始化水表缓存数据完成");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建水表待发送的任务数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="watermeter">水表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">时间格式的任务批次名称</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-04-24 17:48:20 +08:00
|
|
|
|
private async Task<List<MeterReadingTelemetryPacketInfo>> WatermeterCreatePublishTaskAction(int timeDensity
|
2025-06-03 11:58:17 +08:00
|
|
|
|
, DeviceCacheInfo watermeter, int groupIndex, DateTime timestamps)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
string typeName;
|
|
|
|
|
|
if (watermeter.MeterType == MeterTypeEnum.WaterMeter)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeDensity = watermeter.TimeDensity;//水表默认为60分钟
|
|
|
|
|
|
typeName = watermeter.LinkType;
|
2025-05-21 10:14:33 +08:00
|
|
|
|
if (watermeter.BrandType.Contains("泉高阀门") || watermeter.BrandType.Equals("LXSY-山水翔"))
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-05-21 10:14:33 +08:00
|
|
|
|
typeName = watermeter.BrandType;
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-04-23 09:42:09 +08:00
|
|
|
|
else if (watermeter.MeterType == MeterTypeEnum.WaterMeterFlowmeter)
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
2025-05-21 10:14:33 +08:00
|
|
|
|
typeName = watermeter.BrandType;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(WatermeterCreatePublishTaskAction)} 水表类型错误:{watermeter.Serialize()}");
|
|
|
|
|
|
return null;
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
//根据表型号获取协议插件
|
2025-05-13 14:51:38 +08:00
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(watermeter.BrandType);
|
2025-04-27 09:40:31 +08:00
|
|
|
|
if (protocolPlugin == null)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-05-22 17:29:54 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 创建水表待发送的任务数据时{currentTime}没有找到对应的协议组件,-101");
|
2025-04-27 09:40:31 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-04-27 09:40:31 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
if (watermeter.ItemCodes == null || watermeter.ItemCodes.Count <=0)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-05-22 17:29:54 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 创建水表待发送的任务数据时{watermeter.Name}没有相应的采集项,-102");
|
2025-04-27 09:40:31 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
foreach (var item in watermeter.ItemCodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tempRequest = new ProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = watermeter.FocusAddress,
|
|
|
|
|
|
Pn = watermeter.MeteringCode,
|
|
|
|
|
|
ItemCode = item,
|
|
|
|
|
|
};
|
2025-04-27 09:40:31 +08:00
|
|
|
|
|
2025-05-22 17:29:54 +08:00
|
|
|
|
if (item == T37612012PacketItemCodeConst.AFN09HFN01H)
|
|
|
|
|
|
{
|
|
|
|
|
|
//var itemCodeInfo = T37612012PacketItemCodeConst.MappingItemCodeTo188SubCodeRelationship(T37612012PacketItemCodeConst.AFN10HFN99H, true);//阀控
|
|
|
|
|
|
tempRequest.SubProtocolRequest = new SubProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
MeterAddress = watermeter.MeterAddress,
|
|
|
|
|
|
Password = watermeter.Password,
|
|
|
|
|
|
ItemCode = T1882018PacketItemCodeConst.CTR01901F00,
|
|
|
|
|
|
MeteringPort = watermeter.MeteringPort,
|
|
|
|
|
|
Baudrate = watermeter.Baudrate,
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(tempRequest);
|
|
|
|
|
|
|
|
|
|
|
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
//_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeterInfo.FocusAddress}的电表{ammeterInfo.Name}采集项{tempItem}未能正确获取报文。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (builderResponse == null || builderResponse.Data.Length <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"{nameof(WatermeterCreatePublishTaskAction)} 集中器{watermeter.FocusAddress}的水表{watermeter.Name} 水表采抄读采集项{T1882018PacketItemCodeConst.CTR01901F00}未能正确获取报文。");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
|
|
|
|
|
ammeterInfo: watermeter,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: T37612012PacketItemCodeConst.AFN10HFN01H,
|
|
|
|
|
|
subItemCode: T1882018PacketItemCodeConst.CTR01901F00,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
|
|
|
|
|
creationTime: currentTime,
|
|
|
|
|
|
packetType: TelemetryPacketTypeEnum.WatermeterAutoReadding,
|
|
|
|
|
|
_guidGenerator);
|
|
|
|
|
|
taskList.Add(meterReadingRecords);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
return taskList;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 集中器处理
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 自动获取终端版
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual async Task<List<MeterReadingTelemetryPacketInfo>> ConcentratorScheduledAutomaticGetTerminalVersion(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-27 09:40:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
|
|
|
|
|
|
|
|
|
|
|
try
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-05-18 17:14:30 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
#else
|
2025-04-27 09:40:31 +08:00
|
|
|
|
//判断是否是自动获取版本号时间
|
2025-04-27 17:27:04 +08:00
|
|
|
|
if (!string.Equals(currentTimeStr, _applicationOptions.AutomaticTerminalVersionTime, StringComparison.CurrentCultureIgnoreCase))
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-27 09:40:31 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(ConcentratorScheduledAutomaticGetTerminalVersion)} 集中器自动获取版本号,非自动处理时间");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-05-18 17:14:30 +08:00
|
|
|
|
#endif
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
var itemCode = T37612012PacketItemCodeConst.AFN09HFN01H;
|
|
|
|
|
|
//var subItemCode = T6452007PacketItemCodeConst.C08;
|
|
|
|
|
|
|
|
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-27 09:40:31 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 集中器自动获取版本号{currentTime}没有找到对应的协议组件,-105");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-24 23:39:39 +08:00
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-27 09:40:31 +08:00
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
|
|
|
|
|
ItemCode = itemCode,
|
|
|
|
|
|
//SubProtocolRequest = new SubProtocolBuildRequest()
|
|
|
|
|
|
//{
|
|
|
|
|
|
// MeterAddress = ammeterInfo.AmmerterAddress,
|
|
|
|
|
|
// Password = ammeterInfo.Password,
|
|
|
|
|
|
// ItemCode = subItemCode,
|
|
|
|
|
|
//}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
2025-05-13 14:51:38 +08:00
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: itemCode,
|
|
|
|
|
|
subItemCode: null,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
|
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: TelemetryPacketTypeEnum.TerminalVersion,
|
|
|
|
|
|
_guidGenerator);
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
|
|
|
|
|
|
|
|
|
|
|
if (taskList == null || taskList.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有自动阀控任务生成,-106");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 09:40:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return taskList;
|
2025-04-27 09:40:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 自动获取远程通信模块(SIM)版本信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="groupIndex">集中器所在分组</param>
|
|
|
|
|
|
/// <param name="timestamps">采集频率对应的时间戳</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
public virtual async Task<List<MeterReadingTelemetryPacketInfo>> ConcentratorScheduledAutomaticGetTelematicsModule(int timeDensity, DeviceCacheInfo ammeterInfo, int groupIndex, DateTime timestamps)
|
2025-04-27 09:40:31 +08:00
|
|
|
|
{
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
string currentTimeStr = $"{currentTime:HH:mm:00}";
|
|
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
#else
|
2025-04-27 09:40:31 +08:00
|
|
|
|
//判断是否是自动获取版本号时间
|
2025-04-27 17:27:04 +08:00
|
|
|
|
if (!string.Equals(currentTimeStr, _applicationOptions.AutomaticTerminalVersionTime, StringComparison.CurrentCultureIgnoreCase))
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-27 09:40:31 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(ConcentratorScheduledAutomaticGetTelematicsModule)} 自动获取远程通信模块(SIM)版本信息,非自动处理时间");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#endif
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
List<MeterReadingTelemetryPacketInfo> taskList = new List<MeterReadingTelemetryPacketInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
var itemCode = T37612012PacketItemCodeConst.AFN09HFN09H;
|
|
|
|
|
|
|
|
|
|
|
|
//根据电表型号获取协议插件
|
|
|
|
|
|
var protocolPlugin = await _protocolService.GetProtocolServiceAsync(ammeterInfo.BrandType);
|
|
|
|
|
|
if (protocolPlugin == null)
|
2025-04-23 09:42:09 +08:00
|
|
|
|
{
|
2025-04-27 09:40:31 +08:00
|
|
|
|
_logger.LogError($"{nameof(ConcentratorScheduledAutomaticGetTelematicsModule)} 自动获取远程通信模块(SIM)版本信息{currentTime}没有找到对应的协议组件,-105");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-23 09:42:09 +08:00
|
|
|
|
}
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
ProtocolBuildResponse builderResponse = await protocolPlugin.BuildAsync(new ProtocolBuildRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
|
|
|
|
|
ItemCode = itemCode,
|
|
|
|
|
|
});
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
var meterReadingRecords = CreateAmmeterPacketInfo(
|
2025-05-13 14:51:38 +08:00
|
|
|
|
ammeterInfo: ammeterInfo,
|
|
|
|
|
|
timestamps: currentTime.GetDateTimeOffset().ToUnixTimeNanoseconds(),
|
|
|
|
|
|
builderResponse: builderResponse,
|
|
|
|
|
|
itemCode: itemCode,
|
|
|
|
|
|
subItemCode: null,
|
|
|
|
|
|
pendingCopyReadTime: currentTime,
|
|
|
|
|
|
creationTime: currentTime,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
packetType: TelemetryPacketTypeEnum.TelematicsModule,
|
|
|
|
|
|
_guidGenerator);
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
2025-04-23 09:42:09 +08:00
|
|
|
|
taskList.Add(meterReadingRecords);
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-04-27 09:40:31 +08:00
|
|
|
|
if (taskList == null || taskList.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledAutoValveControl)} 定时阀控运行时间{currentTime}没有自动阀控任务生成,-106");
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return null;
|
2025-04-27 09:40:31 +08:00
|
|
|
|
}
|
2025-04-21 22:57:49 +08:00
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
return taskList;
|
2025-04-27 09:40:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-05-20 16:41:58 +08:00
|
|
|
|
#endregion
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 公共处理方法
|
2025-04-14 21:56:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <summary>
|
2025-04-14 16:41:41 +08:00
|
|
|
|
/// 判断是否需要生成采集指令
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// </summary>
|
2025-04-14 16:41:41 +08:00
|
|
|
|
/// <param name="nextTaskTime"></param>
|
|
|
|
|
|
/// <param name="timeDensity"></param>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <returns></returns>
|
2025-04-23 16:17:29 +08:00
|
|
|
|
protected bool IsTaskTime(DateTime nextTaskTime, int timeDensity = 0)
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
2025-04-14 16:41:41 +08:00
|
|
|
|
if (DateTime.Now.AddMinutes(timeDensity) >= nextTaskTime)
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
2025-04-14 16:41:41 +08:00
|
|
|
|
return true;
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-14 16:41:41 +08:00
|
|
|
|
return false;
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-04-18 17:46:24 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 创建表的待发送的任务数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
2025-04-21 22:57:49 +08:00
|
|
|
|
/// <param name="nextTaskTime">采集频率对应的任务时间戳</param>
|
2025-04-18 17:46:24 +08:00
|
|
|
|
/// <param name="meterType">表类型</param>
|
|
|
|
|
|
/// <param name="taskCreateAction">具体的创建任务的委托</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-04-23 16:17:29 +08:00
|
|
|
|
protected async Task CreateMeterPublishTask<T>(int timeDensity, DateTime nextTaskTime, MeterTypeEnum meterType, Action<int, T, int, DateTime> taskCreateAction) where T : DeviceCacheBasicModel
|
2025-04-18 17:46:24 +08:00
|
|
|
|
{
|
|
|
|
|
|
var timer = Stopwatch.StartNew();
|
|
|
|
|
|
|
|
|
|
|
|
//获取对应频率中的所有电表信息
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//设备hash缓存key
|
2025-06-03 11:58:17 +08:00
|
|
|
|
string redisCacheDeviceCacheInfoHashKey = $"{string.Format(RedisConst.CacheDeviceInfoHashKey, SystemType, ServerTagName)}";
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//设备分组集合key
|
|
|
|
|
|
string redisCacheDeviceGroupSetIndexKey = $"{string.Format(RedisConst.CacheDeviceGroupSetIndexKey, SystemType, ServerTagName)}";
|
2025-04-30 15:57:14 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//List<T> meterInfos = new List<T>();
|
|
|
|
|
|
//decimal? cursor = null;
|
|
|
|
|
|
//string member = null;
|
2025-04-30 15:57:14 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//while (true)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// var page = await _redisDataCacheService.GetAllPagedData2<T>(
|
|
|
|
|
|
// redisCacheDeviceGroupSetIndexKey,
|
2025-06-03 11:58:17 +08:00
|
|
|
|
// redisCacheDeviceCacheInfoHashKey,
|
2025-05-13 14:51:38 +08:00
|
|
|
|
// pageSize: 1000,
|
|
|
|
|
|
// lastScore: cursor,
|
|
|
|
|
|
// lastMember: member);
|
|
|
|
|
|
|
|
|
|
|
|
// meterInfos.AddRange(page.Items);
|
|
|
|
|
|
// if (!page.HasNext)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// break;
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
// cursor = page.NextScore;
|
|
|
|
|
|
// member = page.NextMember;
|
|
|
|
|
|
//}
|
2025-04-23 09:42:09 +08:00
|
|
|
|
|
|
|
|
|
|
//var page = await _redisDataCacheService.GetAllPagedData<T>(
|
|
|
|
|
|
// redisCacheMeterInfoHashKeyTemp,
|
|
|
|
|
|
// redisCacheMeterInfoZSetScoresIndexKeyTemp,
|
|
|
|
|
|
// pageSize: 10,
|
|
|
|
|
|
// lastScore: cursor,
|
|
|
|
|
|
// lastMember: member);
|
|
|
|
|
|
//meterInfos.AddRange(page.Items);
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
//if (meterInfos == null || meterInfos.Count <= 0)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// timer.Stop();
|
|
|
|
|
|
// _logger.LogError($"{nameof(CreateMeterPublishTask)} {meterType}的{timeDensity}分钟采集待下发任务创建失败,没有获取到缓存信息,-105");
|
|
|
|
|
|
// return;
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
2025-06-03 11:58:17 +08:00
|
|
|
|
Dictionary<string, List<T>> keyValuePairs = FreeRedisProvider.Instance.HGetAll<List<T>>(redisCacheDeviceCacheInfoHashKey);
|
2025-05-15 23:59:10 +08:00
|
|
|
|
|
2025-04-30 15:57:14 +08:00
|
|
|
|
timer.Stop();
|
|
|
|
|
|
|
2025-04-30 12:36:54 +08:00
|
|
|
|
_logger.LogError($"{nameof(CreateMeterPublishTask)} 构建采集待下发任务,缓存获取信息共花费{timer.ElapsedMilliseconds}毫秒");
|
2025-04-18 17:46:24 +08:00
|
|
|
|
|
2025-05-13 14:51:38 +08:00
|
|
|
|
|
|
|
|
|
|
List<T> meterInfos = new List<T>();
|
|
|
|
|
|
foreach (var item in keyValuePairs)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var subItem in item.Value)
|
|
|
|
|
|
{
|
2025-05-15 23:59:10 +08:00
|
|
|
|
if (subItem.MeterType == meterType && subItem.TimeDensity == timeDensity)
|
2025-05-13 14:51:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
meterInfos.Add(subItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-30 15:57:14 +08:00
|
|
|
|
timer.Restart();
|
|
|
|
|
|
|
2025-04-18 17:46:24 +08:00
|
|
|
|
await DeviceGroupBalanceControl.ProcessWithThrottleAsync(
|
|
|
|
|
|
items: meterInfos,
|
2025-04-29 23:48:47 +08:00
|
|
|
|
deviceIdSelector: data => data.MeterId.ToString(),
|
2025-04-18 17:46:24 +08:00
|
|
|
|
processor: (data, groupIndex) =>
|
|
|
|
|
|
{
|
2025-04-21 22:57:49 +08:00
|
|
|
|
taskCreateAction(timeDensity, data, groupIndex, nextTaskTime);
|
2025-04-18 17:46:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
timer.Stop();
|
2025-04-29 23:48:47 +08:00
|
|
|
|
_logger.LogError($"{nameof(CreateMeterPublishTask)} {meterType} {timeDensity}分钟采集待下发任务创建完成,耗时{timer.ElapsedMilliseconds}毫秒,总共{meterInfos.Count}表计信息");
|
2025-04-18 17:46:24 +08:00
|
|
|
|
}
|
2025-06-03 11:58:17 +08:00
|
|
|
|
|
2025-04-27 17:27:04 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 构建报文保存对象
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="ammeterInfo">电表信息</param>
|
|
|
|
|
|
/// <param name="timestamps">IoTDB存储时标</param>
|
|
|
|
|
|
/// <param name="builderResponse">报文构建返回结果</param>
|
|
|
|
|
|
/// <param name="itemCode">端到云协议采集项编码</param>
|
|
|
|
|
|
/// <param name="subItemCode">端到端采集项编码</param>
|
|
|
|
|
|
/// <param name="pendingCopyReadTime">待采集时间,定时采集频率才是特殊情况,其他默认当前时间戳</param>
|
|
|
|
|
|
/// <param name="creationTime">数据创建时间戳</param>
|
2025-04-29 10:02:10 +08:00
|
|
|
|
/// <param name="packetType">数据包类型</param>
|
2025-05-14 14:40:34 +08:00
|
|
|
|
/// <param name="guidGenerator">Guid生成器</param>
|
2025-04-27 17:27:04 +08:00
|
|
|
|
/// <returns></returns>
|
2025-06-03 11:58:17 +08:00
|
|
|
|
protected MeterReadingTelemetryPacketInfo CreateAmmeterPacketInfo(DeviceCacheInfo ammeterInfo, long timestamps, ProtocolBuildResponse builderResponse, string itemCode, string subItemCode, DateTime pendingCopyReadTime, DateTime creationTime, TelemetryPacketTypeEnum packetType, IGuidGenerator guidGenerator)
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
2025-05-09 17:54:52 +08:00
|
|
|
|
try
|
2025-04-27 17:27:04 +08:00
|
|
|
|
{
|
2025-05-09 17:54:52 +08:00
|
|
|
|
string taskMark = CommonHelper.GetTaskMark(builderResponse.AFn, builderResponse.Fn, ammeterInfo.MeteringCode, builderResponse.MSA, builderResponse.Seq);
|
|
|
|
|
|
return new MeterReadingTelemetryPacketInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
SystemName = SystemType,
|
2025-06-03 23:01:46 +08:00
|
|
|
|
ProjectId = $"{ammeterInfo.ProjectId}",
|
2025-05-09 17:54:52 +08:00
|
|
|
|
DeviceType = $"{MeterTypeEnum.Ammeter}",
|
|
|
|
|
|
DeviceId = $"{ammeterInfo.MeterId}",
|
|
|
|
|
|
Timestamps = timestamps,
|
|
|
|
|
|
DatabaseBusiID = ammeterInfo.DatabaseBusiID,
|
|
|
|
|
|
PendingCopyReadTime = pendingCopyReadTime,
|
|
|
|
|
|
CreationTime = creationTime,
|
2025-05-13 14:51:38 +08:00
|
|
|
|
MeterAddress = ammeterInfo.MeterAddress,
|
2025-05-09 17:54:52 +08:00
|
|
|
|
PacketType = (int)packetType,
|
|
|
|
|
|
AFN = builderResponse.AFn,
|
|
|
|
|
|
Fn = builderResponse.Fn,
|
|
|
|
|
|
Seq = builderResponse.Seq,
|
|
|
|
|
|
MSA = builderResponse.MSA,
|
|
|
|
|
|
FocusId = ammeterInfo.FocusId,
|
|
|
|
|
|
FocusAddress = ammeterInfo.FocusAddress,
|
|
|
|
|
|
ItemCode = itemCode,
|
|
|
|
|
|
SubItemCode = subItemCode,
|
|
|
|
|
|
TaskMark = taskMark,
|
|
|
|
|
|
IsSend = false,
|
|
|
|
|
|
ManualOrNot = false,
|
|
|
|
|
|
Pn = ammeterInfo.MeteringCode,
|
2025-05-14 14:40:34 +08:00
|
|
|
|
IssuedMessageId = guidGenerator.Create().ToString(),
|
2025-05-09 17:54:52 +08:00
|
|
|
|
IssuedMessageHexString = Convert.ToHexString(builderResponse.Data),
|
2025-05-20 16:41:58 +08:00
|
|
|
|
FocusDensity = ammeterInfo.TimeDensity.GetFocusDensity(),
|
2025-05-09 17:54:52 +08:00
|
|
|
|
IsReceived = false,
|
|
|
|
|
|
ScoreValue = $"{ammeterInfo.FocusAddress}.{taskMark}".Md5Fun(),
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
2025-05-15 23:59:10 +08:00
|
|
|
|
{
|
2025-05-09 17:54:52 +08:00
|
|
|
|
throw ex;
|
|
|
|
|
|
}
|
2025-05-15 23:59:10 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
#endregion
|
2025-04-09 23:11:36 +08:00
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|