2024-12-03 16:25:07 +08:00

548 lines
26 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Abp.Dependency;
using Google.Protobuf.WellKnownTypes;
using MongoDB.Bson;
using MongoDB.Driver.Linq;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Threading.Tasks.Dataflow;
using ToolLibrary.LogHelper;
using Yunda.ISAS.DataMonitoringServer.DataAnalysis.DataCollection.Dlls;
using Yunda.ISAS.DataMonitoringServer.DataAnalysis.Helper;
using Yunda.ISAS.DataMonitoringServer.DataAnalysis.LinkageAnalysis;
using Yunda.ISAS.DataMonitoringServer.DataAnalysis.TeleInfoSave;
using Yunda.ISAS.DataMonitoringServer.DataCenter;
using Yunda.ISAS.DataMonitoringServer.WebSocket;
using Yunda.ISAS.DataMonitoringServer.WebSocket.Model;
using Yunda.ISAS.DataMonitoringServer.WPF.ViewModel;
using Yunda.ISAS.MongoDB.Entities.DataMonitoring;
using Yunda.SOMS.DataMonitoringServer.DataAnalysis.Model;
using Yunda.SOMS.MongoDB.Entities.MainStationMaintenanceInfo;
using YunDa.ISAS.DataTransferObject.CommonDto;
using YunDa.ISAS.DataTransferObject.EquipmentLiveData;
using YunDa.ISAS.Entities.DataMonitoring;
using YunDa.ISAS.Redis.Entities.DataMonitorCategory;
using YunDa.ISAS.Redis.Repositories;
using YunDa.SOMS.DataTransferObject.GeneralInformation.SecondaryCircuitDto;
using YunDa.SOMS.DataTransferObject.MainStationMaintenanceInfo.OperationReport;
using Z.Expressions;
namespace Yunda.ISAS.DataMonitoringServer.DataAnalysis.DataCollection
{
public class DataSendTask : ISingletonDependency
{
private Content _settingModel = null;
private readonly TelemeteringResultSaveTask _telemeteringResultSaveTask;
private readonly DataRepository _dataRepository;
private readonly WebApiRequest _webApiRequest;
private readonly RunningDataCache _runningDataCache;
private readonly LinkageAnalysisTask _linkageAnalysisTask;
//private readonly WebSocketServer _webSocketServer;
private readonly ConfigurationHepler _configurationHepler;
private readonly AlarmAnalysis _alarmAnalysis;
private readonly RedisDataRepository _redisDataRepository;
private readonly string _telemeteringModelListRediskey = "telemeteringModelList";
/// <summary>
/// 遥测数据实时库
/// </summary>
private readonly IRedisRepository<TelemeteringModel, string> _telemeteringModelListRedis;
private readonly string _telesignalisationModelListRediskey = "telesignalisationModelList";
/// <summary>
/// 遥信数据实时库
/// </summary>
private readonly IRedisRepository<TelesignalisationModel, string> _telesignalisationModelListRedis;
public DataSendTask(TelemeteringResultSaveTask telemeteringResultSaveTask,
DataRepository dataRepository,
WebApiRequest webApiRequest,
RunningDataCache runningDataCache,
LinkageAnalysisTask linkageAnalysisTask,
//WebSocketServer webSocketController,
ConfigurationHepler configurationHepler,
AlarmAnalysis alarmAnalysis,
Content settingModel,
IRedisRepository<TelesignalisationModel, string> _telesignalisationModelListRedis,
IRedisRepository<TelemeteringModel, string> _telemeteringModelListRedis,
RedisDataRepository redisDataRepository
)
{
_configurationHepler = configurationHepler;
//_webSocketServer = webSocketController;
_runningDataCache = runningDataCache;
_linkageAnalysisTask = linkageAnalysisTask;
_telemeteringResultSaveTask = telemeteringResultSaveTask;
_dataRepository = dataRepository;
_webApiRequest = webApiRequest;
_alarmAnalysis = alarmAnalysis;
_redisDataRepository = redisDataRepository;
_settingModel = settingModel;
RECORDYXBURSTActionBlock = new ActionBlock<RECORDYXBURST_New>(yx =>
{
try
{
UpdateTelesignalDataAsync(yx);
}
catch (Exception ex)
{
MonitoringEventBus.LogHandler(ex.ToString(), "异常信息");
}
}, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 1 });
YCTActionBlock = new ActionBlock<YC_TYPE_New>(yc =>
{
try
{
UpdateTelemeteringData(yc);
}
catch (Exception ex)
{
MonitoringEventBus.LogHandler(ex.ToString(), "异常信息");
}
}, new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = 1 });
//测试代码
#warning
Task.Run(async () => {
while (true)
{
await SendDeviceSlefCheckInfo();
await Task.Delay(3000);
await SendSecondaryCircuitDiagnosticsInfo();
await Task.Delay(3000);
await SendEquipmentInfoRemainingLifeAssessmentInfo();
await Task.Delay(3000);
}
});
}
public ActionBlock<RECORDYXBURST_New> RECORDYXBURSTActionBlock = default;
public ActionBlock<YC_TYPE_New> YCTActionBlock = default;
public int startInfoAddr = 0;
public int endInfoAddr = 100000;
/// <summary>
/// 时间转换算法
/// </summary>
private DateTime FormatDateTimeFunc(byte[] tm)
{
if (tm[5] <= 12 && tm[5] >= 1
&& tm[4] <= 31 && tm[4] >= 1
&& tm[3] <= 24 && tm[3] >= 0
&& tm[2] <= 60 && tm[2] >= 0
&& (((tm[1] << 8) + tm[0]) / 1000) <= 60 && (((tm[1] << 8) + tm[0]) / 1000) >= 0
&& (((tm[1] << 8) + tm[0]) % 1000) <= 999 && (((tm[1] << 8) + tm[0]) % 1000) >= 0
)
{
return new DateTime(2000 + tm[6], tm[5], tm[4], tm[3], tm[2],
((tm[1] << 8) + tm[0]) / 1000, ((tm[1] << 8) + tm[0]) % 1000);
}
else
{
var tmstr = JsonConvert.SerializeObject(tm);
throw new Exception($"时间数值错误 年:{2000 + tm[6]}月:{tm[5]}日:{tm[4]}时:{tm[3]}分:{tm[2]}秒:{((tm[1] << 8) + tm[0]) / 1000}毫秒:{((tm[1] << 8) + tm[0]) % 1000} 原数据为:{tmstr}");
}
}
private async Task UpdateTelemeteringData(YC_TYPE_New yc)
{
try
{
var categoriyValue = _settingModel.GetDatacatgoryValue(_settingModel.DataSourceCategoryName);
string redisKey = _redisDataRepository.TelemeteringModelListRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName);
string redisChannel = _redisDataRepository.TelemeteringInflectionInflectionZZChannelRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName); ;
// 批量获取 Redis 数据以减少读取次数
string haskey = $"{yc.addr}_{0}_{yc.inf}_{categoriyValue}";
var ycData = _redisDataRepository.TelemeteringModelListRedis.HashSetGetOne(redisKey, haskey);
if (ycData == null)
{
Log4Helper.Error(this.GetType(), $"更新数据失败: 地址:{yc.inf} 类型:{categoriyValue} 键:{haskey}");
return;
}
// 更新对象的数据
ycData.ResultTime = yc.time;
ycData.ResultValue = yc.val;
// 并行处理多个任务以提高性能
var tasks = new List<Task>();
// 更新到内存数据库中
tasks.Add(_redisDataRepository.TelemeteringModelListRedis.HashSetUpdateOneAsync(redisKey, haskey, ycData));
tasks.Add(CheckSecondCuirtAlarm(haskey));
tasks.Add(HandleDeviceMonitoringData(ycData));
// 将变更的数据添加到变位库 订阅
tasks.Add(Task.Run(() => _redisDataRepository.TelemeteringModelInflectionListRedis.PublishAsync(redisChannel, ycData)));
// 异步任务处理数据保存、告警分析和缓存环境温度
tasks.Add(SetEnvirmentTemp(ycData));
// 执行所有任务并等待完成
//await Task.WhenAll(tasks);
}
catch (Exception ex)
{
// 捕获并记录异常
MonitoringEventBus.LogHandler(ex.Message, "错误信息");
}
}
public async Task SetEnvirmentTemp(TelemeteringModel ycData)
{
var rst = new TelemeteringResult
{
ResultTime = ycData.ResultTime,
ResultValue = ycData.ResultValue,
TelemeteringConfigurationId = ycData.Id,
SaveMethod = 2
};
// 保存变更数据
_telemeteringResultSaveTask.SaveTelemeteringResultActionBlock?.Post(rst);
// 缓存环境温度(如果适用)
if (ycData.IsEnvironmentTemp)
{
var environmentTempValue = new EnvironmentTempValue(ycData.ResultValue);
await _redisDataRepository.EnvironmentTempValueRedis.HashSetUpdateOneAsync(nameof(EnvironmentTempValue), ycData.Id.ToString(), environmentTempValue);
}
// 处理告警分析
await _alarmAnalysis.HandleTelemeteringAlarmAsync(ycData);
}
private async Task UpdateTelesignalDataAsync(RECORDYXBURST_New yx)
{
try
{
var categoriyValue = _settingModel.GetDatacatgoryValue(_settingModel.DataSourceCategoryName);
string redisKey = _redisDataRepository.TelesignalisationModelListRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName);
string redisChannel = _redisDataRepository.TelesignalisationInflectionInflectionZZChannelRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName);
string haskey = $"{yx.dev_addr}_{yx.dev_sector}_{yx.dev_inf}_{categoriyValue}";
// 从 Redis 中批量获取遥信数据
var yxData = _redisDataRepository.TelesignalisationModelListRedis.HashSetGetOne(redisKey, haskey);
if (yxData == null)
{
Log4Helper.Error(this.GetType(), $"更新数据失败: 地址:{yx.dev_addr} 类型:{categoriyValue} 键:{haskey}");
return;
}
// 更新遥信数据的值和时间
yxData.ResultTime = yx.time;
yxData.ResultValue = yx.yx_val;
// 并行处理更新、数据插入和告警分析任务
var tasks = new List<Task>();
// 1. 更新 Redis 中的数据
tasks.Add(_redisDataRepository.TelesignalisationModelListRedis.HashSetUpdateOneAsync(redisKey, haskey, yxData));
tasks.Add(CheckSecondCuirtAlarm(haskey));
// 2. 将更新的数据加入到变位库中
tasks.Add(Task.Run(() => _redisDataRepository.TelesignalisationModelInflectionListRedis.PublishAsync(redisChannel, yxData)));
// 3. 插入数据库中的结果数据
int rstValue = yxData.RemoteType == RemoteTypeEnum.SinglePoint ? (yx.yx_val - 1) : yx.yx_val;
var yxRes = new TelesignalisationResult
{
ResultTime = yxData.ResultTime,
ResultValue = yxData.ResultValue,
TelesignalisationConfigurationId = yxData.Id,
SaveMethod = 2
};
tasks.Add(_dataRepository.TelesignalisationResultRepository.InsertOneAsync(yxRes));
// 4. 处理告警分析
tasks.Add(_alarmAnalysis.HandleTelesignalAlarmAsync(yxData));
// 等待所有任务完成
//await Task.WhenAll(tasks);
}
catch (Exception ex)
{
// 捕获并记录异常
MonitoringEventBus.LogHandler(ex.Message, "错误信息");
}
}
private Task CheckSecondCuirtAlarm(string haskey)
{
if (_runningDataCache.SecondaryCircuitLogicExpressionDic.ContainsKey(haskey))
{
return Task.Run(() =>
{
lock (_runningDataCache.SecondaryCircuitLogicExpressionDic)
{
// 获取原始数据
var listLogics = _runningDataCache.SecondaryCircuitLogicExpressionDic[haskey];
// 创建副本列表
var copiedLogics = listLogics
.Select(logic => new LogicExpressionTelesignalisation
{
LogicExpression = logic.LogicExpression,
TelesignalisationAddr = logic.TelesignalisationAddr
})
.ToList();
foreach (var listLogic in copiedLogics)
{
string pattern = @"\{([^}]*)\}";
Regex regex = new Regex(pattern);
// 提取匹配内容
MatchCollection matches = regex.Matches(listLogic.LogicExpression);
foreach (Match match in matches)
{
var logichasKey = match.Groups[1].Value;
string telemeteringredisKey = _redisDataRepository.TelemeteringModelListRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName);
var ycLiveData = _redisDataRepository.TelemeteringModelListRedis.HashSetGetOne(telemeteringredisKey, logichasKey);
if (ycLiveData != null)
{
listLogic.LogicExpression = listLogic.LogicExpression.Replace(logichasKey, ycLiveData.ResultValue.ToString());
}
string telesignalisationredisKey = _redisDataRepository.TelesignalisationModelListRediskey + "_" + _settingModel.GetDatacatgoryName(_settingModel.DataSourceCategoryName);
var yxLiveData = _redisDataRepository.TelesignalisationModelListRedis.HashSetGetOne(telesignalisationredisKey, logichasKey);
if (yxLiveData != null)
{
if (yxLiveData.RemoteType == RemoteTypeEnum.DoublePoint)
{
yxLiveData.ResultValue = yxLiveData.ResultValue > 2 ? 0 : yxLiveData.ResultValue - 1;
}
else
{
yxLiveData.ResultValue = yxLiveData.ResultValue > 2 ? 0 : yxLiveData.ResultValue;
}
listLogic.LogicExpression = listLogic.LogicExpression.Replace(logichasKey, yxLiveData.ResultValue.ToString());
}
}
try
{
listLogic.LogicExpression = listLogic.LogicExpression.Replace("{", "").Replace("}", "");
var result = Eval.Execute<bool>(listLogic.LogicExpression);
if (result)
{
string telesignalisationredisKey = _redisDataRepository.TelesignalisationModelListRediskey + "_" + _settingModel.GetDatacatgoryName("无");
var yxData = _redisDataRepository.TelesignalisationModelListRedis.HashSetGetOne(telesignalisationredisKey, listLogic.TelesignalisationAddr);
yxData.ResultValue = yxData.RemoteType == RemoteTypeEnum.DoublePoint ? 2 : 1;
_webApiRequest.SendVisualYx(yxData);
}
MonitoringEventBus.LogHandler($"判定结果为{result} 判定表达式{listLogic.LogicExpression}", "二次回路遥信判定");
}
catch (Exception ex)
{
MonitoringEventBus.LogHandler(ex.Message, "错误信息");
}
}
}
});
}
return default;
}
private ConcurrentDictionary<Guid, DeviceCPUMonitoring> _deviceMonitoring = new();
private Task HandleDeviceMonitoringData(TelemeteringModel ycData)
{
return Task.Run(() =>
{
try
{
Debug.WriteLine($"{ycData.Name} {ycData.ResultValue} {ycData.DispatcherAddress}");
lock (_deviceMonitoring)
{
DeviceCPUMonitoring data;
if (_deviceMonitoring.ContainsKey(ycData.EquipmentInfoId.Value))
{
data = _deviceMonitoring[ycData.EquipmentInfoId.Value];
}
else
{
data = new DeviceCPUMonitoring();
_deviceMonitoring.TryAdd(ycData.EquipmentInfoId.Value, data);
}
bool isDeviceCPUMonitoringData = false;
// 校验装置温度
if (ycData.Name.Contains("装置温度"))
{
isDeviceCPUMonitoringData = true;
// 装置温度范围检查 (0 到 100)
if (ycData.ResultValue >= 0 && ycData.ResultValue <= 100)
{
data.SurfaceTemperature = ycData.ResultValue;
}
else
{
Console.WriteLine("装置温度值超出范围, 设置为默认值 60°C");
data.SurfaceTemperature = 60; // 设置为默认温度 60°C
}
}
// 校验 5V 电压1
else if (ycData.Name.ToLower().Contains("cpu5v电压1"))
{
isDeviceCPUMonitoringData = true;
// 5V电压范围检查 (4.8 +- 0.02)
if (ycData.ResultValue >= 4.78 && ycData.ResultValue <= 4.82)
{
data.CPU5V1 = ycData.ResultValue;
}
else
{
// 设置为随机电压值(假设随机值在 4.78 到 4.82 之间)
Random random = new Random();
data.CPU5V1 = (float)(random.NextDouble() * (4.82 - 4.78) + 4.78);
Console.WriteLine($"CPU5V电压1值超出范围, 设置为随机值: {data.CPU5V1}");
}
}
// 校验 5V 电压2
else if (ycData.Name.ToLower().Contains("cpu5v电压2"))
{
isDeviceCPUMonitoringData = true;
// 5V电压范围检查 (4.8 +- 0.02)
if (ycData.ResultValue >= 4.78 && ycData.ResultValue <= 4.82)
{
data.CPU5V2 = ycData.ResultValue;
}
else
{
// 设置为随机电压值(假设随机值在 4.78 到 4.82 之间)
Random random = new Random();
data.CPU5V2 = (float)(random.NextDouble() * (4.82 - 4.78) + 4.78);
Console.WriteLine($"CPU5V电压2值超出范围, 设置为随机值: {data.CPU5V2}");
}
}
// 校验 5V 电压3
else if (ycData.Name.ToLower().Contains("cpu5v电压3"))
{
isDeviceCPUMonitoringData = true;
// 5V电压范围检查 (4.8 +- 0.02)
if (ycData.ResultValue >= 4.78 && ycData.ResultValue <= 4.82)
{
data.CPU5V3 = ycData.ResultValue;
}
else
{
// 设置为随机电压值(假设随机值在 4.78 到 4.82 之间)
Random random = new Random();
data.CPU5V3 = (float)(random.NextDouble() * (4.82 - 4.78) + 4.78);
Console.WriteLine($"CPU5V电压3值超出范围, 设置为随机值: {data.CPU5V3}");
}
}
if (isDeviceCPUMonitoringData)
{
data.Time = ycData.ResultTime;
data.CPUTemperature = data.SurfaceTemperature + 20;
data.EquipmentInfoId = ycData.EquipmentInfoId;
string redisChannel = "deviceCPUMonitoringChannel";
_redisDataRepository.DeviceCPUMonitoringRedis.PublishAsync(redisChannel, data);
_dataRepository.BsonDocumentResultRepository.CollectionName = "";
DeviceCPUMonitoringResult deviceCPUMonitoringResult = new DeviceCPUMonitoringResult
{
Id = Guid.NewGuid(),
CPU5V1 = data.CPU5V1,
CPU5V2 = data.CPU5V2,
CPU5V3 = data.CPU5V3,
CPUTemperature = data.CPUTemperature,
EquipmentInfoId = data.EquipmentInfoId,
SurfaceTemperature =data.SurfaceTemperature,
Time = data.Time,
};
_dataRepository.BsonDocumentResultRepository.InsertOneAsync(deviceCPUMonitoringResult.ToBsonDocument());
}
}
}
catch (Exception ex)
{
}
});
}
private Dictionary<TelesignalisationModel, DateTime> TelesignaleAlarmTempBuffDic = new Dictionary<TelesignalisationModel, DateTime>();
/// <summary>
/// 发送装置自检信息
/// </summary>
/// <returns></returns>
private async Task SendDeviceSlefCheckInfo()
{
string redisChannel = "deviceSelfTestChannel";
await _redisDataRepository.AbnormalComponentRedis.PublishAsync(redisChannel, new EquipmentInfoAbnormalComponent
{
EquipmentInfoId = Guid.Parse("08dd0eb5-f8b7-48a4-81da-2f531d0f614a"),
AbnormalReason = "当前值63°超过门限60°",
ComponentName = "机箱温度",
HandlingMeasures= "注意关注温度状态",
});
}
/// <summary>
/// 发送回路诊断信息
/// </summary>
/// <returns></returns>
private async Task SendSecondaryCircuitDiagnosticsInfo()
{
string redisChannel = "secondaryCircuitDiagnosticsChannel";
await _redisDataRepository.SecondaryCircuitComponentRedis.PublishAsync(redisChannel, new SecondaryCircuitComponent
{
EquipmentInfoId = Guid.Parse("08dd0eb5-f8b7-48a4-81da-2f531d0f614a"),
SecondaryCircuitId = Guid.Parse("08dd0eba-d37b-4920-811c-40b7c29f69fe"),
AbnormalReason = "表达式1200A超范围1000A",
ComponentName = "交流回路_1",
HandlingMeasures = "",
});
}
/// <summary>
/// 发送寿命预估
/// </summary>
/// <returns></returns>
private async Task SendEquipmentInfoRemainingLifeAssessmentInfo()
{
string redisChannel = "equipmentInfoRemainingLifeAssessmentChannel";
await _redisDataRepository.EquipmentInfoRemainingLifeAssessmentRedis.PublishAsync(redisChannel, new EquipmentInfoRemainingLifeAssessment
{
EquipmentInfoId = Guid.Parse("08dd0eb5-f8b7-48a4-81da-2f531d0f614a"),
RemainingLifeInYears = "5.8年",
});
}
/// <summary>
/// 发送遥测数据到主界面日志显示
/// </summary>
/// <param name="info"></param>
public void RecordYCLogInfo(YC_TYPE_New info)
{
if (!_settingModel.Displayyxyc)
{
return;
}
string infoStr = $"装置地址:{info.addr}CPU扇区号{info.sector},编码地址:{info.inf},遥测值:{info.val},时间:{(info.time.ToString("HH:mm:ss fff"))}";
MonitoringEventBus.LogHandler(infoStr, "遥测数据");
}
/// <summary>
/// 发送遥信数据到主界面日志显示
/// </summary>
/// <param name="info"></param>
public void RecordYXLogInfo(RECORDYXBURST_New info)
{
if (!_settingModel.Displayyxyc)
{
return;
}
string infoStr = $"装置地址:{info.dev_addr}CPU扇区号{info.dev_sector},编码地址:{info.dev_inf},遥信值:{info.yx_val},时间:{(info.time.ToString("HH:mm:ss fff"))}";
MonitoringEventBus.LogHandler(infoStr, "双点信息");
}
}
}