2025-04-09 23:11:36 +08:00
|
|
|
|
using DotNetCore.CAP;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Ammeters;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
using JiShe.CollectBus.Common.BuildSendDatas;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Consts;
|
|
|
|
|
|
using JiShe.CollectBus.Common.Enums;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Extensions;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Common.Helpers;
|
|
|
|
|
|
using JiShe.CollectBus.GatherItem;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
using JiShe.CollectBus.IoTDBProvider;
|
2025-03-17 14:23:48 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.MessageIssueds;
|
2025-03-18 22:43:24 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.MeterReadingRecords;
|
2025-03-14 14:38:08 +08:00
|
|
|
|
using JiShe.CollectBus.IotSystems.Watermeter;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using JiShe.CollectBus.Protocol.Contracts;
|
2025-03-20 16:40:27 +08:00
|
|
|
|
using JiShe.CollectBus.Repository.MeterReadingRecord;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
using Microsoft.Extensions.Logging;
|
2025-04-09 23:11:36 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Threading.Tasks;
|
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-04-09 23:11:36 +08:00
|
|
|
|
private readonly ICapPublisher _producerBus;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
private readonly IIoTDBProvider _dbProvider;
|
2025-04-09 23:11:36 +08:00
|
|
|
|
private readonly IMeterReadingRecordRepository _meterReadingRecordRepository;
|
2025-03-17 14:23:48 +08:00
|
|
|
|
|
|
|
|
|
|
public BasicScheduledMeterReadingService(
|
|
|
|
|
|
ILogger<BasicScheduledMeterReadingService> logger,
|
2025-04-08 17:44:42 +08:00
|
|
|
|
ICapPublisher producerBus,
|
|
|
|
|
|
IMeterReadingRecordRepository meterReadingRecordRepository,
|
|
|
|
|
|
IIoTDBProvider dbProvider)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-04-01 22:50:34 +08:00
|
|
|
|
_producerBus = producerBus;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
_logger = logger;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
_dbProvider = dbProvider;
|
|
|
|
|
|
_meterReadingRecordRepository = meterReadingRecordRepository;
|
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-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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in taskInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
var tasksToBeIssueModel = await FreeRedisProvider.Instance.GetAsync<TasksToBeIssueModel>(item);
|
|
|
|
|
|
if (tasksToBeIssueModel == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogWarning($"{nameof(CreateToBeIssueTasks)} 构建待处理的下发指令任务处理时Key=>{item}没有缓存数据,102");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//item 为 CacheTasksToBeIssuedKey 对应的缓存待下发的指令生产任务数据Redis Key tempArryay[0]=>CollectBus,tempArryay[1]=>SystemTypeConst,tempArryay[2]=>TaskInfo,tempArryay[3]=>表计类别,tempArryay[4]=>采集频率
|
|
|
|
|
|
var tempArryay = item.Split(":");
|
|
|
|
|
|
string meteryType = tempArryay[3];//表计类别
|
2025-03-20 16:40:27 +08:00
|
|
|
|
int timeDensity = Convert.ToInt32(tempArryay[4]);//采集频率
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
//获取缓存中的电表信息
|
2025-03-18 16:20:08 +08:00
|
|
|
|
var redisKeyList = $"{string.Format(RedisConst.CacheMeterInfoKey, SystemType, meteryType, timeDensity)}*";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
var oneMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (oneMinutekeyList == null || oneMinutekeyList.Length <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建失败,没有获取到缓存信息,-103");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (meteryType == MeterTypeEnum.Ammeter.ToString())
|
|
|
|
|
|
{
|
|
|
|
|
|
// 解析结果(结果为嵌套数组)
|
2025-03-20 16:40:27 +08:00
|
|
|
|
var meterInfos = await GetMeterRedisCacheData<AmmeterInfo>(oneMinutekeyList, $"{timeDensity}", meteryType);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterInfos == null || meterInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建失败,没有获取到缓存信息,-104");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
await AmmerterScheduledMeterReadingIssued(timeDensity, meterInfos);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (meteryType == MeterTypeEnum.WaterMeter.ToString())
|
|
|
|
|
|
{
|
|
|
|
|
|
//todo 水表任务创建待处理
|
|
|
|
|
|
//await WatermeterScheduledMeterReadingIssued(timeDensity, meterInfos);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建失败,没有获取到缓存信息,-105");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(CreateToBeIssueTasks)} {timeDensity}分钟采集待下发任务创建完成");
|
|
|
|
|
|
|
|
|
|
|
|
//删除已经处理过的缓存数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
#region 电表采集处理
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取电表信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual Task<List<AmmeterInfo>> GetAmmeterInfoList(string gatherCode = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NotImplementedException($"{nameof(GetAmmeterInfoList)}请根据不同系统类型进行实现");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化电表缓存数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task InitAmmeterCacheData(string gatherCode = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
var meterInfos = await GetAmmeterInfoList(gatherCode);
|
|
|
|
|
|
if (meterInfos == null || meterInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NullReferenceException($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,电表数据为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取采集项类型数据
|
|
|
|
|
|
var gatherItemInfos = await GetGatherItemByDataTypes();
|
|
|
|
|
|
if (gatherItemInfos == null || gatherItemInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new NullReferenceException($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据时,采集项类型数据为空");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
List<string> focusAddressDataList = new List<string>();//用于处理Kafka主题分区数据的分发和处理。
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
//根据采集频率分组,获得采集频率分组
|
|
|
|
|
|
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
|
|
|
|
|
foreach (var itemTimeDensity in meterInfoGroupByTimeDensity)
|
|
|
|
|
|
{
|
|
|
|
|
|
//将表计信息根据集中器分组,获得集中器号
|
|
|
|
|
|
var meterInfoGroup = itemTimeDensity.GroupBy(x => x.FocusAddress).ToList();
|
|
|
|
|
|
foreach (var item in meterInfoGroup)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(item.Key))//集中器号为空,跳过
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisCacheKey = $"{string.Format(RedisConst.CacheMeterInfoKey, SystemType, ServerTagName, MeterTypeEnum.Ammeter, itemTimeDensity.Key)}{item.Key}";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
#if DEBUG
|
2025-03-21 11:48:31 +08:00
|
|
|
|
//每次缓存时,删除缓存,避免缓存数据有不准确的问题
|
2025-03-18 22:43:24 +08:00
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(redisCacheKey);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
#else
|
2025-03-21 11:48:31 +08:00
|
|
|
|
//每次缓存时,删除缓存,避免缓存数据有不准确的问题
|
2025-03-18 15:58:37 +08:00
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(redisCacheKey);
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
Dictionary<string, AmmeterInfo> keyValuePairs = new Dictionary<string, AmmeterInfo>();
|
|
|
|
|
|
foreach (var ammeter in item)
|
|
|
|
|
|
{
|
|
|
|
|
|
//处理ItemCode
|
2025-03-27 08:38:19 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeter.ItemCodes) && !string.IsNullOrWhiteSpace(ammeter.DataTypes))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
var itemArr = ammeter.DataTypes.Split(',').ToList();
|
|
|
|
|
|
|
|
|
|
|
|
#region 拼接采集项
|
|
|
|
|
|
List<string> itemCodeList = new List<string>();
|
|
|
|
|
|
foreach (var dataType in itemArr)
|
|
|
|
|
|
{
|
2025-03-17 11:34:30 +08:00
|
|
|
|
var excludeItemCode = "10_98,10_94";//TODO 排除透明转发:尖峰平谷时段、跳合闸,特殊电表
|
2025-03-14 14:24:38 +08:00
|
|
|
|
var gatherItem = gatherItemInfos.FirstOrDefault(f => f.DataType.Equals(dataType));
|
|
|
|
|
|
if (gatherItem != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!excludeItemCode.Contains(gatherItem.ItemCode))
|
|
|
|
|
|
{
|
|
|
|
|
|
itemCodeList.Add(gatherItem.ItemCode);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-17 11:34:30 +08:00
|
|
|
|
#region 特殊电表采集项编号处理
|
|
|
|
|
|
if (itemArr.Exists(e => e.Equals("95"))) //德力西DTS
|
|
|
|
|
|
{
|
|
|
|
|
|
itemCodeList.Add("10_95");
|
|
|
|
|
|
}
|
|
|
|
|
|
if (itemArr.Exists(e => e.Equals("109")))//WAVE_109
|
|
|
|
|
|
{
|
|
|
|
|
|
itemCodeList.Add("10_109");
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-03-17 11:34:30 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
ammeter.ItemCodes = itemCodeList.Serialize();//转换成JSON字符串
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(ammeter.ItemCodes))
|
|
|
|
|
|
{
|
|
|
|
|
|
ammeter.ItemCodes = ammeter.ItemCodes.Replace("WAVE_109", "10_109");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
keyValuePairs.TryAdd($"{ammeter.ID}", ammeter);
|
|
|
|
|
|
}
|
2025-03-17 08:35:19 +08:00
|
|
|
|
await FreeRedisProvider.Instance.HSetAsync(redisCacheKey, keyValuePairs);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
//在缓存表信息数据的时候,新增下一个时间的自动处理任务,1分钟后执行所有的采集频率任务
|
2025-03-18 15:58:37 +08:00
|
|
|
|
TasksToBeIssueModel nextTask = new TasksToBeIssueModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
TimeDensity = itemTimeDensity.Key,
|
|
|
|
|
|
NextTask = DateTime.Now.AddMinutes(1)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var taskRedisCacheKey = string.Format(RedisConst.CacheTasksToBeIssuedKey, SystemType, ServerTagName, MeterTypeEnum.Ammeter, itemTimeDensity.Key);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(taskRedisCacheKey, nextTask);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(InitAmmeterCacheData)} 初始化电表缓存数据完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// 1分钟采集电表数据,只获取任务数据下发,不构建任务
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task AmmeterScheduledMeterOneMinuteReading()
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取缓存中的电表信息
|
2025-04-09 23:11:36 +08:00
|
|
|
|
int timeDensity = 1;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-17 08:35:19 +08:00
|
|
|
|
var oneMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
if (oneMinutekeyList == null || oneMinutekeyList.Length <= 0)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-101");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//获取下发任务缓存数据
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(oneMinutekeyList, timeDensity.ToString(), MeterTypeEnum.Ammeter.ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-102");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
|
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-04-07 21:34:05 +08:00
|
|
|
|
_ = _producerBus.PublishDelayAsync(TimeSpan.FromMicroseconds(500), ProtocolConst.AmmeterSubscriberWorkerOneMinuteIssuedEventName, tempMsg);
|
|
|
|
|
|
//_= _producerBus.Publish(tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-04-08 17:44:42 +08:00
|
|
|
|
//_dbProvider.SwitchSessionPool(true);
|
|
|
|
|
|
//await _dbProvider.InsertAsync(meterTaskInfosList);
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList, currentTime);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
//删除任务数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(oneMinutekeyList);
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理完成");
|
|
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// 5分钟采集电表数据
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
public virtual async Task AmmeterScheduledMeterFiveMinuteReading()
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
//获取缓存中的电表信息
|
2025-03-18 15:58:37 +08:00
|
|
|
|
int timeDensity = 5;
|
2025-04-08 17:44:42 +08:00
|
|
|
|
var currentTime = DateTime.Now;
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var fiveMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (fiveMinutekeyList == null || fiveMinutekeyList.Length <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-101");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//获取下发任务缓存数据
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(fiveMinutekeyList, timeDensity.ToString(), ((int)MeterTypeEnum.Ammeter).ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-102");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-17 11:34:30 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-04-09 23:11:36 +08:00
|
|
|
|
_ = _producerBus.PublishDelayAsync(TimeSpan.FromMicroseconds(500), ProtocolConst.AmmeterSubscriberWorkerFiveMinuteIssuedEventName, tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-04-07 21:34:05 +08:00
|
|
|
|
//_ = _producerBus.Publish(tempMsg);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList, currentTime);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
//删除任务数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(fiveMinutekeyList);
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//缓存下一个时间的任务
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(AmmeterScheduledMeterFiveMinuteReading)} {timeDensity}分钟采集电表数据处理完成");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// 15分钟采集电表数据
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
public virtual async Task AmmeterScheduledMeterFifteenMinuteReading()
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
Stopwatch stopwatch = new Stopwatch();
|
|
|
|
|
|
stopwatch.Start();
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//获取缓存中的电表信息
|
|
|
|
|
|
int timeDensity = 15;
|
2025-03-20 16:40:27 +08:00
|
|
|
|
var currentDateTime = DateTime.Now;
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var fifteenMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (fifteenMinutekeyList == null || fifteenMinutekeyList.Length <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-101");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//获取下发任务缓存数据
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(fifteenMinutekeyList, timeDensity.ToString(), MeterTypeEnum.Ammeter.ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集电表数据处理时没有获取到缓存信息,-102");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
|
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-03-24 20:54:31 +08:00
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
_ = _producerBus.PublishDelayAsync(TimeSpan.FromMicroseconds(500), ProtocolConst.AmmeterSubscriberWorkerFifteenMinuteIssuedEventName, tempMsg);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-04-07 21:34:05 +08:00
|
|
|
|
//_ = _producerBus.Publish(tempMsg);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList, currentDateTime);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//删除任务数据
|
2025-03-20 16:40:27 +08:00
|
|
|
|
//await FreeRedisProvider.Instance.DelAsync(fifteenMinutekeyList);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//缓存下一个时间的任务
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.Ammeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
stopwatch.Stop();
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterFifteenMinuteReading)} {timeDensity}分钟采集电表数据处理完成,共消耗{stopwatch.ElapsedMilliseconds}毫秒。");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 电表采集任务指令创建
|
|
|
|
|
|
/// </summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <param name="timeDensity">采集频率1分钟、5分钟、15分钟</param>
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <param name="focusGroup">集中器数据分组</param>
|
|
|
|
|
|
/// <returns></returns>
|
2025-03-20 16:40:27 +08:00
|
|
|
|
private async Task AmmerterScheduledMeterReadingIssued(int timeDensity, Dictionary<string, Dictionary<string, AmmeterInfo>> focusGroup)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-20 16:40:27 +08:00
|
|
|
|
if (timeDensity <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeDensity = 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (timeDensity > 15)
|
|
|
|
|
|
{
|
|
|
|
|
|
timeDensity = 15;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
if (focusGroup == null || focusGroup.Count <= 0)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmerterScheduledMeterReadingIssued)} 电表数据采集指令生成失败,参数异常,-101");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
//将采集器编号的hash值取模分组
|
2025-03-17 14:23:48 +08:00
|
|
|
|
const int TotalShards = 1024;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
var focusHashGroups = new Dictionary<int, Dictionary<string, Dictionary<string, AmmeterInfo>>>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var (collectorId, ammetersDictionary) in focusGroup)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(collectorId))
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmerterScheduledMeterReadingIssued)} 集中器信息分组取模失败,无效Key -102");
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算哈希分组ID
|
|
|
|
|
|
int hashGroupId = Math.Abs(collectorId.GetHashCode() % TotalShards);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取或创建分组(避免重复查找)
|
|
|
|
|
|
if (!focusHashGroups.TryGetValue(hashGroupId, out var group))
|
|
|
|
|
|
{
|
|
|
|
|
|
group = new Dictionary<string, Dictionary<string, AmmeterInfo>>();
|
|
|
|
|
|
focusHashGroups[hashGroupId] = group;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 将当前集中器数据加入分组
|
|
|
|
|
|
group[collectorId] = ammetersDictionary;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (focusHashGroups == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmerterScheduledMeterReadingIssued)} 集中器信息分组取模失败 -103");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//根据分组创建线程批处理集中器
|
|
|
|
|
|
foreach (var group in focusHashGroups)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
await AmmerterCreatePublishTask(timeDensity, group.Value);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
throw;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// 电表创建发布任务
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// </summary>
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="focusGroup">集中器号hash分组的集中器集合数据</param>
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <returns></returns>
|
2025-03-20 16:40:27 +08:00
|
|
|
|
private async Task AmmerterCreatePublishTask(int timeDensity
|
2025-03-18 15:58:37 +08:00
|
|
|
|
, Dictionary<string, Dictionary<string, AmmeterInfo>> focusGroup)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-20 16:40:27 +08:00
|
|
|
|
var handlerPacketBuilder = TelemetryPacketBuilder.AFNHandlersDictionary;
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
var currentTime = DateTime.Now;
|
2025-03-20 16:40:27 +08:00
|
|
|
|
var pendingCopyReadTime = currentTime.AddMinutes(timeDensity);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
foreach (var focusInfo in focusGroup)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//构建缓存任务key,依然 表计类型+采集频率+集中器地址,存hash类型
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisCacheKey = $"{string.Format(RedisConst.CacheTelemetryPacketInfoKey, SystemType, ServerTagName, MeterTypeEnum.Ammeter, timeDensity)}{focusInfo.Key}";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
foreach (var ammeterInfo in focusInfo.Value)
|
2025-03-14 17:28:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
var ammeter = ammeterInfo.Value;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeter.ItemCodes))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}数据采集指令生成失败,采集项为空,-101");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//载波的不处理
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (ammeter.MeteringPort == (int)MeterLinkProtocolEnum.Carrierwave)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}数据采集指令生成失败,载波不处理,-102");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (ammeter.State.Equals(2))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} {ammeter.Name} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}状态为禁用,不处理");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-17 11:34:30 +08:00
|
|
|
|
////排除1天未在线的集中器生成指令 或 排除集中器配置为自动上报的集中器
|
|
|
|
|
|
//if (!IsGennerateCmd(ammeter.LastTime, -1))
|
|
|
|
|
|
//{
|
|
|
|
|
|
// _logger.LogInformation($"{nameof(CreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name},采集时间:{ammeter.LastTime},已超过1天未在线,不生成指令");
|
|
|
|
|
|
// continue;
|
|
|
|
|
|
//}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeter.AreaCode))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 表ID:{ammeter.ID},集中器通信区号为空");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (string.IsNullOrWhiteSpace(ammeter.Address))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 表ID:{ammeter.ID},集中器通信地址为空");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (Convert.ToInt32(ammeter.Address) > 65535)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 表ID:{ammeter.ID},集中器通信地址无效,确保大于65535");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (ammeter.MeteringCode <= 0 || ammeter.MeteringCode > 2033)
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogError($"{nameof(AmmerterCreatePublishTask)} 表ID:{ammeter.ID},非有效测量点号({ammeter.MeteringCode})");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
List<string> tempCodes = ammeter.ItemCodes.Deserialize<List<string>>()!;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
|
|
|
|
|
//TODO:自动上报数据只主动采集1类数据。
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (ammeter.AutomaticReport.Equals(1))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
var tempSubCodes = new List<string>();
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (tempCodes.Contains("0C_49"))
|
|
|
|
|
|
{
|
|
|
|
|
|
tempSubCodes.Add("0C_49");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tempSubCodes.Contains("0C_149"))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-14 17:28:58 +08:00
|
|
|
|
tempSubCodes.Add("0C_149");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ammeter.ItemCodes.Contains("10_97"))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
2025-03-14 17:28:58 +08:00
|
|
|
|
tempSubCodes.Add("10_97");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (tempSubCodes == null || tempSubCodes.Count <= 0)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}自动上报数据主动采集1类数据时数据类型为空");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-03-14 17:28:58 +08:00
|
|
|
|
tempCodes = tempSubCodes;
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-17 11:34:30 +08:00
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, MeterReadingRecords> keyValuePairs = new Dictionary<string, MeterReadingRecords>();
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
foreach (var tempItem in tempCodes)
|
|
|
|
|
|
{
|
|
|
|
|
|
//排除已发送日冻结和月冻结采集项配置
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (DayFreezeCodes.Contains(tempItem))
|
2025-03-14 14:24:38 +08:00
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (MonthFreezeCodes.Contains(tempItem))
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
var itemCodeArr = tempItem.Split('_');
|
2025-03-18 15:58:37 +08:00
|
|
|
|
var aFNStr = itemCodeArr[0];
|
|
|
|
|
|
var aFN = (AFN)aFNStr.HexToDec();
|
2025-03-14 17:28:58 +08:00
|
|
|
|
var fn = int.Parse(itemCodeArr[1]);
|
|
|
|
|
|
byte[] dataInfos = null;
|
2025-03-17 11:34:30 +08:00
|
|
|
|
if (ammeter.AutomaticReport.Equals(1) && aFN == AFN.请求实时数据)
|
2025-03-14 17:28:58 +08:00
|
|
|
|
{
|
|
|
|
|
|
//实时数据
|
|
|
|
|
|
dataInfos = Build3761SendData.BuildAmmeterReadRealTimeDataSendCmd(ammeter.FocusAddress, ammeter.MeteringCode, (ATypeOfDataItems)fn);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
string methonCode = $"AFN{aFNStr}_Fn_Send";
|
2025-03-17 11:34:30 +08:00
|
|
|
|
//特殊表暂不处理
|
2025-03-20 16:40:27 +08:00
|
|
|
|
if (handlerPacketBuilder != null && handlerPacketBuilder.TryGetValue(methonCode
|
2025-03-18 15:58:37 +08:00
|
|
|
|
, out var handler))
|
2025-03-14 17:28:58 +08:00
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
dataInfos = handler(new TelemetryPacketRequest()
|
|
|
|
|
|
{
|
|
|
|
|
|
FocusAddress = ammeter.FocusAddress,
|
|
|
|
|
|
Fn = fn,
|
|
|
|
|
|
Pn = ammeter.MeteringCode
|
|
|
|
|
|
});
|
2025-03-14 17:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}采集项{tempItem}无效编码。");
|
2025-03-17 11:34:30 +08:00
|
|
|
|
continue;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//TODO:特殊表
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-14 17:28:58 +08:00
|
|
|
|
if (dataInfos == null || dataInfos.Length <= 0)
|
|
|
|
|
|
{
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogWarning($"{nameof(AmmerterCreatePublishTask)} 集中器{ammeter.FocusAddress}的电表{ammeter.Name}采集项{tempItem}未能正确获取报文。");
|
2025-03-14 17:28:58 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
var meterReadingRecords = new MeterReadingRecords()
|
2025-03-14 17:28:58 +08:00
|
|
|
|
{
|
2025-03-21 11:48:31 +08:00
|
|
|
|
ProjectID = ammeter.ProjectID,
|
|
|
|
|
|
DatabaseBusiID = ammeter.DatabaseBusiID,
|
2025-03-20 16:40:27 +08:00
|
|
|
|
PendingCopyReadTime = pendingCopyReadTime,
|
|
|
|
|
|
CreationTime = currentTime,
|
2025-03-18 22:43:24 +08:00
|
|
|
|
MeterAddress = ammeter.AmmerterAddress,
|
|
|
|
|
|
MeterId = ammeter.ID,
|
|
|
|
|
|
MeterType = MeterTypeEnum.Ammeter,
|
|
|
|
|
|
FocusAddress = ammeter.FocusAddress,
|
|
|
|
|
|
FocusID = ammeter.FocusID,
|
|
|
|
|
|
AFN = aFN,
|
|
|
|
|
|
Fn = fn,
|
2025-04-08 17:44:42 +08:00
|
|
|
|
ItemCode = tempItem,
|
|
|
|
|
|
ManualOrNot = false,
|
2025-03-18 22:43:24 +08:00
|
|
|
|
Pn = ammeter.MeteringCode,
|
|
|
|
|
|
IssuedMessageId = GuidGenerator.Create().ToString(),
|
2025-03-18 21:21:35 +08:00
|
|
|
|
IssuedMessageHexString = Convert.ToHexString(dataInfos),
|
2025-03-14 17:28:58 +08:00
|
|
|
|
};
|
2025-03-18 22:43:24 +08:00
|
|
|
|
meterReadingRecords.CreateDataId(GuidGenerator.Create());
|
2025-04-09 23:11:36 +08:00
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
keyValuePairs.TryAdd($"{ammeter.ID}_{tempItem}", meterReadingRecords);
|
2025-03-14 17:28:58 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
await FreeRedisProvider.Instance.HSetAsync(redisCacheKey, keyValuePairs);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 水表采集处理
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取水表信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="gatherCode">采集端Code</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual Task<List<WatermeterInfo>> GetWatermeterInfoList(string gatherCode = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
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-03-18 15:58:37 +08:00
|
|
|
|
//根据采集频率分组,获得采集频率分组
|
|
|
|
|
|
var meterInfoGroupByTimeDensity = meterInfos.GroupBy(d => d.TimeDensity);
|
|
|
|
|
|
foreach (var itemTimeDensity in meterInfoGroupByTimeDensity)
|
|
|
|
|
|
{
|
|
|
|
|
|
//将表计信息根据集中器分组,获得集中器号
|
|
|
|
|
|
var meterInfoGroup = itemTimeDensity.GroupBy(x => x.FocusAddress).ToList();
|
|
|
|
|
|
foreach (var item in meterInfoGroup)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrWhiteSpace(item.Key))
|
|
|
|
|
|
{
|
|
|
|
|
|
continue;
|
2025-03-14 17:28:58 +08:00
|
|
|
|
}
|
2025-03-14 14:24:38 +08:00
|
|
|
|
|
2025-03-18 16:20:08 +08:00
|
|
|
|
var redisCacheKey = $"{string.Format(RedisConst.CacheMeterInfoKey, SystemType, MeterTypeEnum.WaterMeter, itemTimeDensity.Key)}{item.Key}";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
Dictionary<string, WatermeterInfo> keyValuePairs = new Dictionary<string, WatermeterInfo>();
|
|
|
|
|
|
foreach (var subItem in item)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
keyValuePairs.TryAdd($"{subItem.ID}", subItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
await FreeRedisProvider.Instance.HSetAsync(redisCacheKey, keyValuePairs);
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
//在缓存表信息数据的时候,新增下一个时间的自动处理任务,1分钟后执行
|
|
|
|
|
|
TasksToBeIssueModel nextTask = new TasksToBeIssueModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
TimeDensity = itemTimeDensity.Key,
|
|
|
|
|
|
NextTask = DateTime.Now.AddMinutes(1)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-18 16:20:08 +08:00
|
|
|
|
var taskRedisCacheKey = string.Format(RedisConst.CacheTasksToBeIssuedKey, SystemType, MeterTypeEnum.WaterMeter, itemTimeDensity.Key);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(taskRedisCacheKey, nextTask);
|
2025-03-17 11:34:30 +08:00
|
|
|
|
}
|
2025-03-18 15:58:37 +08:00
|
|
|
|
_logger.LogInformation($"{nameof(InitAmmeterCacheData)} 初始化水表缓存数据完成");
|
2025-03-14 14:24:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 1分钟采集水表数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task WatermeterScheduledMeterOneMinuteReading()
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取缓存中的水表信息
|
2025-04-09 23:11:36 +08:00
|
|
|
|
int timeDensity = 1;
|
|
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
var oneMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (oneMinutekeyList == null || oneMinutekeyList.Length <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(WatermeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-101");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取下发任务缓存数据
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(oneMinutekeyList, timeDensity.ToString(), ((int)MeterTypeEnum.WaterMeter).ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(WatermeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-102");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
|
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-04-07 21:34:05 +08:00
|
|
|
|
await _producerBus.PublishAsync(ProtocolConst.AmmeterSubscriberWorkerOneMinuteIssuedEventName, tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-04-07 21:34:05 +08:00
|
|
|
|
//_ = _producerBus.Publish(tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
|
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
//删除任务数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(oneMinutekeyList);
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//缓存下一个时间的任务
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(WatermeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 5分钟采集水表数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task WatermeterScheduledMeterFiveMinuteReading()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
//获取缓存中的电表信息
|
|
|
|
|
|
int timeDensity = 5;
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var fiveMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (fiveMinutekeyList == null || fiveMinutekeyList.Length <= 0)
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-101");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取下发任务缓存数据
|
2025-03-19 14:31:04 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(fiveMinutekeyList, timeDensity.ToString(), ((int)MeterTypeEnum.WaterMeter).ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-102");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
|
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-04-07 21:34:05 +08:00
|
|
|
|
await _producerBus.PublishAsync(ProtocolConst.AmmeterSubscriberWorkerOneMinuteIssuedEventName, tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-04-07 21:34:05 +08:00
|
|
|
|
//_ = _producerBus.Publish(tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
|
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
//删除任务数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(fiveMinutekeyList);
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//缓存下一个时间的任务
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(WatermeterScheduledMeterFiveMinuteReading)} {timeDensity}分钟采集水表数据处理完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 15分钟采集水表数据
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public virtual async Task WatermeterScheduledMeterFifteenMinuteReading()
|
|
|
|
|
|
{
|
|
|
|
|
|
//获取缓存中的电表信息
|
|
|
|
|
|
int timeDensity = 15;
|
2025-04-09 23:11:36 +08:00
|
|
|
|
var redisKeyList = GetTelemetryPacketCacheKeyPrefix(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var fifteenMinutekeyList = await FreeRedisProvider.Instance.KeysAsync(redisKeyList);
|
|
|
|
|
|
if (fifteenMinutekeyList == null || fifteenMinutekeyList.Length <= 0)
|
2025-03-18 15:58:37 +08:00
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-101");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//获取下发任务缓存数据
|
2025-04-09 23:11:36 +08:00
|
|
|
|
Dictionary<string, Dictionary<string, MeterReadingRecords>> meterTaskInfos = await GetMeterRedisCacheData<MeterReadingRecords>(fifteenMinutekeyList, timeDensity.ToString(), MeterTypeEnum.WaterMeter.ToString());
|
2025-03-18 15:58:37 +08:00
|
|
|
|
if (meterTaskInfos == null || meterTaskInfos.Count <= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(AmmeterScheduledMeterOneMinuteReading)} {timeDensity}分钟采集水表数据处理时没有获取到缓存信息,-102");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-19 14:31:04 +08:00
|
|
|
|
List<MeterReadingRecords> meterTaskInfosList = new List<MeterReadingRecords>();
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
//将取出的缓存任务数据发送到Kafka消息队列中
|
|
|
|
|
|
foreach (var focusItem in meterTaskInfos)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var ammerterItem in focusItem.Value)
|
|
|
|
|
|
{
|
2025-03-18 22:43:24 +08:00
|
|
|
|
var tempMsg = new ScheduledMeterReadingIssuedEventMessage()
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageHexString = ammerterItem.Value.IssuedMessageHexString,
|
|
|
|
|
|
MessageId = ammerterItem.Value.IssuedMessageId,
|
|
|
|
|
|
FocusAddress = ammerterItem.Value.FocusAddress,
|
|
|
|
|
|
TimeDensity = timeDensity.ToString(),
|
|
|
|
|
|
};
|
2025-04-01 22:50:34 +08:00
|
|
|
|
//await _producerBus.PublishAsync(ProtocolConst.AmmeterSubscriberWorkerOneMinuteIssuedEventName, tempMsg);
|
|
|
|
|
|
|
2025-04-07 21:34:05 +08:00
|
|
|
|
//_ = _producerBus.Publish(tempMsg);
|
2025-04-01 22:50:34 +08:00
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
meterTaskInfosList.Add(ammerterItem.Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (meterTaskInfosList != null && meterTaskInfosList.Count > 0)
|
|
|
|
|
|
{
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await _meterReadingRecordRepository.InsertManyAsync(meterTaskInfosList);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-18 22:43:24 +08:00
|
|
|
|
//删除任务数据
|
|
|
|
|
|
await FreeRedisProvider.Instance.DelAsync(fifteenMinutekeyList);
|
|
|
|
|
|
|
2025-03-18 15:58:37 +08:00
|
|
|
|
//缓存下一个时间的任务
|
2025-04-09 23:11:36 +08:00
|
|
|
|
await CacheNextTaskData(timeDensity, MeterTypeEnum.WaterMeter);
|
2025-03-18 15:58:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_logger.LogInformation($"{nameof(WatermeterScheduledMeterFiveMinuteReading)} {timeDensity}分钟采集水表数据处理完成");
|
|
|
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region 公共处理方法
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 批量获取缓存的表计信息
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <typeparam name="T">表信息数据对象</typeparam>
|
|
|
|
|
|
/// <param name="redisKeys">采集频率对应的缓存Key集合</param>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率,1分钟、5分钟、15分钟</param>
|
|
|
|
|
|
/// <param name="meterType">表计类型</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private async Task<Dictionary<string, Dictionary<string, T>>> GetMeterRedisCacheData<T>(string[] redisKeys, string timeDensity, string meterType) where T : class
|
|
|
|
|
|
{
|
|
|
|
|
|
//通过lua脚本一次性获取所有缓存内容
|
|
|
|
|
|
var luaScript = @"
|
|
|
|
|
|
local results = {}
|
|
|
|
|
|
for i, key in ipairs(KEYS) do
|
|
|
|
|
|
local data = redis.call('HGETALL', key)
|
|
|
|
|
|
results[i] = {key, data}
|
|
|
|
|
|
end
|
|
|
|
|
|
return results";
|
|
|
|
|
|
var merterResult = await FreeRedisProvider.Instance.EvalAsync(luaScript, redisKeys); //传递 KEYS
|
|
|
|
|
|
if (merterResult == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogError($"{nameof(GetMeterRedisCacheData)} 定时任务采集表数据处理时没有获取到缓存信息,-102");
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 解析结果(结果为嵌套数组)
|
|
|
|
|
|
var meterInfos = new Dictionary<string, Dictionary<string, T>>(); ;
|
|
|
|
|
|
if (merterResult is object[] arr)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (object[] item in arr)
|
|
|
|
|
|
{
|
|
|
|
|
|
string key = (string)item[0];//集中器地址对应的Redis缓存Key
|
|
|
|
|
|
object[] fieldsAndValues = (object[])item[1];//缓存Key对应的Hash表数据集合
|
2025-03-18 16:20:08 +08:00
|
|
|
|
var redisCacheKey = $"{string.Format(RedisConst.CacheMeterInfoKey, SystemType, meterType, timeDensity)}";
|
2025-03-18 15:58:37 +08:00
|
|
|
|
string focusAddress = key.Replace(redisCacheKey, "");//集中器地址
|
|
|
|
|
|
|
|
|
|
|
|
var meterHashs = new Dictionary<string, T>();
|
|
|
|
|
|
for (int i = 0; i < fieldsAndValues.Length; i += 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
string meterld = (string)fieldsAndValues[i];//表ID
|
|
|
|
|
|
string meterStr = (string)fieldsAndValues[i + 1];//表详情数据
|
|
|
|
|
|
|
|
|
|
|
|
T meterInfo = default!;
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(meterStr))
|
|
|
|
|
|
{
|
|
|
|
|
|
meterInfo = meterStr.Deserialize<T>()!;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (meterInfo != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
meterHashs[meterld] = meterInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
_logger.LogInformation($"{nameof(GetMeterRedisCacheData)} 定时任务采集表数据处理时集中器缓存{key}数据的{meterld}处理异常");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
meterInfos[focusAddress] = meterHashs;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return meterInfos;
|
|
|
|
|
|
}
|
2025-03-18 22:43:24 +08:00
|
|
|
|
|
2025-03-14 14:24:38 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 指定时间对比当前时间
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="lastTime"></param>
|
|
|
|
|
|
/// <param name="subtrahend"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private bool IsGennerateCmd(DateTime lastTime, int subtrahend = 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (DateTime.Now.AddDays(subtrahend) >= lastTime)//当前时间减去一天,大于等于最后在线时间,不再生成该集中器下表生成采集指令
|
|
|
|
|
|
return false;
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-04-09 23:11:36 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 缓存下一个时间的任务
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity">采集频率</param>
|
|
|
|
|
|
/// <param name="meterType">表类型</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private async Task CacheNextTaskData(int timeDensity, MeterTypeEnum meterType)
|
|
|
|
|
|
{
|
|
|
|
|
|
//缓存下一个时间的任务
|
|
|
|
|
|
TasksToBeIssueModel nextTask = new TasksToBeIssueModel()
|
|
|
|
|
|
{
|
|
|
|
|
|
TimeDensity = timeDensity,
|
|
|
|
|
|
NextTask = DateTime.Now.AddMinutes(timeDensity)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var redisCacheKey = string.Format(RedisConst.CacheTasksToBeIssuedKey, SystemType, ServerTagName, meterType, timeDensity);
|
|
|
|
|
|
await FreeRedisProvider.Instance.SetAsync(redisCacheKey, nextTask);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取缓存表计下发指令缓存key前缀
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="timeDensity"></param>
|
|
|
|
|
|
/// <param name="meterType"></param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
private string GetTelemetryPacketCacheKeyPrefix(int timeDensity, MeterTypeEnum meterType)
|
|
|
|
|
|
{
|
|
|
|
|
|
return $"{string.Format(RedisConst.CacheTelemetryPacketInfoKey, SystemType, ServerTagName, meterType, timeDensity)}*";
|
|
|
|
|
|
}
|
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
|
|
|
|
}
|
|
|
|
|
|
}
|