修改了二次回路巡检的一些问题

This commit is contained in:
guorui 2025-12-02 13:49:02 +08:00
parent 4d4da8ac2b
commit c9e3609369
17 changed files with 381 additions and 217 deletions

View File

@ -48,6 +48,8 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
private readonly IRepository<SecondaryCircuitInspectionEventItem, Guid> _inspectionEventItemRepository; private readonly IRepository<SecondaryCircuitInspectionEventItem, Guid> _inspectionEventItemRepository;
private readonly IRepository<SecondaryCircuitInspectionTelemetryConfig, Guid> _telemetryConfigRepository; private readonly IRepository<SecondaryCircuitInspectionTelemetryConfig, Guid> _telemetryConfigRepository;
private readonly IRepository<SecondaryCircuitInspectionTelesignalConfig, Guid> _telesignalConfigRepository; private readonly IRepository<SecondaryCircuitInspectionTelesignalConfig, Guid> _telesignalConfigRepository;
private readonly IRepository<TelemeteringConfiguration, Guid> _telemeteringConfigurationRepository;
private readonly IRepository<TelesignalisationConfiguration, Guid> _telesignalisationConfigurationRepository;
private readonly IRedisRepository<TelemeteringModel, string> _telemeteringRedisRepository; private readonly IRedisRepository<TelemeteringModel, string> _telemeteringRedisRepository;
private readonly IRedisRepository<TelesignalisationModel, string> _telesignalisationRedisRepository; private readonly IRedisRepository<TelesignalisationModel, string> _telesignalisationRedisRepository;
private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository; private readonly IRepository<EquipmentInfo, Guid> _equipmentInfoRepository;
@ -75,6 +77,8 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
IRepository<SecondaryCircuitInspectionEventItem, Guid> inspectionEventItemRepository, IRepository<SecondaryCircuitInspectionEventItem, Guid> inspectionEventItemRepository,
IRepository<SecondaryCircuitInspectionTelemetryConfig, Guid> telemetryConfigRepository, IRepository<SecondaryCircuitInspectionTelemetryConfig, Guid> telemetryConfigRepository,
IRepository<SecondaryCircuitInspectionTelesignalConfig, Guid> telesignalConfigRepository, IRepository<SecondaryCircuitInspectionTelesignalConfig, Guid> telesignalConfigRepository,
IRepository<TelemeteringConfiguration, Guid> telemeteringConfigurationRepository,
IRepository<TelesignalisationConfiguration, Guid> telesignalisationConfigurationRepository,
IRedisRepository<TelemeteringModel, string> telemeteringRedisRepository, IRedisRepository<TelemeteringModel, string> telemeteringRedisRepository,
IRedisRepository<TelesignalisationModel, string> telesignalisationRedisRepository, IRedisRepository<TelesignalisationModel, string> telesignalisationRedisRepository,
IRepository<EquipmentInfo, Guid> equipmentInfoRepository, IRepository<EquipmentInfo, Guid> equipmentInfoRepository,
@ -88,6 +92,8 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
_inspectionEventItemRepository = inspectionEventItemRepository; _inspectionEventItemRepository = inspectionEventItemRepository;
_telemetryConfigRepository = telemetryConfigRepository; _telemetryConfigRepository = telemetryConfigRepository;
_telesignalConfigRepository = telesignalConfigRepository; _telesignalConfigRepository = telesignalConfigRepository;
_telemeteringConfigurationRepository = telemeteringConfigurationRepository;
_telesignalisationConfigurationRepository = telesignalisationConfigurationRepository;
_telemeteringRedisRepository = telemeteringRedisRepository; _telemeteringRedisRepository = telemeteringRedisRepository;
_telesignalisationRedisRepository = telesignalisationRedisRepository; _telesignalisationRedisRepository = telesignalisationRedisRepository;
_equipmentInfoRepository = equipmentInfoRepository; _equipmentInfoRepository = equipmentInfoRepository;
@ -946,22 +952,8 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
RequestPageResult<SecondaryCircuitEventDrivenConfigOutput> rst = new RequestPageResult<SecondaryCircuitEventDrivenConfigOutput>(); RequestPageResult<SecondaryCircuitEventDrivenConfigOutput> rst = new RequestPageResult<SecondaryCircuitEventDrivenConfigOutput>();
try try
{ {
// Build query with eager loading of related entities // Step 1: Build query for main entities WITHOUT joins
var query = _eventDrivenConfigRepository.GetAll() var query = _eventDrivenConfigRepository.GetAll();
.Include(x => x.SecondaryCircuitInspectionEventItems)
.ThenInclude(t => t.InspectionItem)
.ThenInclude(t => t.TelemetryConfigs)
.ThenInclude(t => t.TelemeteringConfiguration)
.Include(x => x.SecondaryCircuitInspectionEventItems)
.ThenInclude(t => t.InspectionItem)
.ThenInclude(t => t.TelesignalConfigs)
.ThenInclude(t => t.TelesignalisationConfiguration)
.Include(x => x.TelemetryConfigs)
.ThenInclude(t => t.TelemeteringConfiguration)
.Include(x => x.TelesignalConfigs)
.ThenInclude(t => t.TelesignalisationConfiguration)
.AsQueryable()
;
// Apply search conditions // Apply search conditions
if (input.SearchCondition != null) if (input.SearchCondition != null)
@ -996,103 +988,244 @@ namespace YunDa.SOMS.Application.DataMonitoring.SecondaryCircuitInspection
query = query.PageBy(skipCount, input.PageSize); query = query.PageBy(skipCount, input.PageSize);
} }
// Execute query to get main entities
var entities = await query.ToListAsync(cancellationToken).ConfigureAwait(false); var entities = await query.ToListAsync(cancellationToken).ConfigureAwait(false);
// Load equipment info dictionary for efficient lookups if (!entities.Any())
var equipmentInfoDict = await _equipmentInfoRepository.GetAll() {
.ToDictionaryAsync(e => e.Id, e => e.Name, cancellationToken) rst.PageSize = input.PageSize;
rst.PageIndex = input.PageIndex;
rst.TotalCount = totalCount;
rst.Flag = true;
rst.ResultData = new List<SecondaryCircuitEventDrivenConfigOutput>();
return rst;
}
// Step 2: Collect all IDs for subsequent queries
var configIds = entities.Select(e => e.Id).ToList();
// Step 3: Query SecondaryCircuitInspectionEventItems for these configs
var eventItems = await _inspectionEventItemRepository.GetAll()
.Where(ei => configIds.Contains(ei.InpectionEventDrivenId.Value))
.ToListAsync(cancellationToken)
.ConfigureAwait(false); .ConfigureAwait(false);
// Map entities to output DTOs var inspectionItemIds = eventItems
.Where(ei => ei.InspectionItemId.HasValue)
.Select(ei => ei.InspectionItemId.Value)
.Distinct()
.ToList();
// Step 4: Query InspectionItems
var inspectionItems = inspectionItemIds.Any()
? await _inspectionItemRepository.GetAll()
.Where(ii => inspectionItemIds.Contains(ii.Id))
.ToListAsync(cancellationToken)
.ConfigureAwait(false)
: new List<SecondaryCircuitInspectionItem>();
// Step 5: Query TelemetryConfigs (both from EventDrivenConfig and InspectionItems)
var telemetryConfigs = await _telemetryConfigRepository.GetAll()
.Where(tc => configIds.Contains(tc.SecondaryCircuitEventDrivenConfigId.Value) ||
inspectionItemIds.Contains(tc.SecondaryCircuitInspectionItemId.Value))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
var telemetryConfigIds = telemetryConfigs
.Where(tc => tc.TelemetryConfigurationId.HasValue)
.Select(tc => tc.TelemetryConfigurationId.Value)
.Distinct()
.ToList();
// Step 6: Query TelesignalConfigs (both from EventDrivenConfig and InspectionItems)
var telesignalConfigs = await _telesignalConfigRepository.GetAll()
.Where(tc => configIds.Contains(tc.SecondaryCircuitEventDrivenConfigId.Value) ||
inspectionItemIds.Contains(tc.SecondaryCircuitInspectionItemId.Value))
.ToListAsync(cancellationToken)
.ConfigureAwait(false);
var telesignalConfigIds = telesignalConfigs
.Where(tc => tc.TelesignalConfigurationId.HasValue)
.Select(tc => tc.TelesignalConfigurationId.Value)
.Distinct()
.ToList();
// Step 7: Query TelemeteringConfiguration entities
var telemeteringConfigurations = telemetryConfigIds.Any()
? await _telemeteringConfigurationRepository.GetAll()
.Where(tc => telemetryConfigIds.Contains(tc.Id))
.ToListAsync(cancellationToken)
.ConfigureAwait(false)
: new List<TelemeteringConfiguration>();
// Step 8: Query TelesignalisationConfiguration entities
var telesignalisationConfigurations = telesignalConfigIds.Any()
? await _telesignalisationConfigurationRepository.GetAll()
.Where(tc => telesignalConfigIds.Contains(tc.Id))
.ToListAsync(cancellationToken)
.ConfigureAwait(false)
: new List<TelesignalisationConfiguration>();
// Step 9: Get all equipment IDs and load equipment info dictionary
var equipmentIds = telemeteringConfigurations
.Where(tc => tc.EquipmentInfoId.HasValue)
.Select(tc => tc.EquipmentInfoId.Value)
.Concat(telesignalisationConfigurations
.Where(tc => tc.EquipmentInfoId.HasValue)
.Select(tc => tc.EquipmentInfoId.Value))
.Distinct()
.ToList();
var equipmentInfoDict = equipmentIds.Any()
? await _equipmentInfoRepository.GetAll()
.Where(e => equipmentIds.Contains(e.Id))
.ToDictionaryAsync(e => e.Id, e => e.Name, cancellationToken)
.ConfigureAwait(false)
: new Dictionary<Guid, string>();
// Step 10: Create lookup dictionaries for efficient in-memory correlation
var telemeteringConfigDict = telemeteringConfigurations.ToDictionary(tc => tc.Id);
var telesignalisationConfigDict = telesignalisationConfigurations.ToDictionary(tc => tc.Id);
var inspectionItemDict = inspectionItems.ToDictionary(ii => ii.Id);
var eventItemsByConfigId = eventItems
.Where(ei => ei.InpectionEventDrivenId.HasValue)
.GroupBy(ei => ei.InpectionEventDrivenId.Value)
.ToDictionary(g => g.Key, g => g.ToList());
var telemetryConfigsByEventConfigId = telemetryConfigs
.Where(tc => tc.SecondaryCircuitEventDrivenConfigId.HasValue)
.GroupBy(tc => tc.SecondaryCircuitEventDrivenConfigId.Value)
.ToDictionary(g => g.Key, g => g.ToList());
var telemetryConfigsByInspectionItemId = telemetryConfigs
.Where(tc => tc.SecondaryCircuitInspectionItemId.HasValue)
.GroupBy(tc => tc.SecondaryCircuitInspectionItemId.Value)
.ToDictionary(g => g.Key, g => g.ToList());
var telesignalConfigsByEventConfigId = telesignalConfigs
.Where(tc => tc.SecondaryCircuitEventDrivenConfigId.HasValue)
.GroupBy(tc => tc.SecondaryCircuitEventDrivenConfigId.Value)
.ToDictionary(g => g.Key, g => g.ToList());
var telesignalConfigsByInspectionItemId = telesignalConfigs
.Where(tc => tc.SecondaryCircuitInspectionItemId.HasValue)
.GroupBy(tc => tc.SecondaryCircuitInspectionItemId.Value)
.ToDictionary(g => g.Key, g => g.ToList());
// Step 11: Map entities to output DTOs using in-memory correlation
var outputList = new List<SecondaryCircuitEventDrivenConfigOutput>(); var outputList = new List<SecondaryCircuitEventDrivenConfigOutput>();
foreach (var entity in entities) foreach (var entity in entities)
{ {
var output = ObjectMapper.Map<SecondaryCircuitEventDrivenConfigOutput>(entity); var output = ObjectMapper.Map<SecondaryCircuitEventDrivenConfigOutput>(entity);
output.SecondaryCircuitInspectionEventItems = ObjectMapper.Map<List<SecondaryCircuitInspectionItemOutput>>(
entity.SecondaryCircuitInspectionEventItems.Select(t => t.InspectionItem));
// Enrich nested inspection items with telemetry and telesignal config details // Get event items for this config
foreach (var eventItem in entity.SecondaryCircuitInspectionEventItems) var configEventItems = eventItemsByConfigId.ContainsKey(entity.Id)
? eventItemsByConfigId[entity.Id]
: new List<SecondaryCircuitInspectionEventItem>();
// Map inspection items
var inspectionItemOutputs = new List<SecondaryCircuitInspectionItemOutput>();
foreach (var eventItem in configEventItems)
{ {
if (eventItem.InspectionItem == null) continue; if (!eventItem.InspectionItemId.HasValue || !inspectionItemDict.ContainsKey(eventItem.InspectionItemId.Value))
continue;
var outputItem = output.SecondaryCircuitInspectionEventItems.FirstOrDefault(x => x.Id == eventItem.InspectionItem.Id); var inspectionItem = inspectionItemDict[eventItem.InspectionItemId.Value];
if (outputItem == null) continue; var inspectionItemOutput = ObjectMapper.Map<SecondaryCircuitInspectionItemOutput>(inspectionItem);
// Enrich telemetry configs for nested inspection item // Get telemetry configs for this inspection item
if (eventItem.InspectionItem.TelemetryConfigs != null && eventItem.InspectionItem.TelemetryConfigs.Any()) var itemTelemetryConfigs = telemetryConfigsByInspectionItemId.ContainsKey(inspectionItem.Id)
? telemetryConfigsByInspectionItemId[inspectionItem.Id]
: new List<SecondaryCircuitInspectionTelemetryConfig>();
inspectionItemOutput.TelemetryConfigs = itemTelemetryConfigs
.Where(tc => tc.TelemetryConfigurationId.HasValue && telemeteringConfigDict.ContainsKey(tc.TelemetryConfigurationId.Value))
.Select(tc =>
{
var telemetryConfig = telemeteringConfigDict[tc.TelemetryConfigurationId.Value];
return new SecondaryCircuitInspectionTelemetryConfigOutput
{
Id = tc.Id,
EquipmentInfoId = telemetryConfig.EquipmentInfoId ?? Guid.Empty,
EquipmentInfoName = telemetryConfig.EquipmentInfoId.HasValue && equipmentInfoDict.ContainsKey(telemetryConfig.EquipmentInfoId.Value)
? equipmentInfoDict[telemetryConfig.EquipmentInfoId.Value]
: string.Empty,
TelemetryConfigurationId = tc.TelemetryConfigurationId ?? Guid.Empty,
TelemetryConfigurationName = telemetryConfig.Name,
TelemetryConfigurationIsmsId = telemetryConfig.ismsbaseYCId
};
}).ToList();
inspectionItemOutput.TelemetryConfigCount = inspectionItemOutput.TelemetryConfigs.Count;
// Get telesignal configs for this inspection item
var itemTelesignalConfigs = telesignalConfigsByInspectionItemId.ContainsKey(inspectionItem.Id)
? telesignalConfigsByInspectionItemId[inspectionItem.Id]
: new List<SecondaryCircuitInspectionTelesignalConfig>();
inspectionItemOutput.TelesignalConfigs = itemTelesignalConfigs
.Where(tc => tc.TelesignalConfigurationId.HasValue && telesignalisationConfigDict.ContainsKey(tc.TelesignalConfigurationId.Value))
.Select(tc =>
{
var telesignalConfig = telesignalisationConfigDict[tc.TelesignalConfigurationId.Value];
return new SecondaryCircuitInspectionTelesignalConfigOutput
{
Id = tc.Id,
EquipmentInfoId = telesignalConfig.EquipmentInfoId ?? Guid.Empty,
EquipmentInfoName = telesignalConfig.EquipmentInfoId.HasValue && equipmentInfoDict.ContainsKey(telesignalConfig.EquipmentInfoId.Value)
? equipmentInfoDict[telesignalConfig.EquipmentInfoId.Value]
: string.Empty,
TelesignalConfigurationId = tc.TelesignalConfigurationId ?? Guid.Empty,
TelesignalConfigurationName = telesignalConfig.Name,
TelesignalConfigurationIsmsId = telesignalConfig.ismsbaseYXId
};
}).ToList();
inspectionItemOutput.TelesignalConfigCount = inspectionItemOutput.TelesignalConfigs.Count;
inspectionItemOutputs.Add(inspectionItemOutput);
}
output.SecondaryCircuitInspectionEventItems = inspectionItemOutputs;
// Map telemetry configs directly associated with event driven config
var configTelemetryConfigs = telemetryConfigsByEventConfigId.ContainsKey(entity.Id)
? telemetryConfigsByEventConfigId[entity.Id]
: new List<SecondaryCircuitInspectionTelemetryConfig>();
output.TelemetryConfigs = configTelemetryConfigs
.Where(tc => tc.TelemetryConfigurationId.HasValue && telemeteringConfigDict.ContainsKey(tc.TelemetryConfigurationId.Value))
.Select(tc =>
{ {
outputItem.TelemetryConfigs = eventItem.InspectionItem.TelemetryConfigs.Select(tc => new SecondaryCircuitInspectionTelemetryConfigOutput var telemetryConfig = telemeteringConfigDict[tc.TelemetryConfigurationId.Value];
return new SecondaryCircuitInspectionTelemetryConfigOutput
{ {
Id = tc.Id, Id = tc.Id,
EquipmentInfoId = tc.TelemeteringConfiguration.EquipmentInfoId.Value, EquipmentInfoId = telemetryConfig.EquipmentInfoId ?? Guid.Empty,
EquipmentInfoName = equipmentInfoDict.ContainsKey(tc.TelemeteringConfiguration.EquipmentInfoId.Value) EquipmentInfoName = telemetryConfig.EquipmentInfoId.HasValue && equipmentInfoDict.ContainsKey(telemetryConfig.EquipmentInfoId.Value)
? equipmentInfoDict[tc.TelemeteringConfiguration.EquipmentInfoId.Value] ? equipmentInfoDict[telemetryConfig.EquipmentInfoId.Value]
: string.Empty, : string.Empty,
TelemetryConfigurationId = tc.TelemetryConfigurationId ?? Guid.Empty, TelemetryConfigurationId = tc.TelemetryConfigurationId ?? Guid.Empty,
TelemetryConfigurationName = tc.TelemeteringConfiguration?.Name, TelemetryConfigurationName = telemetryConfig.Name,
TelemetryConfigurationIsmsId = tc.TelemeteringConfiguration?.ismsbaseYCId TelemetryConfigurationIsmsId = telemetryConfig.ismsbaseYCId
}).ToList(); };
outputItem.TelemetryConfigCount = outputItem.TelemetryConfigs.Count; }).ToList();
}
// Enrich telesignal configs for nested inspection item // Map telesignal configs directly associated with event driven config
if (eventItem.InspectionItem.TelesignalConfigs != null && eventItem.InspectionItem.TelesignalConfigs.Any()) var configTelesignalConfigs = telesignalConfigsByEventConfigId.ContainsKey(entity.Id)
? telesignalConfigsByEventConfigId[entity.Id]
: new List<SecondaryCircuitInspectionTelesignalConfig>();
output.TelesignalConfigs = configTelesignalConfigs
.Where(tc => tc.TelesignalConfigurationId.HasValue && telesignalisationConfigDict.ContainsKey(tc.TelesignalConfigurationId.Value))
.Select(tc =>
{ {
outputItem.TelesignalConfigs = eventItem.InspectionItem.TelesignalConfigs.Select(tc => new SecondaryCircuitInspectionTelesignalConfigOutput var telesignalConfig = telesignalisationConfigDict[tc.TelesignalConfigurationId.Value];
return new SecondaryCircuitInspectionTelesignalConfigOutput
{ {
Id = tc.Id, Id = tc.Id,
EquipmentInfoId = tc.TelesignalisationConfiguration.EquipmentInfoId.Value, EquipmentInfoId = telesignalConfig.EquipmentInfoId ?? Guid.Empty,
EquipmentInfoName = equipmentInfoDict.ContainsKey(tc.TelesignalisationConfiguration.EquipmentInfoId.Value) EquipmentInfoName = telesignalConfig.EquipmentInfoId.HasValue && equipmentInfoDict.ContainsKey(telesignalConfig.EquipmentInfoId.Value)
? equipmentInfoDict[tc.TelesignalisationConfiguration.EquipmentInfoId.Value] ? equipmentInfoDict[telesignalConfig.EquipmentInfoId.Value]
: string.Empty, : string.Empty,
TelesignalConfigurationId = tc.TelesignalConfigurationId ?? Guid.Empty, TelesignalConfigurationId = tc.TelesignalConfigurationId ?? Guid.Empty,
TelesignalConfigurationName = tc.TelesignalisationConfiguration?.Name, TelesignalConfigurationName = telesignalConfig.Name,
TelesignalConfigurationIsmsId = tc.TelesignalisationConfiguration?.ismsbaseYXId TelesignalConfigurationIsmsId = telesignalConfig.ismsbaseYXId
}).ToList(); };
outputItem.TelesignalConfigCount = outputItem.TelesignalConfigs.Count;
}
}
// Map telemetry configs
if (entity.TelemetryConfigs != null && entity.TelemetryConfigs.Any())
{
output.TelemetryConfigs = entity.TelemetryConfigs.Select(tc => new SecondaryCircuitInspectionTelemetryConfigOutput
{
Id = tc.Id,
EquipmentInfoId = tc.TelemeteringConfiguration.EquipmentInfoId.Value,
EquipmentInfoName = equipmentInfoDict.ContainsKey(tc.TelemeteringConfiguration.EquipmentInfoId.Value)
? equipmentInfoDict[tc.TelemeteringConfiguration.EquipmentInfoId.Value]
: string.Empty,
TelemetryConfigurationId = tc.TelemetryConfigurationId ?? Guid.Empty,
TelemetryConfigurationName = tc.TelemeteringConfiguration?.Name,
TelemetryConfigurationIsmsId = tc.TelemeteringConfiguration?.ismsbaseYCId
}).ToList(); }).ToList();
}
else
{
output.TelemetryConfigs = new List<SecondaryCircuitInspectionTelemetryConfigOutput>();
}
// Map telesignal configs
if (entity.TelesignalConfigs != null && entity.TelesignalConfigs.Any())
{
output.TelesignalConfigs = entity.TelesignalConfigs.Select(tc => new SecondaryCircuitInspectionTelesignalConfigOutput
{
Id = tc.Id,
EquipmentInfoId = tc.TelesignalisationConfiguration.EquipmentInfoId.Value,
EquipmentInfoName = equipmentInfoDict.ContainsKey(tc.TelesignalisationConfiguration.EquipmentInfoId.Value)
? equipmentInfoDict[tc.TelesignalisationConfiguration.EquipmentInfoId.Value]
: string.Empty,
TelesignalConfigurationId = tc.TelesignalConfigurationId ?? Guid.Empty,
TelesignalConfigurationName = tc.TelesignalisationConfiguration?.Name,
TelesignalConfigurationIsmsId = tc.TelesignalisationConfiguration?.ismsbaseYXId
}).ToList();
}
else
{
output.TelesignalConfigs = new List<SecondaryCircuitInspectionTelesignalConfigOutput>();
}
outputList.Add(output); outputList.Add(output);
} }

