Compare commits
4 Commits
111f8d06ff
...
326d50630a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
326d50630a | ||
|
|
1fc9614257 | ||
|
|
1d0d933aa5 | ||
|
|
52290ac5f7 |
@ -378,6 +378,28 @@
|
||||
<param name="videos">Video devices list</param>
|
||||
<param name="presets">Preset points list</param>
|
||||
</member>
|
||||
<member name="T:YunDa.SOMS.ExternalInteraction.Application.MainStation.HandleUploadInspectionItems.Services.IBatchOperationService">
|
||||
<summary>
|
||||
Batch operation service interface for optimizing database operations
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:YunDa.SOMS.ExternalInteraction.Application.MainStation.HandleUploadInspectionItems.Services.IBatchOperationService.BatchInsertInspectionResultsAsync(System.Collections.Generic.List{YunDa.SOMS.DataTransferObject.MainstationData.OriginalInspectionStoreResult},System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
Batch insert inspection results into MongoDB with automatic partitioning
|
||||
</summary>
|
||||
<param name="items">Collection of inspection results to insert</param>
|
||||
<param name="cancellationToken">Cancellation token for async operation</param>
|
||||
<returns>True if all batches inserted successfully, false otherwise</returns>
|
||||
</member>
|
||||
<member name="M:YunDa.SOMS.ExternalInteraction.Application.MainStation.HandleUploadInspectionItems.Services.IBatchOperationService.BatchInsertInspectionResultsAsync(System.Collections.Generic.List{YunDa.SOMS.DataTransferObject.MainstationData.OriginalInspectionStoreResult},System.Int32,System.Threading.CancellationToken)">
|
||||
<summary>
|
||||
Batch insert inspection results with custom batch size
|
||||
</summary>
|
||||
<param name="items">Collection of inspection results to insert</param>
|
||||
<param name="batchSize">Custom batch size for partitioning</param>
|
||||
<param name="cancellationToken">Cancellation token for async operation</param>
|
||||
<returns>True if all batches inserted successfully, false otherwise</returns>
|
||||
</member>
|
||||
<member name="T:YunDa.SOMS.ExternalInteraction.Application.PatternRecognition.MainstationGetTempService">
|
||||
<summary>
|
||||
对外通信-主站额外需求
|
||||
|
||||
@ -1417,6 +1417,12 @@
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YunDa.SOMS.MongoDB.Application.Inspection.InspectionItemResultAppService.TestGetAlarmMessage(System.String,System.String,System.String)">
|
||||
<summary>
|
||||
测试报警api
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:YunDa.SOMS.MongoDB.Application.Inspection.InspectionItemResultAppService.GetAlarmMessage(System.Nullable{System.Guid},System.Int32,System.String)">
|
||||
<summary>
|
||||
获取报警信息
|
||||
|
||||
@ -150,6 +150,10 @@ namespace YunDa.Server.ISMSTcp.Configuration
|
||||
/// </summary>
|
||||
public string GetOpticalCableConfigUri => $"{BaseUrl.TrimEnd('/')}/api/services/SOMS/OpticalCable/GetList";
|
||||
|
||||
|
||||
//获取架式设备配置
|
||||
public string GetRackEquipmentConfig => $"{BaseUrl.TrimEnd('/')}/api/services/SOMS/RackEquipment/GetList";
|
||||
|
||||
/// <summary>
|
||||
/// 保存巡检计划执行结果
|
||||
/// </summary>
|
||||
|
||||
@ -37,6 +37,8 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
private readonly TelesignalisationHandle _telesignalisationHandle;
|
||||
private readonly GwErrorRatioService _gwErrorRatioService;
|
||||
private readonly VirtualTerminalHandler _virtualTerminalHandler;
|
||||
private readonly SecondaryCircuitInspectionPlanService _secondaryCircuitInspectionPlanService;
|
||||
private readonly ThingService _thingService;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
@ -58,7 +60,9 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
TelemeteringHandle telemeteringHandle,
|
||||
TelesignalisationHandle telesignalisationHandle,
|
||||
GwErrorRatioService gwErrorRatioService,
|
||||
VirtualTerminalHandler virtualTerminalHandler)
|
||||
VirtualTerminalHandler virtualTerminalHandler,
|
||||
SecondaryCircuitInspectionPlanService secondaryCircuitInspectionPlanService,
|
||||
ThingService thingService)
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_queryService = queryService ?? throw new ArgumentNullException(nameof(queryService));
|
||||
@ -70,6 +74,8 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
_telesignalisationHandle = telesignalisationHandle ?? throw new ArgumentNullException(nameof(telesignalisationHandle));
|
||||
_gwErrorRatioService = gwErrorRatioService ?? throw new ArgumentNullException(nameof(gwErrorRatioService));
|
||||
_virtualTerminalHandler = virtualTerminalHandler ?? throw new ArgumentNullException(nameof(virtualTerminalHandler));
|
||||
_secondaryCircuitInspectionPlanService = secondaryCircuitInspectionPlanService ?? throw new ArgumentNullException(nameof(secondaryCircuitInspectionPlanService));
|
||||
_thingService = thingService ?? throw new ArgumentNullException( nameof(thingService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -255,49 +261,6 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
return StatusCode(500, $"服务器内部错误: {ex.Message}");
|
||||
}
|
||||
|
||||
|
||||
private List<string> GetValidZzCmd(string cmdName, List<string> ids)
|
||||
{
|
||||
const int maxLength = 250;
|
||||
|
||||
var cmds = new List<string>();
|
||||
|
||||
// 开始构建
|
||||
string prefix = cmdName + "|"; // 固定前缀
|
||||
int prefixLength = prefix.Length;
|
||||
|
||||
var currentIds = new List<string>();
|
||||
int currentLength = prefixLength; // 当前命令的长度(含前缀)
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
// 如果添加这个ID会超长,则先生成一个命令
|
||||
int idLength = (currentIds.Count == 0 ? id.Length : (1 + id.Length)); // 第一个ID不需要 '#'
|
||||
|
||||
if (currentLength + idLength > maxLength)
|
||||
{
|
||||
// 将当前批次加入 cmds
|
||||
cmds.Add(prefix + string.Join("#", currentIds));
|
||||
|
||||
// 清空并重建
|
||||
currentIds.Clear();
|
||||
currentLength = prefixLength;
|
||||
}
|
||||
|
||||
// 添加新的 ID
|
||||
currentIds.Add(id);
|
||||
currentLength += idLength;
|
||||
}
|
||||
|
||||
// 收尾:如果还有剩余 IDs,生成最后一个命令
|
||||
if (currentIds.Count > 0)
|
||||
{
|
||||
cmds.Add(prefix + string.Join("#", currentIds));
|
||||
}
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据数据ID召唤遥测数据
|
||||
/// </summary>
|
||||
@ -320,21 +283,18 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
[FromBody] ZzDataRequestModel request,
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
var id = request.Id;
|
||||
var ids = request.Id;
|
||||
var times = request.Times;
|
||||
|
||||
id.RemoveAll(string.IsNullOrWhiteSpace);
|
||||
ids.RemoveAll(string.IsNullOrWhiteSpace);
|
||||
|
||||
//string cmd = string.Format("CallYCByDataID|{0}", string.Join("#", id));
|
||||
_logger.LogWarning("收到 CallYCByDataId");
|
||||
|
||||
//System.Console.WriteLine($"发送遥测命令:{cmd}");
|
||||
|
||||
var cmds = GetValidZzCmd("CallYCByDataID", id);
|
||||
|
||||
try
|
||||
{
|
||||
// 参数验证
|
||||
if (id.Count == 0)
|
||||
if (ids.Count == 0)
|
||||
{
|
||||
return BadRequest(new
|
||||
{
|
||||
@ -344,64 +304,23 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
_logger.LogInformation("收到遥测数据召唤请求 - cmd: {cmd}", string.Join("#", id));
|
||||
// 发送TCP消息
|
||||
|
||||
DateTime cmdTime = DateTime.Now;
|
||||
|
||||
int sucessCount = 0;
|
||||
|
||||
if(request.TimeWindowType == 1 || request.TimeWindowType == 2)
|
||||
{
|
||||
for (int i = 0; i < times; i++)
|
||||
{
|
||||
bool isSuccess = true;
|
||||
|
||||
foreach (var cmd in cmds)
|
||||
{
|
||||
var sendResult = await SendTcpMessageAsync(cmd, cancellationToken);
|
||||
isSuccess &= sendResult.Success;
|
||||
if (!isSuccess)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(5);
|
||||
}
|
||||
}
|
||||
|
||||
if (isSuccess)
|
||||
{
|
||||
sucessCount++;
|
||||
}
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sucessCount = 10;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (times - sucessCount < 3)
|
||||
{
|
||||
List<ZzDataResultModel>? ycDataList = null;
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
while (sw.ElapsedMilliseconds < 10 * 1000)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
{
|
||||
ycDataList = await _telemeteringHandle.GetYCDataByDataIds(id, times, request.TimeWindowType, cancellationToken, cmdTime);
|
||||
ycDataList = await _telemeteringHandle.GetYCDataByDataIds(ids, times, request.TimeWindowType, cancellationToken);
|
||||
|
||||
if (ycDataList.Count == id.Count)
|
||||
if (ycDataList.Count == ids.Count)
|
||||
{
|
||||
break;
|
||||
|
||||
await Task.Delay(100);
|
||||
}
|
||||
|
||||
if (ycDataList?.Count == id.Count)
|
||||
if(request.TimeWindowType == 0)
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
|
||||
if (ycDataList?.Count == ids.Count)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
@ -421,21 +340,10 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return StatusCode(500, new
|
||||
{
|
||||
success = false,
|
||||
message = $"发送命令失败",
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.LogWarning("遥测数据召唤请求被取消 - cmd: {cmd}", string.Join("#", id));
|
||||
_logger.LogWarning("遥测数据召唤请求被取消 - cmd: {cmd}", string.Join("#", ids));
|
||||
return StatusCode(504, new
|
||||
{
|
||||
success = false,
|
||||
@ -445,7 +353,7 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "处理遥测数据召唤请求时发生异常 - cmd: {cmd}", string.Join("#", id));
|
||||
_logger.LogError(ex, "处理遥测数据召唤请求时发生异常 - cmd: {cmd}", string.Join("#", ids));
|
||||
return StatusCode(500, new
|
||||
{
|
||||
success = false,
|
||||
@ -1163,6 +1071,103 @@ namespace YunDa.Server.ISMSTcp.Controllers
|
||||
// });
|
||||
// }
|
||||
//}
|
||||
|
||||
[HttpGet("UpdateConfig")]
|
||||
public async Task<IActionResult> UpdateConfig([FromQuery] int configType)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (configType)
|
||||
{
|
||||
//更新计划巡检、事件巡检
|
||||
case 1:
|
||||
await _secondaryCircuitInspectionPlanService.UpdatePlanConfig();
|
||||
break;
|
||||
|
||||
//更新网线配置
|
||||
case 2:
|
||||
await _thingService.UpdateNetworkCableConfig();
|
||||
break;
|
||||
|
||||
//更新光纤配置
|
||||
case 3:
|
||||
await _thingService.UpdateOpticalFiberConfig();
|
||||
break;
|
||||
|
||||
//更新光缆配置
|
||||
case 4:
|
||||
await _thingService.UpdateOpticalCableConfig();
|
||||
break;
|
||||
|
||||
//更新架式设备配置、孪生体与遥测数据绑定关系、设备和孪生体的关联
|
||||
case 5:
|
||||
await _thingService.UpdateRackEquipmentConfig();
|
||||
await _thingService.UpdateDeviceBindingConfig();
|
||||
await _thingService.UpdateSimDatasConfig();
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
return BadRequest(new
|
||||
{
|
||||
success = false,
|
||||
message = "错误configType",
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
_logger.LogInformation($"收到配置更新命令:configType = {configType}");
|
||||
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
message = "更新成功",
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"更新失败: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("ClearAllThingAlarm")]
|
||||
public async Task<IActionResult> ClearAllThingAlarm()
|
||||
{
|
||||
try
|
||||
{
|
||||
bool success = await _thingService.ClearAllAlarm();
|
||||
|
||||
if (success)
|
||||
{
|
||||
|
||||
return Ok(new
|
||||
{
|
||||
success = true,
|
||||
message = "清除成功",
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
return BadRequest(new
|
||||
{
|
||||
success = false,
|
||||
message = "清除失败",
|
||||
timestamp = DateTime.Now
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return StatusCode(500, $"清除失败: {ex.Message}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -107,6 +107,9 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// </summary>
|
||||
string GetOpticalCableConfigUri { get; }
|
||||
|
||||
//获取架式设备配置
|
||||
string GetRackEquipmentConfig { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 保存巡检计划执行结果
|
||||
/// </summary>
|
||||
@ -251,6 +254,9 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// </summary>
|
||||
public string GetOpticalCableConfigUri => _config.GetOpticalCableConfigUri;
|
||||
|
||||
//获取架式设备配置
|
||||
public string GetRackEquipmentConfig => _config.GetRackEquipmentConfig;
|
||||
|
||||
/// <summary>
|
||||
/// 保存巡检计划执行结果
|
||||
/// </summary>
|
||||
|
||||
@ -700,12 +700,12 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// <summary>
|
||||
/// 获取孪生体与遥测数据绑定关系
|
||||
/// </summary>
|
||||
public async Task<List<ThingDeviceBindingModel>> GetThingDeviceBindingConfigAsync()
|
||||
public async Task<List<ThingDeviceBindingModel>> GetThingDeviceBindingConfigAsync(int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var response = await HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.ThingDeviceBindingConfigUri, new object());
|
||||
var response = await HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.ThingDeviceBindingConfigUri, new { pageIndex = pageIndex, pageSize = pageSize });
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
@ -908,12 +908,12 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// <summary>
|
||||
/// 获取网线配置
|
||||
/// </summary>
|
||||
public async Task<List<OpticalFiberConfigModel>> GetNetworkCableConfigAsync()
|
||||
public async Task<List<OpticalFiberConfigModel>> GetNetworkCableConfigAsync(int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetNetworkCableConfigUri, new object()));
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetNetworkCableConfigUri, new { pageIndex = pageIndex, pageSize = pageSize }));
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
@ -947,12 +947,12 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// <summary>
|
||||
/// 获取光纤配置
|
||||
/// </summary>
|
||||
public async Task<List<OpticalFiberConfigModel>> GetOpticalFiberConfigAsync()
|
||||
public async Task<List<OpticalFiberConfigModel>> GetOpticalFiberConfigAsync(int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetOpticalFiberConfigUri, new object()));
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetOpticalFiberConfigUri, new { pageIndex = pageIndex, pageSize = pageSize }));
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
@ -985,11 +985,11 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
/// <summary>
|
||||
/// 获取光缆配置
|
||||
/// </summary>
|
||||
public async Task<List<OpticalFiberConfigModel>> GetOpticalCableConfigAsync()
|
||||
public async Task<List<OpticalFiberConfigModel>> GetOpticalCableConfigAsync(int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetOpticalCableConfigUri, new { includeInspectionItems = true }));
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetOpticalCableConfigUri, new { pageIndex = pageIndex, pageSize = pageSize }));
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
@ -1007,6 +1007,31 @@ namespace YunDa.Server.ISMSTcp.Domain
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
///获取架式设备配置
|
||||
public async Task<List<OpticalFiberConfigModel>> GetRackEquipmentConfigAsync(int pageIndex, int pageSize)
|
||||
{
|
||||
try
|
||||
{
|
||||
var response = await Task.Run(() => HttpHelper.HttpPostRequestAsync<JObject>(_apiEndpoints.GetRackEquipmentConfig, new { pageIndex = pageIndex, pageSize = pageSize }));
|
||||
|
||||
if (response != null)
|
||||
{
|
||||
|
||||
var result = ExtractDataFromAbpResponse<List<OpticalFiberConfigModel>>(response);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error Call GetRackEquipmentConfigAsync Api");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存巡检计划执行结果
|
||||
/// </summary>
|
||||
|
||||
@ -132,6 +132,7 @@ namespace YunDa.Server.ISMSTcp.Extensions
|
||||
services.AddSingleton<GwErrorRatioService>();
|
||||
services.AddSingleton<ZzTcpService>();
|
||||
services.AddSingleton<ZzDataCacheContainerInit>();
|
||||
services.AddSingleton<ZzDataCmdService>();
|
||||
|
||||
// 日志过滤器配置
|
||||
services.Configure<YunDa.Server.ISMSTcp.Filters.Configuration.LogFilterConfiguration>(
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Helpers
|
||||
{
|
||||
public static class StringHelper
|
||||
{
|
||||
public static string GetAfterLastOfAny(string input, params char[] separators)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input) || separators == null || separators.Length == 0)
|
||||
return input;
|
||||
|
||||
int index = input.AsSpan().LastIndexOfAny(separators);
|
||||
return index >= 0
|
||||
? input.Substring(index + 1)
|
||||
: input;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,151 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using YunDa.Server.ISMSTcp.Services;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection;
|
||||
using YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipment;
|
||||
using YunDa.SOMS.Entities.DataMonitoring.SecondaryCircuitInspection;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Models
|
||||
{
|
||||
//带执行状态的巡检计划结构体
|
||||
public class SecondaryCircuitInspectionPlanStateModel
|
||||
{
|
||||
//执行时间
|
||||
public DateTime ExecuteTime { get; set; } = DateTime.MinValue;
|
||||
|
||||
public SecondaryCircuitInspectionPlanOutput Plan { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionPlanStateModel()
|
||||
{
|
||||
Plan = new SecondaryCircuitInspectionPlanOutput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SecondaryCircuitInspectionItemOutputEx
|
||||
{
|
||||
public int TriggerType { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionItemOutput Item { get; set; }
|
||||
|
||||
public string PlanId { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionItemOutputEx(int triggerType, SecondaryCircuitInspectionItemOutput item, string planId)
|
||||
{
|
||||
TriggerType = triggerType;
|
||||
Item = item;
|
||||
PlanId = planId;
|
||||
}
|
||||
}
|
||||
|
||||
public class DeviceDzData
|
||||
{
|
||||
public List<DzInfo> UserDz { get; set; }
|
||||
|
||||
public List<DzInfo> SysDz { get; set; }
|
||||
|
||||
public string DeviceName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class InspectionResultData
|
||||
{
|
||||
public string PresetName { get; set; } = string.Empty;
|
||||
|
||||
public int PresetCode { get; set; }
|
||||
|
||||
public string TimeStamp { get; set; } = string.Empty;
|
||||
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class SecondaryCircuitInspectionStoreDataModel
|
||||
{
|
||||
//遥测数据
|
||||
public List<ZzDataResultModel> TelemetryData { get; set; }
|
||||
|
||||
//遥信数据
|
||||
public List<ZzDataResultModel> TeleSignalData { get; set; }
|
||||
|
||||
//定值
|
||||
public List<DeviceDzData> SettingData { get; set; }
|
||||
|
||||
//预置位
|
||||
public List<InspectionResultData> PresetData { get; set; }
|
||||
|
||||
//虚点数据
|
||||
public List<ZzDataResultModel> VariantData { get; set; }
|
||||
|
||||
//网关数据
|
||||
public List<ZzDataResultModel> GatewayData { get; set; }
|
||||
|
||||
public bool IsAllDataNull()
|
||||
{
|
||||
return (TelemetryData == null && TeleSignalData == null && SettingData == null &&
|
||||
PresetData == null && GatewayData == null && VariantData == null);
|
||||
}
|
||||
}
|
||||
//巡检结果
|
||||
public class SecondaryCircuitInspectionJsDataModel
|
||||
{
|
||||
public int TimeWindowSeconds { get; set; }
|
||||
public int TimeWindowCount { get; set; }
|
||||
public TimeWindowTypeEnum TimeWindowType { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionStoreDataModel StoreData { get; set; } = new SecondaryCircuitInspectionStoreDataModel();
|
||||
public List<SecondaryCircuitInspectionTelemetryConfigOutput> TelemetryConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionTelesignalConfigOutput> TelesignalConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionCameraPresetOutput> CameraPresets { get; set; }
|
||||
public List<SecondaryCircuitInspectionDeviceConfigOutput> DeviceConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionVariantOutput> VariantConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionGatewayOutput> GatewayConfigs { get; set; }
|
||||
}
|
||||
|
||||
|
||||
//巡检结果上传Model
|
||||
public class SecondaryCircuitInspectionResultSaveModel
|
||||
{
|
||||
public string SecondaryCircuitInspectionItemId { get; set; } = string.Empty;
|
||||
public string InspectionPlanId { get; set; } = string.Empty;
|
||||
|
||||
public string ExecutionTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public long ExecutionDurationMs { get; set; }
|
||||
|
||||
public int TriggerType { get; set; } //1计划,2事件
|
||||
|
||||
public string TriggerEventId { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
|
||||
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
|
||||
public string CalculationProcess { get; set; } = string.Empty; //计算过程
|
||||
public string VerificationResult { get; set; } = string.Empty; //校验结果
|
||||
public SecondaryCircuitInspectionJsDataModel Data { get; set; }
|
||||
public string Remark { get; set; } = string.Empty; //无用
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
public class SecondaryCircuitInspectionAiParamModel
|
||||
{
|
||||
public string InspectionResultId { get; set; } = string.Empty;
|
||||
public string InspectionName { get; set; } = string.Empty;
|
||||
public string InspectionDescription { get; set; } = string.Empty;
|
||||
public string PlanName => string.Concat(InspectionName, " ", InspectionDescription);
|
||||
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
|
||||
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
|
||||
public string CalculationProcess { get; set; } = string.Empty; //计算过程
|
||||
public string VerificationResult { get; set; } = string.Empty; //校验结果
|
||||
|
||||
}
|
||||
|
||||
public class SecondaryCircuitInspectionAiSaveModel
|
||||
{
|
||||
public string InspectionResultId { get; set; } = string.Empty;
|
||||
public string AiAnalysisResult { get; set; } = string.Empty; // "AI结果状态:失败|成功",
|
||||
public string ResultHandleDescription { get; set; } = string.Empty; //"AI返回的处理结果"
|
||||
}
|
||||
}
|
||||
174
src/YunDa.Server/YunDa.Server.ISMSTcp/Models/ThingModel.cs
Normal file
174
src/YunDa.Server/YunDa.Server.ISMSTcp/Models/ThingModel.cs
Normal file
@ -0,0 +1,174 @@
|
||||
using Esprima.Ast;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using YunDa.Server.ISMSTcp.Helpers;
|
||||
using YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipment;
|
||||
using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Models
|
||||
{
|
||||
//ThingApiService配置
|
||||
public class ThingApiServiceSettings
|
||||
{
|
||||
public string ApiServerUrl { get; set; } = string.Empty;
|
||||
public string LoginCode { get; set; } = string.Empty;
|
||||
public string LoginKey { get; set; } = string.Empty;
|
||||
public string EsAuthorization { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ThingDeviceStatusModel
|
||||
{
|
||||
public string TwinID { get; set; } = string.Empty;
|
||||
|
||||
public string Metric { get; set; } = string.Empty;
|
||||
|
||||
public string Val { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
public class ThingDeviceBindingModel
|
||||
{
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public string TwinID { get; set; } = string.Empty;
|
||||
|
||||
public string Metric { get; set; } = string.Empty; //格式:1:绿灯1|0:红灯1
|
||||
|
||||
public string Val { get; set; } = string.Empty;
|
||||
|
||||
public int TwinDataBindingType { get; set; }
|
||||
|
||||
public string Remark { get; set; } = string.Empty;
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
public TelesignalisationConfigurationModel TelesignalisationConfiguration { get; set; }
|
||||
|
||||
public List<ThingDevicePushDataModel> MetricList { get; set; }
|
||||
|
||||
public List<ThingDevicePushDataModel> ValList { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class TelesignalisationConfigurationModel
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public int DispatcherAddress { get; set; }
|
||||
|
||||
public string IsmsbaseYXId { get; set; } = string.Empty;
|
||||
|
||||
public int RemoteType { get; set; }
|
||||
|
||||
public string Id { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ThingDevicePushDataModel
|
||||
{
|
||||
public string Val { get; set; } = string.Empty;
|
||||
|
||||
public string Cmd { get; set; } = string.Empty;
|
||||
|
||||
public string CloseCmd { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
//性能数据
|
||||
public class TingSimDataModel
|
||||
{
|
||||
public string TwinId { get; set; } = string.Empty;
|
||||
|
||||
public string EquipmentInfoId { get; set; } = string.Empty;
|
||||
|
||||
public string EquipmentInfoName { get; set; } = string.Empty;
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
//告警推送数据
|
||||
public class TingAlarmPushDataModel
|
||||
{
|
||||
public string TwinId { get; set; } = string.Empty; //孪生体Id ******
|
||||
|
||||
public int Severity { get; set; } //报警级别
|
||||
|
||||
public int Status { get; set; } //状态:1=告警;2=恢复
|
||||
|
||||
public string SourceAlertKey { get; set; } = string.Empty; //指标名称 ******
|
||||
|
||||
public string Summary { get; set; } = string.Empty; //告警内容
|
||||
|
||||
public string SourceIdentifier { get; set; } = string.Empty;//事件源的唯一标识 ******
|
||||
|
||||
public string LastOccurrence { get; set; } = string.Empty; //告警最后一次发生时间
|
||||
|
||||
|
||||
static public string[] AlarmKeyword = { "分", "未同步", "告警", "异常", "断", "未就绪", "无效", "未复归", "动作", "检修", "未储能", "跳闸", "失步", "分位", "故障", "产生", "不定", "中断", "不良", "失灵" };
|
||||
//static public string[] RecoveryKeyword = { "正常", "消失", "通", "同步", "解除", "复归", "已复归", "返回", "已储能", "恢复" };
|
||||
|
||||
|
||||
public bool Parse(string twinId, AlertData alertData)
|
||||
{
|
||||
List<string> alarmLevel = new List<string> { "", "事故", "异常", "变位", "越限", "告知" };
|
||||
Severity = alarmLevel.IndexOf(alertData.AlertLevel);
|
||||
|
||||
if (Severity < 1)
|
||||
return false;
|
||||
else if (Severity == 5)
|
||||
Severity = 4;
|
||||
|
||||
|
||||
bool isAlarm = AlarmKeyword.Any(e => alertData.Content.Contains(e));
|
||||
|
||||
TwinId = twinId;
|
||||
|
||||
Status = isAlarm ? 1 : 2;
|
||||
|
||||
SourceAlertKey = alertData.Alerter; //Alerter是唯一的,相同的告警,TwinId、SourceAlertKey和SourceIdentifier要相同
|
||||
|
||||
Summary = $"{ StringHelper.GetAfterLastOfAny(alertData.Alerter, '|')} : {StringHelper.GetAfterLastOfAny(alertData.Content, ':')}";
|
||||
|
||||
SourceIdentifier = alertData.Alerter; //Alerter是唯一的
|
||||
|
||||
LastOccurrence = alertData.AlertTime.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
|
||||
if (Summary.Contains("保护CPU连接状态"))
|
||||
{
|
||||
int kk = 0;
|
||||
Debug.WriteLine($"{Summary}\ttwinId ={twinId}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Parse(string twinId, int severity, bool isAlarm, string alarmUuid, string alarmContent, string alarmTime)
|
||||
{
|
||||
TwinId = twinId;
|
||||
Severity = severity;
|
||||
Status = isAlarm ? 1 : 2;
|
||||
SourceAlertKey = alarmUuid;
|
||||
Summary = $"{alarmUuid}{alarmContent}";
|
||||
SourceIdentifier = alarmUuid;
|
||||
LastOccurrence = alarmTime;
|
||||
}
|
||||
}
|
||||
|
||||
//光纤
|
||||
public class OpticalFiberConfigModel : NetworkCable
|
||||
{
|
||||
public string VirtualPointCode { get; set; } = string.Empty;
|
||||
|
||||
public string[] VirtualPointCodes => string.IsNullOrWhiteSpace(VirtualPointCode) ? Array.Empty<string>() : VirtualPointCode.Split(',', ',');
|
||||
|
||||
public string LinkageData { get; set; } = string.Empty;
|
||||
|
||||
public string[] LinkageDatas => string.IsNullOrWhiteSpace(LinkageData) ? Array.Empty<string>() : LinkageData.Split(',', ',');
|
||||
|
||||
public string[] LogicalExpressions => string.IsNullOrWhiteSpace(LogicalExpression) ? Array.Empty<string>() : LogicalExpression.Split(',', ',');
|
||||
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Serilog;
|
||||
using YunDa.Server.ISMSTcp.Extensions;
|
||||
using YunDa.Server.ISMSTcp.Models;
|
||||
using YunDa.Server.ISMSTcp.Services;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp
|
||||
|
||||
62
src/YunDa.Server/YunDa.Server.ISMSTcp/Services/AppInit.cs
Normal file
62
src/YunDa.Server/YunDa.Server.ISMSTcp/Services/AppInit.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
public static class AppInit
|
||||
{
|
||||
private static readonly TaskCompletionSource<bool> _tcs =
|
||||
new TaskCompletionSource<bool>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||
|
||||
private static int _state = 0; // 0 = 未初始化; 1 = 已初始化
|
||||
private static readonly DateTime _startTime = DateTime.UtcNow;
|
||||
|
||||
public static readonly TimeSpan DefaultTimeOut = TimeSpan.FromMinutes(10);
|
||||
|
||||
/// <summary>立即返回初始化状态</summary>
|
||||
public static bool IsInitialized() => Volatile.Read(ref _state) == 1;
|
||||
|
||||
/// <summary>从程序启动开始计算超时,如果初始化完成或超过超时返回 true</summary>
|
||||
public static bool IsInitialized(TimeSpan timeout)
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true;
|
||||
|
||||
return (DateTime.UtcNow - _startTime) >= timeout;
|
||||
}
|
||||
|
||||
/// <summary>等待初始化完成(无限等待)</summary>
|
||||
public static Task WaitAsync() => _tcs.Task;
|
||||
|
||||
/// <summary>等待初始化完成(从调用时间开始计时超时)</summary>
|
||||
public static async ValueTask<bool> WaitAsync(TimeSpan timeout)
|
||||
{
|
||||
if (IsInitialized())
|
||||
return true;
|
||||
|
||||
using var cts = new CancellationTokenSource(timeout);
|
||||
|
||||
try
|
||||
{
|
||||
await _tcs.Task.WaitAsync(cts.Token);
|
||||
return IsInitialized();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>标记初始化完成(线程安全,只会触发一次)</summary>
|
||||
public static void MarkInitialized()
|
||||
{
|
||||
if (Interlocked.Exchange(ref _state, 1) != 0)
|
||||
return;
|
||||
|
||||
_tcs.TrySetResult(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -76,6 +76,9 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
//二次回路巡检计划
|
||||
private readonly SecondaryCircuitInspectionPlanService _secondaryCircuitInspectionPlanService;
|
||||
|
||||
|
||||
private readonly ZzDataCmdService _zzDataCmdService;
|
||||
|
||||
public DataProcessor(
|
||||
ILogger<DataProcessor> logger,
|
||||
MessageParser messageParser,
|
||||
@ -94,7 +97,8 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
WebApiRequest webApiRequest,
|
||||
SecondaryCircuitInspectionPlanService secondaryCircuitInspectionPlanService,
|
||||
ThingService thingService,
|
||||
GwErrorRatioService gwErrorRatioService)
|
||||
GwErrorRatioService gwErrorRatioService,
|
||||
ZzDataCmdService zzDataCmdService)
|
||||
{
|
||||
_logger = logger;
|
||||
_messageParser = messageParser;
|
||||
@ -114,6 +118,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
_secondaryCircuitInspectionPlanService = secondaryCircuitInspectionPlanService ?? throw new ArgumentNullException(nameof(secondaryCircuitInspectionPlanService));
|
||||
_thingService = thingService ?? throw new ArgumentNullException(nameof(thingService));
|
||||
_gwErrorRatioService = gwErrorRatioService ?? throw new ArgumentNullException(nameof(gwErrorRatioService));
|
||||
_zzDataCmdService = zzDataCmdService ?? throw new ArgumentNullException(nameof(zzDataCmdService));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -180,6 +185,8 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
HandleRecvMsg(contentToken, "FAULTRPT");
|
||||
var alertDatas = contentToken.ToObject<List<AlertData>>();
|
||||
if(alertDatas != null)
|
||||
Log.Warning($"收到故障报告:数量{alertDatas.Count}");
|
||||
foreach (var item in alertDatas)
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(item);
|
||||
@ -226,6 +233,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
// 批量处理遥测数据
|
||||
await _telemeteringHandle.ProcessYCDataAsync(contentArray);
|
||||
|
||||
//_logger.LogWarning($"收到遥测数据,数量:{contentArray.Count}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -464,6 +472,10 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
deviceUpdates.Add((deviceId, isOnline));
|
||||
processedCount++;
|
||||
|
||||
|
||||
//更新装置状态
|
||||
_zzDataCmdService.UpdateDeviceCommState(deviceId, isOnline);
|
||||
|
||||
}
|
||||
catch (Exception itemEx)
|
||||
{
|
||||
@ -610,10 +622,10 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
//await ProcessFaultReportsAsync(alertDatas);
|
||||
|
||||
//报警上传
|
||||
await _webApiRequest.UploadAlertMessageAsync(alertDatas);
|
||||
_webApiRequest.UploadAlertMessageAsync(alertDatas);
|
||||
|
||||
//报警推送到孪生体
|
||||
await _thingService.UpdateAlarmDatas(alertDatas);
|
||||
_thingService.UpdateAlarmDatas(alertDatas);
|
||||
|
||||
|
||||
|
||||
|
||||
@ -31,6 +31,9 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
_logger = logger;
|
||||
_zzDataCacheContainerInit = zzDataCacheContainerInit;
|
||||
_zzDataCacheContainerInit.InitGateWayBaseInfo(_cacheContainer);
|
||||
|
||||
|
||||
ZzDataCache.SetDataCache(ZzDataCacheContainerDataType.eGW, _cacheContainer);
|
||||
}
|
||||
|
||||
//解析数据
|
||||
@ -79,7 +82,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
}
|
||||
}
|
||||
|
||||
//缓存遥信数据到内存
|
||||
//缓存数据到内存
|
||||
private void SaveDataToCache(GwErrorRatioDataModel data)
|
||||
{
|
||||
_cacheContainer.Write(data.GatewayID, data.ErrorRatio, data.DataTimeStamp, "", data.ErrorRatio.ToString("P2"));
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
using DotNetty.Common.Utilities;
|
||||
using Abp.AutoMapper;
|
||||
using DotNetty.Common.Utilities;
|
||||
using Jint;
|
||||
using Jint.Native;
|
||||
using Jint.Native.Object;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -25,14 +27,13 @@ using System.Threading;
|
||||
using System.Threading.Channels;
|
||||
using System.Threading.Tasks;
|
||||
using YunDa.Server.ISMSTcp.Domain;
|
||||
using YunDa.Server.ISMSTcp.Helpers;
|
||||
using YunDa.Server.ISMSTcp.Interfaces;
|
||||
using YunDa.Server.ISMSTcp.Models;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Configurations;
|
||||
using YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipment;
|
||||
using YunDa.SOMS.Entities.DataMonitoring.SecondaryCircuitInspection;
|
||||
using YunDa.Server.ISMSTcp.Helpers;
|
||||
using Abp.AutoMapper;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
@ -42,137 +43,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
public int Port { get; set; }
|
||||
}
|
||||
|
||||
//带执行状态的巡检计划结构体
|
||||
public class SecondaryCircuitInspectionPlanStateModel
|
||||
{
|
||||
//执行时间
|
||||
public DateTime ExecuteTime { get; set; } = DateTime.MinValue;
|
||||
|
||||
public SecondaryCircuitInspectionPlanOutput Plan { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionPlanStateModel()
|
||||
{
|
||||
Plan = new SecondaryCircuitInspectionPlanOutput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class SecondaryCircuitInspectionItemOutputEx
|
||||
{
|
||||
public int TriggerType { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionItemOutput Item { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionItemOutputEx(int triggerType, SecondaryCircuitInspectionItemOutput item)
|
||||
{
|
||||
TriggerType = triggerType;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
|
||||
public class DeviceDzData
|
||||
{
|
||||
public List<DzInfo> UserDz { get; set; }
|
||||
|
||||
public List<DzInfo> SysDz { get; set; }
|
||||
|
||||
public string DeviceName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class InspectionResultData
|
||||
{
|
||||
public string PresetName { get; set; } = string.Empty;
|
||||
|
||||
public int PresetCode { get; set; }
|
||||
|
||||
public string TimeStamp { get; set; } = string.Empty;
|
||||
|
||||
public string Value { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class SecondaryCircuitInspectionStoreDataModel
|
||||
{
|
||||
//遥测数据
|
||||
public List<ZzDataResultModel> TelemetryData { get; set; }
|
||||
|
||||
//遥信数据
|
||||
public List<ZzDataResultModel> TeleSignalData { get; set; }
|
||||
|
||||
//定值
|
||||
public List<DeviceDzData> SettingData { get; set; }
|
||||
|
||||
//预置位
|
||||
public List<InspectionResultData> PresetData { get; set; }
|
||||
|
||||
//虚点数据
|
||||
public List<ZzDataResultModel> VariantData { get; set; }
|
||||
|
||||
//网关数据
|
||||
public List<ZzDataResultModel> GatewayData { get; set; }
|
||||
}
|
||||
//巡检结果
|
||||
public class SecondaryCircuitInspectionJsDataModel
|
||||
{
|
||||
public int TimeWindowSeconds { get; set; }
|
||||
public int TimeWindowCount { get; set; }
|
||||
public TimeWindowTypeEnum TimeWindowType { get; set; }
|
||||
|
||||
public SecondaryCircuitInspectionStoreDataModel StoreData { get; set; } = new SecondaryCircuitInspectionStoreDataModel();
|
||||
public List<SecondaryCircuitInspectionTelemetryConfigOutput> TelemetryConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionTelesignalConfigOutput> TelesignalConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionCameraPresetOutput> CameraPresets { get; set; }
|
||||
public List<SecondaryCircuitInspectionDeviceConfigOutput> DeviceConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionVariantOutput> VariantConfigs { get; set; }
|
||||
public List<SecondaryCircuitInspectionGatewayOutput> GatewayConfigs { get; set; }
|
||||
}
|
||||
|
||||
|
||||
//巡检结果上传Model
|
||||
public class SecondaryCircuitInspectionResultSaveModel
|
||||
{
|
||||
public string SecondaryCircuitInspectionItemId { get; set; } = string.Empty;
|
||||
public string InspectionPlanId { get; set; } = string.Empty;
|
||||
|
||||
public string ExecutionTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
public long ExecutionDurationMs { get; set; }
|
||||
|
||||
public int TriggerType { get; set; } //1计划,2事件
|
||||
|
||||
public string TriggerEventId { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
|
||||
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
|
||||
public string CalculationProcess { get; set; } = string.Empty; //计算过程
|
||||
public string VerificationResult { get; set; } = string.Empty; //校验结果
|
||||
public SecondaryCircuitInspectionJsDataModel Data { get; set; }
|
||||
public string Remark { get; set; } = string.Empty; //无用
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
public class SecondaryCircuitInspectionAiParamModel
|
||||
{
|
||||
public string InspectionResultId { get; set; } = string.Empty;
|
||||
public string InspectionName { get; set; } = string.Empty;
|
||||
public string InspectionDescription { get; set; } = string.Empty;
|
||||
public string PlanName => string.Concat(InspectionName, " ", InspectionDescription);
|
||||
public string Status { get; set; } = string.Empty; //"异常|正常|故障",
|
||||
public string InspectionResult { get; set; } = string.Empty; //巡检结果 inspectionResult不能超过15个字符
|
||||
public string CalculationProcess { get; set; } = string.Empty; //计算过程
|
||||
public string VerificationResult { get; set; } = string.Empty; //校验结果
|
||||
|
||||
}
|
||||
|
||||
public class SecondaryCircuitInspectionAiSaveModel
|
||||
{
|
||||
public string InspectionResultId { get; set; } = string.Empty;
|
||||
public string AiAnalysisResult { get; set; } = string.Empty; // "AI结果状态:失败|成功",
|
||||
public string ResultHandleDescription { get; set; } = string.Empty; //"AI返回的处理结果"
|
||||
}
|
||||
|
||||
//二次回路巡检计划
|
||||
public class SecondaryCircuitInspectionPlanService
|
||||
@ -184,12 +55,12 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
private readonly WebApiRequest _webApiRequest;
|
||||
private readonly WebApiSettings _webApiSettings;
|
||||
|
||||
private bool _updatedPlanOk = false;
|
||||
|
||||
|
||||
private Queue<SecondaryCircuitInspectionPlanStateModel> _planList;
|
||||
private readonly AsyncLock _planLock = new AsyncLock();
|
||||
private int _planCheckDay = 0;
|
||||
private bool _getPlanListOk = false;
|
||||
|
||||
private readonly Channel<SecondaryCircuitInspectionItemOutputEx> _singlePlanChannel; //巡检计划
|
||||
private readonly ChannelEx<SecondaryCircuitInspectionAiParamModel, string> _aiChannel; //Ai调用
|
||||
@ -199,11 +70,14 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
private readonly AsyncLock _eventPlanLock = new AsyncLock();
|
||||
private bool _getEventPlanListOk = false;
|
||||
|
||||
private readonly ZzDataCmdService _zzDataCmdService;
|
||||
|
||||
public SecondaryCircuitInspectionPlanService(
|
||||
ILogger<SecondaryCircuitInspectionPlanService> logger,
|
||||
IApiEndpoints apiEndpoints,
|
||||
WebApiRequest webApiRequest,
|
||||
IOptions<WebApiSettings> webApiOptions
|
||||
IOptions<WebApiSettings> webApiOptions,
|
||||
ZzDataCmdService zzDataCmdService
|
||||
)
|
||||
{
|
||||
_apiEndpoints = apiEndpoints ?? throw new ArgumentNullException(nameof(apiEndpoints));
|
||||
@ -212,6 +86,8 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
_webApiSettings = webApiOptions.Value;
|
||||
|
||||
_zzDataCmdService = zzDataCmdService ?? throw new ArgumentNullException(nameof(zzDataCmdService));
|
||||
|
||||
_planList = new Queue<SecondaryCircuitInspectionPlanStateModel>();
|
||||
|
||||
_singlePlanChannel = Channel.CreateUnbounded<SecondaryCircuitInspectionItemOutputEx>();
|
||||
@ -235,24 +111,32 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
while (true)
|
||||
{//每10分钟更新一下配置
|
||||
|
||||
await UpdatePlans();
|
||||
|
||||
await UpdateEventPlans();
|
||||
await UpdatePlanConfig();
|
||||
|
||||
//await CheckAiChannel();
|
||||
|
||||
await Task.Delay(TimeSpan.FromMinutes(10));
|
||||
//await Task.Delay(TimeSpan.FromMinutes(10));
|
||||
if(_getPlanListOk && _getEventPlanListOk)
|
||||
{
|
||||
_logger.LogWarning("SecondaryCircuitInspectionPlanService 获取配置信息成功!");
|
||||
break; //程序启动时,主动获取一次,之后有更新,会主动通知
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromMinutes(3));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await AppInit.WaitAsync(AppInit.DefaultTimeOut);
|
||||
|
||||
//检测计划
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{//每10秒检测一下计划
|
||||
{//每60秒检测一下计划
|
||||
|
||||
if (_updatedPlanOk)
|
||||
if (_getPlanListOk)
|
||||
{
|
||||
await CheckPlan();
|
||||
|
||||
@ -300,7 +184,15 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
await ExecutePlan(item);
|
||||
|
||||
await Task.Delay(500);
|
||||
if(item.Item.DeviceConfigCount > 0)
|
||||
{//需要判断定值的,间隔久一点
|
||||
await Task.Delay(TimeSpan.FromSeconds(60));
|
||||
}
|
||||
else
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(30));
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -327,11 +219,23 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
||||
public async Task UpdatePlanConfig()
|
||||
{
|
||||
_zzDataCmdService.ClearYcIds();
|
||||
|
||||
await UpdatePlans();
|
||||
await UpdateEventPlans();
|
||||
|
||||
}
|
||||
//更新计划
|
||||
private async Task UpdatePlans()
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
SecondaryCircuitInspectionPlanStateModel[] planList;
|
||||
|
||||
using (await _planLock.LockAsync())
|
||||
{
|
||||
var oldPlan = _planList.ToArray();
|
||||
@ -381,17 +285,21 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
//获取到绑定信息,可以更新全部状态了
|
||||
if (_planList.Count > 0)
|
||||
_updatedPlanOk = true;
|
||||
_getPlanListOk = true;
|
||||
|
||||
planList = _planList.ToArray();
|
||||
}
|
||||
|
||||
|
||||
_zzDataCmdService.AddCircuitPlanYcIds(planList);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_updatedPlanOk = false;
|
||||
_getPlanListOk = false;
|
||||
}
|
||||
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
@ -400,6 +308,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
SecondaryCircuitEventDrivenConfigOutput[] eventPlantList = null;
|
||||
|
||||
using (await _eventPlanLock.LockAsync())
|
||||
{
|
||||
@ -432,7 +341,12 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
//获取到绑定信息,可以更新全部状态了
|
||||
if (_eventPlanList.Count > 0)
|
||||
_getEventPlanListOk = true;
|
||||
|
||||
eventPlantList = _eventPlanList.ToArray();
|
||||
}
|
||||
|
||||
|
||||
_zzDataCmdService.AddEventPlanYcIds(eventPlantList);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -475,11 +389,16 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
foreach (var item in planList)
|
||||
{
|
||||
if (item.ExecuteTime == DateTime.MinValue && item.Plan.IsActive)
|
||||
bool debugCheck = false;
|
||||
//if (item.Plan.Name == "软压板巡检")
|
||||
//{
|
||||
// debugCheck = true;
|
||||
//}
|
||||
if (item.ExecuteTime == DateTime.MinValue && item.Plan.IsActive || debugCheck)
|
||||
{//当天未执行
|
||||
if (now.Hour == item.Plan.ScheduledHour && now.Minute == item.Plan.ScheduledMinute)
|
||||
if (now.Hour == item.Plan.ScheduledHour && now.Minute == item.Plan.ScheduledMinute || debugCheck)
|
||||
{
|
||||
if (item.Plan.ScheduledWeekDaysList.IndexOf(week) != -1)
|
||||
if (item.Plan.ScheduledWeekDaysList.IndexOf(week) != -1 || debugCheck)
|
||||
{
|
||||
await PushPlanToChannel(1, item.Plan);
|
||||
|
||||
@ -514,10 +433,21 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
string id = item.Id.ToString();
|
||||
|
||||
if(item.IsActive && !string.IsNullOrWhiteSpace(item.CalculationExpression) && !string.IsNullOrWhiteSpace(id))
|
||||
bool debugCheck = true;
|
||||
|
||||
//if (item.Name == "212馈线软压板 + 控制字一致性校验")
|
||||
//{
|
||||
// debugCheck = true;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// debugCheck = false;
|
||||
//}
|
||||
|
||||
if (debugCheck && item.IsActive && !string.IsNullOrWhiteSpace(item.CalculationExpression) && !string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
//写到队列里,由队列控制执行频率
|
||||
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(triggerType, item));
|
||||
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(triggerType, item, plan.Id.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -589,6 +519,15 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
if (item.DeviceConfigCount > 0)
|
||||
{
|
||||
settingData = await GetSourceDataAsync<List<DeviceDzData>>(id, 3);
|
||||
|
||||
if(settingData?.Count > 0)
|
||||
{
|
||||
_logger.LogWarning($"{DateTime.Now.ToString()}: 获取定值成功,id = {id}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogError($"{DateTime.Now.ToString()}: 获取定值失败,id = {id}");
|
||||
}
|
||||
}
|
||||
if (item.CameraPresetCount > 0)
|
||||
{
|
||||
@ -610,8 +549,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
jsData.StoreData.GatewayData = gatewayData;
|
||||
jsData.StoreData.VariantData = variantData;
|
||||
|
||||
if (jsData.StoreData.TelemetryData == null && jsData.StoreData.TeleSignalData == null && jsData.StoreData.SettingData == null &&
|
||||
jsData.StoreData.PresetData == null && jsData.StoreData.GatewayData == null && jsData.StoreData.VariantData == null)
|
||||
if (jsData.StoreData.IsAllDataNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -653,16 +591,36 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
saveData.ExecutionDurationMs = sw.ElapsedMilliseconds;
|
||||
saveData.TriggerType = itemEx.TriggerType;
|
||||
if (saveData.TriggerType == 1)
|
||||
saveData.InspectionPlanId = id;
|
||||
saveData.InspectionPlanId = itemEx.PlanId;
|
||||
else
|
||||
saveData.TriggerEventId = id;
|
||||
saveData.TriggerEventId = itemEx.PlanId;
|
||||
|
||||
saveData.Status = saveObj.Get("status").ToString();
|
||||
saveData.InspectionResult = saveObj.Get("inspectionResult").ToString();
|
||||
saveData.CalculationProcess = saveObj.Get("calculationProcess").ToString();
|
||||
saveData.VerificationResult = saveObj.Get("verificationResult").ToString();
|
||||
|
||||
|
||||
if (saveObj.HasProperty("data"))
|
||||
{//使用过滤后的数据:2025-12-09 王喜沟通
|
||||
engine.SetValue("data", saveObj.Get("data"));
|
||||
var dataJsonString = engine.Evaluate("JSON.stringify(data)").AsString();
|
||||
var model = JsonConvert.DeserializeObject<SecondaryCircuitInspectionJsDataModel>(dataJsonString);
|
||||
|
||||
if(model != null && model.StoreData != null && !model.StoreData.IsAllDataNull())
|
||||
{
|
||||
saveData.Data = model;
|
||||
}
|
||||
else
|
||||
{
|
||||
saveData.Data = jsData;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
saveData.Data = jsData;
|
||||
}
|
||||
|
||||
|
||||
var inspectionResultId = await _webApiRequest.SaveSecondaryCircuitInspectionPlanResultAsync(saveData);
|
||||
|
||||
@ -938,13 +896,13 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
planList = _eventPlanList.ToArray();
|
||||
}
|
||||
|
||||
foreach (var item in planList)
|
||||
foreach (var plan in planList)
|
||||
{
|
||||
await Task.Delay(item.DelayTriggerSeconds * 1000);
|
||||
await Task.Delay(plan.DelayTriggerSeconds * 1000);
|
||||
|
||||
if (item.IsActive && item.SecondaryCircuitInspectionEventItems?.Count > 0 && !string.IsNullOrWhiteSpace(item.TriggerExpression))
|
||||
if (plan.IsActive && plan.SecondaryCircuitInspectionEventItems?.Count > 0 && !string.IsNullOrWhiteSpace(plan.TriggerExpression))
|
||||
{
|
||||
string id = item.Id.ToString() ?? "";
|
||||
string id = plan.Id.ToString() ?? "";
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(id))
|
||||
{
|
||||
@ -957,13 +915,13 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
Task<List<ZzDataResultModel>>? t1 = null;
|
||||
Task<List<ZzDataResultModel>>? t2 = null;
|
||||
|
||||
if (item.TelemetryConfigs.Count > 0)
|
||||
if (plan.TelemetryConfigs.Count > 0)
|
||||
{
|
||||
t1 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 1);
|
||||
tasks.Add(t1);
|
||||
}
|
||||
|
||||
if (item.TelesignalConfigs.Count > 0)
|
||||
if (plan.TelesignalConfigs.Count > 0)
|
||||
{
|
||||
t2 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 2);
|
||||
tasks.Add(t2);
|
||||
@ -974,7 +932,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
if (t1 != null) jsData.StoreData.TelemetryData = await t1;
|
||||
if (t2 != null) jsData.StoreData.TeleSignalData = await t2;
|
||||
|
||||
engine.Execute(item.TriggerExpression);
|
||||
engine.Execute(plan.TriggerExpression);
|
||||
|
||||
bool canCheck = true;
|
||||
|
||||
@ -985,17 +943,17 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
if(canCheck)
|
||||
{
|
||||
await Task.Delay(item.MandatoryWaitSeconds * 1000);
|
||||
await Task.Delay(plan.MandatoryWaitSeconds * 1000);
|
||||
|
||||
//CheckPlanFormIds(item.SecondaryCircuitInspectionEventItems);
|
||||
|
||||
//执行巡检
|
||||
foreach(var planItem in item.SecondaryCircuitInspectionEventItems)
|
||||
foreach(var planItem in plan.SecondaryCircuitInspectionEventItems)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(planItem.CalculationExpression) && !string.IsNullOrWhiteSpace(planItem.Id.ToString()))
|
||||
{
|
||||
//写到队列里,由队列控制执行频率
|
||||
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(2, planItem));
|
||||
await _singlePlanChannel.Writer.WriteAsync(new SecondaryCircuitInspectionItemOutputEx(2, planItem, plan.Id.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,6 +103,9 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
//_cleanupTimer = new Timer(CleanupExpiredData, null, CLEANUP_INTERVAL_MS, CLEANUP_INTERVAL_MS);
|
||||
|
||||
_zzDataCacheContainer.SetTelemeteringHandle(this);
|
||||
|
||||
|
||||
ZzDataCache.SetDataCache(ZzDataCacheContainerDataType.eYC, _zzDataCacheContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -378,6 +381,12 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
//if(ycDataModel.YC_ID == "YCB001162001")
|
||||
//{
|
||||
// _logger.LogWarning($"{DateTime.Now.ToString()}: 收到{ycDataModel.YC_ID}遥测数据");
|
||||
//}
|
||||
|
||||
// 使用映射字典查找对应的haskey列表
|
||||
if (!_ycIdToHashKeysMapping.TryGetValue(ycDataModel.YC_ID, out List<string> haskeys))
|
||||
{
|
||||
@ -393,6 +402,13 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
if (parsedTime.Year>2000)
|
||||
{
|
||||
//if (ycDataModel.YC_ID == "YCB001209003")
|
||||
//if(ycDataModels.Count == 188)
|
||||
//if (ycDataModel.YC_ID == "YCB001112000")
|
||||
//{
|
||||
// _logger.LogWarning($"{resultTime.ToString()} : 收到遥测数据:Id = {ycDataModel.YC_ID}, Time = {parsedTime.ToString()}, 相差{(resultTime - parsedTime).TotalSeconds}秒");
|
||||
|
||||
//}
|
||||
resultTime = parsedTime;
|
||||
}
|
||||
}
|
||||
@ -669,7 +685,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
await InitAsync();
|
||||
}
|
||||
|
||||
var result = await _zzDataCacheContainer.Read(ids, seconds, timeWindowType, cancellationToken, now);
|
||||
var result = await _zzDataCacheContainer.Read(ids, seconds, timeWindowType, cancellationToken, now, true);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -695,6 +711,10 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
return null;
|
||||
}
|
||||
|
||||
public void LogWarning(string msg)
|
||||
{
|
||||
_logger.LogWarning(msg);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -127,7 +127,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
// 发送遥测召唤命令到TCP客户端
|
||||
bool ycResult = await _tcpClient.SendMessageAsync(ycCommand, cancellationToken);
|
||||
// 遥测和遥信命令之间间隔100毫秒
|
||||
await Task.Delay(100, cancellationToken);
|
||||
await Task.Delay(1000, cancellationToken);
|
||||
|
||||
// 构造遥信召唤命令:CallYXByDevice|{装置ID}
|
||||
string yxCommand = $"CallYXByDevice|{device.Id}";
|
||||
@ -135,7 +135,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
// 发送遥信召唤命令到TCP客户端
|
||||
bool yxResult = await _tcpClient.SendMessageAsync(yxCommand, cancellationToken);
|
||||
// 每个装置处理完成后间隔100毫秒
|
||||
await Task.Delay(100, cancellationToken);
|
||||
await Task.Delay(1000, cancellationToken);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -179,6 +179,9 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
// 执行遥测和遥信召唤
|
||||
await ExecuteTelemetryCallAsync(cancellationToken);
|
||||
|
||||
//召唤完成
|
||||
AppInit.MarkInitialized();
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
|
||||
@ -4,6 +4,7 @@ using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@ -77,6 +78,8 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
_webSocketPushService = webSocketPushService ?? throw new ArgumentNullException(nameof(webSocketPushService));
|
||||
_protectionDeviceCommInfoRedis = protectionDeviceCommInfoRedis ?? throw new ArgumentNullException(nameof(protectionDeviceCommInfoRedis));
|
||||
_webApiRequest = webApiRequest ?? throw new ArgumentNullException(nameof(webApiRequest));
|
||||
|
||||
ZzDataCache.SetDataCache(ZzDataCacheContainerDataType.eYX, _zzDataCacheContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -144,7 +147,6 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
if (_yxIdToHashKeyMapping.TryAdd(model.ismsbaseYXId, haskey))
|
||||
{
|
||||
mappingCount++;
|
||||
|
||||
//初始化
|
||||
_zzDataCacheContainer.Write(model.ismsbaseYXId, model.ResultValue, model.ResultTime, model.Name, model.ResultValueStr, model.DispatcherAddress);
|
||||
}
|
||||
@ -370,6 +372,12 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
break;
|
||||
}
|
||||
|
||||
//if (yxDataModel.YX_ID == "YXB001121065")
|
||||
//{
|
||||
// _logger.LogWarning($"YXB001121065: {yxDataModel.V}, {yxDataModel.T}");
|
||||
// Debug.WriteLine($"YXB001121065: {yxDataModel.V}, {yxDataModel.T}");
|
||||
//}
|
||||
|
||||
// 使用映射字典查找对应的haskey
|
||||
if (!_yxIdToHashKeyMapping.TryGetValue(yxDataModel.YX_ID, out string haskey))
|
||||
{
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,9 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
_webApiRequest = webApiRequest ?? throw new ArgumentNullException(nameof(webApiRequest));
|
||||
_zzDataCacheContainerInit = zzDataCacheContainerInit;
|
||||
_zzDataCacheContainerInit.InitVariantBaseinfo(_zzDataCacheContainer);
|
||||
|
||||
|
||||
ZzDataCache.SetDataCache(ZzDataCacheContainerDataType.eVA, _zzDataCacheContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@ -96,6 +96,11 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
.Select(x => x.point)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public ZzDataPoint GetCurrentData()
|
||||
{
|
||||
return new ZzDataPoint(TimeStamp, Value, ValueStr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -192,6 +197,20 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
data.AddData(new ZzDataPoint(time, val, valStr));
|
||||
}
|
||||
|
||||
public ZzDataPoint? ReadCurrentValue(string id, out ZzData? zzData)
|
||||
{
|
||||
if (_datas.TryGetValue(id, out var channel))
|
||||
{
|
||||
zzData = channel;
|
||||
return channel.GetCurrentData();
|
||||
}
|
||||
else
|
||||
{
|
||||
zzData = null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, ZzDataResultModel>> Read(List<string> ids, DateTime start, DateTime end)
|
||||
{
|
||||
var result = new Dictionary<string, ZzDataResultModel>();
|
||||
@ -213,30 +232,30 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
if (data.Data.Count == 0 && data.TimeStamp != DateTime.MinValue)
|
||||
{
|
||||
ZzDataPoint zzDataPoint = new ZzDataPoint(DateTime.Now, data.Value, data.ValueStr.Replace(" ", ""));
|
||||
ZzDataPoint zzDataPoint = new ZzDataPoint(DateTime.Now, data.Value, data.ValueStr);
|
||||
|
||||
data.Data.Add(zzDataPoint);
|
||||
}
|
||||
|
||||
if (_telemeteringHandle != null &&_dataType == ZzDataCacheContainerDataType.eYC && id == "YCB001103003")
|
||||
{
|
||||
if (data.Data.Where(e => Math.Abs(e.Value) < 0.0001).Count() == data.Data.Count)
|
||||
{
|
||||
string time = DateTime.Now.ToString("yyy/MM/dd HH:mm:ss");
|
||||
System.Console.WriteLine($"【{time}】: {id}所有值为0[{data.Data.Count}]:状态:{isFind}, Cache长度:{channel.Datas.Count}, Cache时间:{channel.StartTimeStamp.ToString("yyy/MM/dd HH:mm:ss")} ~ {channel.TimeStamp.ToString("yyy/MM/dd HH:mm:ss")}, 最后一个值:{channel.ValueStr}");
|
||||
//if (_telemeteringHandle != null &&_dataType == ZzDataCacheContainerDataType.eYC && id == "YCB001103003")
|
||||
//{
|
||||
// if (data.Data.Where(e => Math.Abs(e.Value) < 0.0001).Count() == data.Data.Count)
|
||||
// {
|
||||
// string time = DateTime.Now.ToString("yyy/MM/dd HH:mm:ss");
|
||||
// _telemeteringHandle.LogWarning($"【{time}】: {id}所有值为0[{data.Data.Count}]:状态:{isFind}, Cache长度:{channel.Datas.Count}, Cache时间:{channel.StartTimeStamp.ToString("yyy/MM/dd HH:mm:ss")} ~ {channel.TimeStamp.ToString("yyy/MM/dd HH:mm:ss")}, 最后一个值:{channel.ValueStr}");
|
||||
|
||||
var redisData = await _telemeteringHandle.GetDataFromRedis(id);
|
||||
if (redisData != null)
|
||||
{
|
||||
System.Console.WriteLine($"【{time}】: {id}在Redis中的值为:{redisData.ResultValue} - {redisData.ResultTime }");
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Console.WriteLine($"【{time}】: {id}在Redis中没有找到");
|
||||
}
|
||||
// var redisData = await _telemeteringHandle.GetDataFromRedis(id);
|
||||
// if (redisData != null)
|
||||
// {
|
||||
// _telemeteringHandle.LogWarning($"【{time}】: {id}在Redis中的值为:{redisData.ResultValue} - {redisData.ResultTime }");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _telemeteringHandle.LogWarning($"【{time}】: {id}在Redis中没有找到");
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
// }
|
||||
//}
|
||||
|
||||
result[id] = data;
|
||||
|
||||
@ -246,7 +265,7 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<List<ZzDataResultModel>> Read(List<string> ids, int seconds, int timeWindowType, CancellationToken cancellationToken, DateTime now = default)
|
||||
public async Task<List<ZzDataResultModel>> Read(List<string> ids, int seconds, int timeWindowType, CancellationToken cancellationToken, DateTime now = default, bool forceCorrectCount = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
@ -259,7 +278,40 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
if (timeWindowType == 0 || timeWindowType == 2)
|
||||
{
|
||||
matched1 = await Read(ids, now.AddSeconds(-seconds), now);
|
||||
DateTime startTime = now.AddSeconds(-seconds);
|
||||
|
||||
|
||||
for(int i = 0; i < seconds; i++)
|
||||
{
|
||||
matched1 = await Read(ids, startTime, now);
|
||||
|
||||
//要保证有多少秒,就至少有多少个点
|
||||
if (forceCorrectCount)
|
||||
{
|
||||
bool isCountCorrect = true;
|
||||
|
||||
foreach (var item in matched1)
|
||||
{
|
||||
if (item.Value.Data.Count < seconds)
|
||||
{
|
||||
isCountCorrect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCountCorrect)
|
||||
break;
|
||||
else
|
||||
{
|
||||
startTime = startTime.AddSeconds(-3);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (timeWindowType == 1 || timeWindowType == 2)
|
||||
@ -268,7 +320,41 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
|
||||
if(span > 0)
|
||||
await Task.Delay(span, cancellationToken);
|
||||
|
||||
for(int i = 0; i < seconds; i++)
|
||||
{
|
||||
|
||||
matched2 = await Read(ids, now, DateTime.Now);
|
||||
|
||||
//要保证有多少秒,就至少有多少个点
|
||||
if (forceCorrectCount)
|
||||
{
|
||||
bool isCountCorrect = true;
|
||||
|
||||
foreach (var item in matched2)
|
||||
{
|
||||
if (item.Value.Data.Count < seconds)
|
||||
{
|
||||
isCountCorrect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isCountCorrect)
|
||||
break;
|
||||
else
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(2), cancellationToken);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
foreach (var kv in matched2)
|
||||
@ -288,6 +374,27 @@ namespace YunDa.Server.ISMSTcp.Services
|
||||
}
|
||||
}
|
||||
|
||||
public static class ZzDataCache
|
||||
{
|
||||
private static readonly ConcurrentDictionary<ZzDataCacheContainerDataType, ZzDataCacheContainer> _datas = new ConcurrentDictionary<ZzDataCacheContainerDataType, ZzDataCacheContainer>();
|
||||
|
||||
public static void SetDataCache(ZzDataCacheContainerDataType type, ZzDataCacheContainer cache)
|
||||
{
|
||||
_datas.TryAdd(type, cache);
|
||||
}
|
||||
public static ZzDataCacheContainer? GetDataCache(ZzDataCacheContainerDataType type)
|
||||
{
|
||||
if(_datas.TryGetValue(type, out ZzDataCacheContainer cache))
|
||||
{
|
||||
return cache;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ZzDataCacheContainerInit
|
||||
{
|
||||
private readonly ILogger<SecondaryCircuitInspectionPlanService> _logger;
|
||||
|
||||
@ -0,0 +1,249 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using YunDa.Server.ISMSTcp.Domain;
|
||||
using YunDa.Server.ISMSTcp.Interfaces;
|
||||
using YunDa.Server.ISMSTcp.Models;
|
||||
using YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspection.Configurations;
|
||||
|
||||
namespace YunDa.Server.ISMSTcp.Services
|
||||
{
|
||||
public class YcIdExInfo
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string DeviceId { get; set; } = string.Empty;
|
||||
public bool DeviceCommState { get; set; } = true;
|
||||
|
||||
public YcIdExInfo(string id)
|
||||
{
|
||||
Id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class ZzDataIdList
|
||||
{
|
||||
private ConcurrentDictionary<string, YcIdExInfo> _ids = new ConcurrentDictionary<string, YcIdExInfo>();
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_ids.Clear();
|
||||
}
|
||||
|
||||
public bool AddId(string id)
|
||||
{
|
||||
return _ids.TryAdd(id, new YcIdExInfo(id));
|
||||
}
|
||||
public void AddIds(string ids, string keyword, string separator)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ids))
|
||||
return;
|
||||
|
||||
string[] list = ids.Trim().Split(separator);
|
||||
foreach (string id in list)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(id))
|
||||
continue;
|
||||
|
||||
if(id.Contains(keyword))
|
||||
_ids.TryAdd(id, new YcIdExInfo(id));
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateDeviceCommState(string deviceId, bool commState)
|
||||
{
|
||||
foreach (var yc in _ids.Values)
|
||||
{
|
||||
if (yc.Id.Contains(deviceId))
|
||||
{
|
||||
yc.DeviceCommState = commState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetIds(bool? commState)
|
||||
{
|
||||
if(commState.HasValue)
|
||||
return _ids.Where(kvp => kvp.Value.DeviceCommState == commState)
|
||||
.Select(kvp => kvp.Key)
|
||||
.ToList();
|
||||
else
|
||||
return _ids.Keys.ToList();
|
||||
}
|
||||
}
|
||||
public class ZzDataCmdService
|
||||
{
|
||||
|
||||
private readonly ILogger<ZzDataCmdService> _logger;
|
||||
private readonly ZzTcpService _zTcpService = null;
|
||||
|
||||
private ZzDataIdList _ycIds = new ZzDataIdList();
|
||||
|
||||
public ZzDataCmdService(
|
||||
ILogger<ZzDataCmdService> logger,
|
||||
ZzTcpService zTcpService)
|
||||
{
|
||||
_logger = logger;
|
||||
_zTcpService = zTcpService;
|
||||
|
||||
StartAsync();
|
||||
}
|
||||
|
||||
private async Task StartAsync()
|
||||
{
|
||||
await AppInit.WaitAsync(AppInit.DefaultTimeOut);
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{//每秒发送一次命令
|
||||
|
||||
await SendYcCmd();
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
||||
}
|
||||
});
|
||||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{//每30秒发送一次命令
|
||||
|
||||
await SendVaCmd();
|
||||
|
||||
await Task.Delay(TimeSpan.FromSeconds(30));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private List<string> GetValidZzCmd(string cmdName, List<string> ids)
|
||||
{
|
||||
const int maxLength = 25000;
|
||||
|
||||
var cmds = new List<string>();
|
||||
|
||||
// 开始构建
|
||||
string prefix = cmdName + "|"; // 固定前缀
|
||||
int prefixLength = prefix.Length;
|
||||
|
||||
var currentIds = new List<string>();
|
||||
int currentLength = prefixLength; // 当前命令的长度(含前缀)
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
// 如果添加这个ID会超长,则先生成一个命令
|
||||
int idLength = (currentIds.Count == 0 ? id.Length : (1 + id.Length)); // 第一个ID不需要 '#'
|
||||
|
||||
if (currentLength + idLength > maxLength)
|
||||
{
|
||||
// 将当前批次加入 cmds
|
||||
cmds.Add(prefix + string.Join("#", currentIds));
|
||||
|
||||
// 清空并重建
|
||||
currentIds.Clear();
|
||||
currentLength = prefixLength;
|
||||
}
|
||||
|
||||
// 添加新的 ID
|
||||
currentIds.Add(id);
|
||||
currentLength += idLength;
|
||||
}
|
||||
|
||||
// 收尾:如果还有剩余 IDs,生成最后一个命令
|
||||
if (currentIds.Count > 0)
|
||||
{
|
||||
cmds.Add(prefix + string.Join("#", currentIds));
|
||||
}
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
//更新装置状态
|
||||
public void UpdateDeviceCommState(string deviceId, bool commState)
|
||||
{
|
||||
_ycIds.UpdateDeviceCommState(deviceId, commState);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/////遥测
|
||||
|
||||
public void ClearYcIds()
|
||||
{
|
||||
_ycIds.Clear();
|
||||
}
|
||||
|
||||
//计划巡检配置
|
||||
public void AddCircuitPlanYcIds(SecondaryCircuitInspectionPlanStateModel[] planList)
|
||||
{
|
||||
foreach (var plan in planList)
|
||||
{
|
||||
foreach(var inspection in plan.Plan.InspectionItems)
|
||||
{
|
||||
foreach (var item in inspection.TelemetryConfigs)
|
||||
{
|
||||
if(!string.IsNullOrWhiteSpace(item.TelemetryConfigurationIsmsId) && item.TelemetryConfigurationIsmsId.StartsWith("YC"))
|
||||
_ycIds.AddId(item.TelemetryConfigurationIsmsId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//事件巡检配置
|
||||
public void AddEventPlanYcIds(SecondaryCircuitEventDrivenConfigOutput[] planList)
|
||||
{
|
||||
foreach (var plan in planList)
|
||||
{
|
||||
foreach(var item in plan.TelemetryConfigs)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.TelemetryConfigurationIsmsId) && item.TelemetryConfigurationIsmsId.StartsWith("YC"))
|
||||
_ycIds.AddId(item.TelemetryConfigurationIsmsId);
|
||||
}
|
||||
|
||||
foreach (var inspection in plan.SecondaryCircuitInspectionEventItems)
|
||||
{
|
||||
foreach (var item in inspection.TelemetryConfigs)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.TelemetryConfigurationIsmsId) && item.TelemetryConfigurationIsmsId.StartsWith("YC"))
|
||||
_ycIds.AddId(item.TelemetryConfigurationIsmsId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _sendCnt = 0;
|
||||
private async Task SendYcCmd()
|
||||
{
|
||||
var ids = _ycIds.GetIds(null);
|
||||
var cmds = GetValidZzCmd("CallYCByDataID", ids);
|
||||
|
||||
|
||||
foreach (var cmd in cmds)
|
||||
{
|
||||
await _zTcpService.SendTcpMessageAsync(cmd, CancellationToken.None);
|
||||
|
||||
if(_sendCnt % 60 == 0)
|
||||
_logger.LogWarning($"发送命令:{ids.Count}个id");
|
||||
|
||||
_sendCnt++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private async Task SendVaCmd()
|
||||
{
|
||||
string cmd = "CallVAByStat|B001";
|
||||
await _zTcpService.SendTcpMessageAsync(cmd, CancellationToken.None);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user