View File

@ -28,6 +28,7 @@ using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.DataMonitoring; using YunDa.SOMS.Entities.DataMonitoring;
using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo; using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.GeneralInformation; using YunDa.SOMS.Entities.GeneralInformation;
using JsonException = System.Text.Json.JsonException;
namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
{ {

View File

@ -29,6 +29,7 @@ using YunDa.SOMS.DataTransferObject;
using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo; using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo; using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.GeneralInformation; using YunDa.SOMS.Entities.GeneralInformation;
using JsonException = System.Text.Json.JsonException;
namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
{ {

View File

@ -29,6 +29,7 @@ using YunDa.SOMS.DataTransferObject;
using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo; using YunDa.SOMS.DataTransferObject.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo; using YunDa.SOMS.Entities.ExternalEntities.BeijingYounuo;
using YunDa.SOMS.Entities.GeneralInformation; using YunDa.SOMS.Entities.GeneralInformation;
using JsonException = System.Text.Json.JsonException;
namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo namespace YunDa.SOMS.Application.ExternalDataManager.BjYounuo
{ {

View File

@ -64,7 +64,7 @@ namespace YunDa.SOMS.Application.GeneralInformation.SettingAndFaultRpt
private readonly SOMSAuditingStore _SOMSAuditingStore; private readonly SOMSAuditingStore _SOMSAuditingStore;
private string _ISMSGateWayIp = "http://127.0.0.1:38094"; private string _ISMSGateWayIp = "http://127.0.0.1:38094";
private string _ISMSftpIp = "192.168.65.33"; private string _ISMSftpIp = "192.168.81.21";
private string _ISMSftpUser = "admin"; private string _ISMSftpUser = "admin";
private string _ISMSftpPassword = "yunda123"; private string _ISMSftpPassword = "yunda123";
public TransformInfomationAppService(ISessionAppService sessionAppService public TransformInfomationAppService(ISessionAppService sessionAppService

View File

@ -38,14 +38,12 @@ namespace YunDa.SOMS.DataTransferObject.DataMonitoring.SecondaryCircuitInspectio
/// 格式示例: Js代码 /// 格式示例: Js代码
/// </summary> /// </summary>
[Required(ErrorMessage = "触发表达式不能为空")] [Required(ErrorMessage = "触发表达式不能为空")]
[StringLength(500, ErrorMessage = "触发表达式长度不能超过500个字符")]
public string TriggerExpression { get; set; } public string TriggerExpression { get; set; }
/// <summary> /// <summary>
/// 强制等待时间(秒)- 防止连续触发 /// 强制等待时间(秒)- 防止连续触发
/// </summary> /// </summary>
[Range(1, 3600, ErrorMessage = "强制等待时间必须在1-3600秒之间")]
public int? MandatoryWaitSeconds { get; set; } = 30; public int? MandatoryWaitSeconds { get; set; } = 30;
/// <summary> /// <summary>

View File

@ -38,6 +38,9 @@ namespace YunDa.SOMS.DataTransferObject.MaintenanceAndOperations.SecondaryEquipm
[BsonDateTimeOptions(Kind = DateTimeKind.Local)] [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
[MongoDBDescendingIndex] [MongoDBDescendingIndex]
public DateTime Time { get; set; } public DateTime Time { get; set; }
public string DiagnoseResultName{ get; set; }
public string DiaStatus { get; set; }
} }

View File

@ -1236,6 +1236,12 @@
</summary> </summary>
<returns></returns> <returns></returns>
</member> </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)"> <member name="M:YunDa.SOMS.MongoDB.Application.Inspection.InspectionItemResultAppService.GetAlarmMessage(System.Nullable{System.Guid},System.Int32,System.String)">
<summary> <summary>
获取报警信息 获取报警信息
@ -1538,6 +1544,26 @@
<param name="stationId"></param> <param name="stationId"></param>
<returns></returns> <returns></returns>
</member> </member>
<member name="M:YunDa.SOMS.MongoDB.Application.MeasuresTemperature.MeasuresTemperatureResultAppService.FindMeasureTempertureResults(YunDa.SOMS.DataTransferObject.PageSearchCondition{YunDa.SOMS.DataTransferObject.VideoSurveillance.MeasureTemperatureResultDto.SearchCondition.MeasureTemperatureResultSearchConditonInput})">
<summary>
查询温度测量结果(热成像设备)
</summary>
<param name="searchCondition">查询条件</param>
<returns></returns>
</member>
<member name="M:YunDa.SOMS.MongoDB.Application.MeasuresTemperature.MeasuresTemperatureResultAppService.ParseTemperatureFromResult(YunDa.SOMS.DataTransferObject.MainstationData.OriginalInspectionStoreResult,YunDa.SOMS.Entities.VideoSurveillance.PresetPoint)">
<summary>
从巡检结果数据中解析温度数据
</summary>
<param name="data">原始巡检结果数据</param>
<param name="preset">预置点信息</param>
<returns>温度测量结果列表</returns>
</member>
<member name="M:YunDa.SOMS.MongoDB.Application.MeasuresTemperature.MeasuresTemperatureResultAppService.CalculateSimilarity(System.String,System.String)">
<summary>
计算字符串相似度
</summary>
</member>
<member name="M:YunDa.SOMS.MongoDB.Application.MobileSurveillance.IRobotTaskAlarmResultAppService.CreateManyAsync(System.Collections.Generic.List{YunDa.SOMS.DataTransferObject.MobileSurveillance.RobotTaskAlarmResultDto.EditRobotTaskAlarmResultInput})"> <member name="M:YunDa.SOMS.MongoDB.Application.MobileSurveillance.IRobotTaskAlarmResultAppService.CreateManyAsync(System.Collections.Generic.List{YunDa.SOMS.DataTransferObject.MobileSurveillance.RobotTaskAlarmResultDto.EditRobotTaskAlarmResultInput})">
<summary> <summary>
添加多条机器人巡检任务报警结果 添加多条机器人巡检任务报警结果

View File

@ -27,7 +27,6 @@ namespace YunDa.SOMS.Entities.DataMonitoring.SecondaryCircuitInspection
/// 格式示例: {16385_0}==1&&{752}>1000 /// 格式示例: {16385_0}==1&&{752}>1000
/// </summary> /// </summary>
[Required] [Required]
[StringLength(500)]
public virtual string TriggerExpression { get; set; } public virtual string TriggerExpression { get; set; }

View File

@ -1,46 +1,85 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql; using Pomelo.EntityFrameworkCore.MySql;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure; using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
using System; using System;
namespace YunDa.SOMS.EntityFrameworkCore.EntityFrameworkCore namespace YunDa.SOMS.EntityFrameworkCore.EntityFrameworkCore
{ {
public static class DbContextOptionsConfigurer public static class DbContextOptionsConfigurer
{
public static void Configure(
DbContextOptionsBuilder<SOMSDbContext> dbContextOptions,
string connectionString,
ILoggerFactory loggerFactory = null,
bool isDevelopment = false)
{ {
public static void Configure( // 缓存 ServerVersion 以避免重复检测
DbContextOptionsBuilder<SOMSDbContext> dbContextOptions, var serverVersion = ServerVersion.AutoDetect(connectionString);
string connectionString,
ILoggerFactory loggerFactory = null)
{
dbContextOptions.UseMySql(connectionString, ServerVersion.AutoDetect(connectionString),
builder =>
{
builder.CommandTimeout(600);
//builder.EnableRetryOnFailure(
// maxRetryCount: 3,
// maxRetryDelay: TimeSpan.FromSeconds(5),
// errorNumbersToAdd: null
//);
}
)
.EnableSensitiveDataLogging() // 显示敏感数据(如参数值)
.EnableDetailedErrors() // 显示详细错误信息
.LogTo(
Console.WriteLine, // 可以改为你的日志方法
new[] {
DbLoggerCategory.Database.Command.Name,
DbLoggerCategory.Database.Connection.Name,
DbLoggerCategory.Database.Transaction.Name,
DbLoggerCategory.Query.Name
},
LogLevel.Information // 或 LogLevel.Debug 获取更详细信息
);
// 如果传入了 loggerFactory使用它 dbContextOptions.UseMySql(connectionString, serverVersion,
if (loggerFactory != null) builder =>
{ {
dbContextOptions.UseLoggerFactory(loggerFactory); builder.CommandTimeout(600);
// 启用连接重试机制(生产环境推荐)
//builder.EnableRetryOnFailure(
// maxRetryCount: 3,
// maxRetryDelay: TimeSpan.FromSeconds(5),
// errorNumbersToAdd: null
//);
// 性能优化选项
builder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery); // 避免笛卡尔爆炸
builder.MigrationsAssembly(typeof(SOMSDbContext).Assembly.GetName().Name);
} }
);
// 仅在开发环境启用详细日志
if (isDevelopment)
{
dbContextOptions
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
.LogTo(
Console.WriteLine,
new[] {
DbLoggerCategory.Database.Command.Name,
DbLoggerCategory.Database.Connection.Name,
DbLoggerCategory.Database.Transaction.Name,
DbLoggerCategory.Query.Name
},
LogLevel.Information
);
} }
else
{
// 生产环境:只记录警告和错误
dbContextOptions.LogTo(
Console.WriteLine,
new[] {
DbLoggerCategory.Database.Command.Name,
DbLoggerCategory.Database.Connection.Name
},
LogLevel.Warning
);
}
// 使用外部 LoggerFactory如果提供
if (loggerFactory != null)
{
dbContextOptions.UseLoggerFactory(loggerFactory);
}
// 性能优化配置
dbContextOptions
.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking) // 默认无跟踪查询
.ConfigureWarnings(warnings =>
{
// 忽略常见的非关键警告
warnings.Ignore(CoreEventId.FirstWithoutOrderByAndFilterWarning);
warnings.Ignore(CoreEventId.RowLimitingOperationWithoutOrderByWarning);
});
} }
} }
}

View File

@ -22,7 +22,7 @@ namespace YunDa.Server.ISMSTcp.Models
/// <summary> /// <summary>
/// 定值 /// 定值
/// </summary> /// </summary>
public decimal Value { get; set; } public string Value { get; set; }
/// <summary> /// <summary>
/// 单位 /// 单位

View File

@ -258,23 +258,6 @@ namespace YunDa.Server.ISMSTcp.Services
if (contentToken is JArray contentArray && contentArray.Count > 0) if (contentToken is JArray contentArray && contentArray.Count > 0)
{ {
//2025-10-25 所有值加1 send CallYXByDevice|B001208
//foreach (var item in contentArray)
//{
// if (item["YX_ID"].Value<string>() == "YXB001103058")
// {
// int kk = 0;
// }
// if (item["V"] != null && item["V"].Type == JTokenType.String)
// {
// string val = item["V"].Value<string>();
// if(int.TryParse(val, out int value))
// {
// //item["V"] = (value + 1).ToString();
// }
// }
//}
List<TelesignalisationModel> telesignalisationModels = new List<TelesignalisationModel>(); List<TelesignalisationModel> telesignalisationModels = new List<TelesignalisationModel>();
@ -1136,9 +1119,9 @@ namespace YunDa.Server.ISMSTcp.Services
// 检查Value是否为非数字值如"退出"等中文字符) // 检查Value是否为非数字值如"退出"等中文字符)
if (!string.IsNullOrEmpty(valueString) && !decimal.TryParse(valueString, out _)) if (!string.IsNullOrEmpty(valueString) && !decimal.TryParse(valueString, out _))
{ {
_logger.LogWarning("DZ数据Value字段包含非数字值: {Value}将设置为0", valueString); _logger.LogWarning("DZ数据Value字段包含非数字值: {Value}", valueString);
// 将非数字值替换为0 // 将非数字值替换为0
jObject["Value"] = 0; jObject["Value"] = valueString;
} }
} }
return item; return item;

View File

@ -233,7 +233,7 @@ namespace YunDa.Server.ISMSTcp.Services
_ = Task.Run(async () => _ = Task.Run(async () =>
{ {
while (true) while (true)
{//每30秒更新一下配置 {//每10分钟更新一下配置
await UpdatePlans(); await UpdatePlans();
@ -241,7 +241,7 @@ namespace YunDa.Server.ISMSTcp.Services
//await CheckAiChannel(); //await CheckAiChannel();
await Task.Delay(30000); await Task.Delay(TimeSpan.FromMinutes(10));
} }
}); });
@ -256,11 +256,11 @@ namespace YunDa.Server.ISMSTcp.Services
{ {
await CheckPlan(); await CheckPlan();
await Task.Delay(10000); await Task.Delay(TimeSpan.FromSeconds(60));
} }
else else
{ {
await Task.Delay(10000); await Task.Delay(TimeSpan.FromSeconds(60));
} }
} }
@ -278,14 +278,14 @@ namespace YunDa.Server.ISMSTcp.Services
} }
else else
{ {
await Task.Delay(10000); await Task.Delay(TimeSpan.FromSeconds(60));
} }
} }
}); });
//执行计划(两个线程同时执行) //执行计划(两个线程同时执行)
int threadNumber = _isDebug ? 1 : 3; int threadNumber = _isDebug ? 1 : 1;
for (int i = 0; i < threadNumber; ++i) for (int i = 0; i < threadNumber; ++i)
{ {
@ -319,7 +319,7 @@ namespace YunDa.Server.ISMSTcp.Services
await CallAiAndSave(item); await CallAiAndSave(item);
await Task.Delay(500); await Task.Delay(5000);
} }
}); });
} }
@ -571,88 +571,65 @@ namespace YunDa.Server.ISMSTcp.Services
for (int i = 0; i < item.TimeWindowCount; i++) for (int i = 0; i < item.TimeWindowCount; i++)
{ {
List<ZzDataResultModel>? telemetryData = null;
var tasks = new List<Task>(); List<ZzDataResultModel>? teleSignalData = null;
List<DeviceDzData>? settingData = null;
Task<List<ZzDataResultModel>>? t1 = null; List<InspectionResultData>? presetData = null;
Task<List<ZzDataResultModel>>? t2 = null; List<ZzDataResultModel>? gatewayData = null;
Task<List<DeviceDzData>>? t3 = null; List<ZzDataResultModel>? variantData = null;
Task<List<InspectionResultData>>? t4 = null;
Task<List<ZzDataResultModel>>? t5 = null;
Task<List<ZzDataResultModel>>? t6 = null;
if (item.TelemetryConfigCount > 0) if (item.TelemetryConfigCount > 0)
{ {
t1 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 1); telemetryData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 1);
tasks.Add(t1);
} }
if (item.TelesignalConfigCount > 0) if (item.TelesignalConfigCount > 0)
{ {
t2 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 2); teleSignalData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 2);
tasks.Add(t2);
} }
if (item.DeviceConfigCount > 0) if (item.DeviceConfigCount > 0)
{ {
t3 = GetSourceDataAsync<List<DeviceDzData>>(id, 3); settingData = await GetSourceDataAsync<List<DeviceDzData>>(id, 3);
tasks.Add(t3);
} }
if (item.CameraPresetCount > 0) if (item.CameraPresetCount > 0)
{ {
t4 = GetSourceDataAsync<List<InspectionResultData>>(id, 4); presetData = await GetSourceDataAsync<List<InspectionResultData>>(id, 4);
tasks.Add(t4);
} }
if (item.GatewayConfigCount > 0) if (item.GatewayConfigCount > 0)
{ {
t5 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 5); gatewayData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 5);
tasks.Add(t5);
} }
if (item.VariantConfigCount > 0) if (item.VariantConfigCount > 0)
{ {
t6 = GetSourceDataAsync<List<ZzDataResultModel>>(id, 6); variantData = await GetSourceDataAsync<List<ZzDataResultModel>>(id, 6);
tasks.Add(t6);
} }
await Task.WhenAll(tasks); jsData.StoreData.TelemetryData = telemetryData;
jsData.StoreData.TeleSignalData = teleSignalData;
jsData.StoreData.SettingData = settingData;
jsData.StoreData.PresetData = presetData;
jsData.StoreData.GatewayData = gatewayData;
jsData.StoreData.VariantData = variantData;
if (t1 != null) jsData.StoreData.TelemetryData = await t1; if (jsData.StoreData.TelemetryData == null && jsData.StoreData.TeleSignalData == null && jsData.StoreData.SettingData == null &&
if (t2 != null) jsData.StoreData.TeleSignalData = await t2;
if (t3 != null) jsData.StoreData.SettingData = await t3;
if (t4 != null) jsData.StoreData.PresetData = await t4;
if (t5 != null) jsData.StoreData.GatewayData = await t5;
if (t6 != null) jsData.StoreData.VariantData = await t6;
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) jsData.StoreData.PresetData == null && jsData.StoreData.GatewayData == null && jsData.StoreData.VariantData == null)
{ {
continue; continue;
} }
var json = JsonConvert.SerializeObject(jsData, var json = JsonConvert.SerializeObject(jsData,
new JsonSerializerSettings new JsonSerializerSettings
{ {
ContractResolver = new CamelCasePropertyNamesContractResolver() ContractResolver = new CamelCasePropertyNamesContractResolver()
}); });
var js = $"JSON.parse('{json.Replace("'", "\\'")}')"; var js = $"JSON.parse('{json.Replace("'", "\\'")}')";
var jsObj = engine.Evaluate(js).ToObject(); var jsObj = engine.Evaluate(js).ToObject();
var jsResult = engine.Invoke("calculate", jsObj).AsObject(); var jsResult = engine.Invoke("calculate", jsObj).AsObject();
if (jsResult != null && jsResult.HasProperty("status")) if (jsResult != null && jsResult.HasProperty("status"))
{ {
saveObj = jsResult; saveObj = jsResult;
var status = jsResult.Get("status").ToString(); var status = jsResult.Get("status").ToString();
if (status == "正常" || string.IsNullOrWhiteSpace(status)) if (status == "正常" || string.IsNullOrWhiteSpace(status))
{//只要正常,就不用再检测了 {
break; break;
} }
} }

View File

@ -59,11 +59,11 @@ namespace YunDa.Server.ISMSTcp.Services
if (protectionDeviceCommInfos == null || !protectionDeviceCommInfos.Any()) if (protectionDeviceCommInfos == null || !protectionDeviceCommInfos.Any())
{ {
_logger.LogWarning("Redis中未获取到保护装置通信信息跳过本次召唤"); _logger.LogWarning("Redis中未获取到保护装置通信信息跳过本次召唤");
return; //return;
} }
// 只处理在线的设备 // 只处理在线的设备
var onlineDevices = protectionDeviceCommInfos.Where(d => d.IsOnline).ToList(); var onlineDevices = protectionDeviceCommInfos.ToList();
_logger.LogInformation("从Redis获取到 {TotalCount} 个保护装置,其中在线设备 {OnlineCount} 个", _logger.LogInformation("从Redis获取到 {TotalCount} 个保护装置,其中在线设备 {OnlineCount} 个",
protectionDeviceCommInfos.Count, onlineDevices.Count); protectionDeviceCommInfos.Count, onlineDevices.Count);
@ -100,10 +100,13 @@ namespace YunDa.Server.ISMSTcp.Services
// 再次检查TCP连接状态防止在循环过程中连接断开 // 再次检查TCP连接状态防止在循环过程中连接断开
if (!_tcpClient.IsConnected) if (!_tcpClient.IsConnected)
{ {
_logger.LogWarning("TCP连接已断开停止发送召唤命令"); _logger.LogWarning("TCP连接已断开等待5S发送召唤命令");
failureCount++; Task.Delay(5000).Wait();
failedDevices.Add($"{device.DeviceId}({device.DeviceName})"); if (!_tcpClient.IsConnected)
continue; {
_logger.LogWarning("TCP连接已断开停止发送召唤命令");
continue;
}
} }
// 构造召唤命令CallYCByDevice|{装置ID} // 构造召唤命令CallYCByDevice|{装置ID}
@ -132,7 +135,7 @@ namespace YunDa.Server.ISMSTcp.Services
_yxCount = (_yxCount + 1) % 6; _yxCount = (_yxCount + 1) % 6;
// 每个命令之间间隔100毫秒 // 每个命令之间间隔100毫秒
await Task.Delay(100); await Task.Delay(1000);
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -103,14 +103,14 @@ namespace YunDa.Server.ISMSTcp.Services
} }
// 检查设备通信状态 // 检查设备通信状态
bool isCommNormal = await _deviceCommunicationStateService.IsDeviceCommunicationNormalAsync(device.Id, cancellationToken); //bool isCommNormal = await _deviceCommunicationStateService.IsDeviceCommunicationNormalAsync(device.Id, cancellationToken);
if (!isCommNormal) //if (!isCommNormal)
{ //{
_logger.LogWarning("装置通信状态异常,取消数据召唤操作 - 设备ID: {DeviceId} ({DeviceName})", device.Id, device.DeviceName); // _logger.LogWarning("装置通信状态异常,取消数据召唤操作 - 设备ID: {DeviceId} ({DeviceName})", device.Id, device.DeviceName);
commStateSkippedCount++; // commStateSkippedCount++;
commStateSkippedDevices.Add($"{device.Id}({device.DeviceName})"); // commStateSkippedDevices.Add($"{device.Id}({device.DeviceName})");
continue; // continue;
} //}
// 再次检查TCP连接状态防止在循环过程中连接断开 // 再次检查TCP连接状态防止在循环过程中连接断开
if (!_tcpClient.IsConnected) if (!_tcpClient.IsConnected)

View File

@ -10,8 +10,8 @@
}, },
"ISMSServer": { "ISMSServer": {
"ServerIP": "192.168.81.21", "ServerIP": "192.168.81.21",
"HeartbeatIntervalSeconds": 60, "HeartbeatIntervalSeconds": 1800,
"AutoConnectDelaySeconds": 10 "AutoConnectDelaySeconds": 60
}, },
"ScheduledTelemetry": { "ScheduledTelemetry": {
"IntervalMinutes": 30 "IntervalMinutes": 30

View File

@ -14,12 +14,12 @@
"IncompleteDataTimeoutSeconds": 5, "IncompleteDataTimeoutSeconds": 5,
"BufferSize": 1024, "BufferSize": 1024,
"EnableHeartbeat": true, "EnableHeartbeat": true,
"HeartbeatIntervalSeconds": 30, "HeartbeatIntervalSeconds": 1800,
"HeartbeatTimeoutSeconds": 10, "HeartbeatTimeoutSeconds": 10,
"HeartbeatMessage": "HEARTBEAT_PING", "HeartbeatMessage": "HEARTBEAT_PING",
"EnableAutoConnect": true, "EnableAutoConnect": true,
"AutoConnectDelaySeconds": 3, "AutoConnectDelaySeconds": 3,
"ConnectionTimeoutSeconds": 30, "ConnectionTimeoutSeconds": 180,
"EnableConnectionRetry": true "EnableConnectionRetry": true
}, },
"ApiEndpoints": { "ApiEndpoints": {
@ -34,7 +34,7 @@
}, },
"ScheduledTelemetry": { "ScheduledTelemetry": {
"Enabled": true, "Enabled": true,
"IntervalSeconds": 60, "IntervalSeconds": 1800,
"MaxRetries": 10, "MaxRetries": 10,
"RetryDelayMs": 2000, "RetryDelayMs": 2000,
"CommandDelayMs": 100 "CommandDelayMs": 100