From 36f9386e8d299355e104632784bb0293c5a5d314 Mon Sep 17 00:00:00 2001 From: Diego <2248356998@qq.com> Date: Wed, 21 Aug 2024 19:44:34 +0800 Subject: [PATCH] =?UTF-8?q?release=EF=BC=9A6.0.5.14?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit feat: 添加报警延时逻辑 feat: mqtt脚本添加检查按钮 fix(opcuamaster): 服务端时间戳选项在轮询模式下不生效 refactor: aop插入日志ip字段 非null --- .../Controler/RuntimeInfoControler.cs | 2 +- .../Entity/Variable.cs | 6 + .../Enums/EventTypeEnum.cs | 5 + .../GlobalData/GlobalData.cs | 2 +- .../HostService/AlarmHostedService.cs | 145 +++++++++++++----- .../Locales/en-US.json | 2 + .../Locales/zh-CN.json | 2 + .../Model/VariableRunTime.cs | 5 + .../Variable/VariableEditComponent.razor | 3 + .../Pages/Runtime/RealAlarmPage.razor.cs | 2 +- src/Version.props | 2 +- .../Kafka/KafkaProducer.other.cs | 2 +- .../MqttClient/MqttClient.other.cs | 2 +- .../MqttServer/MqttServer.other.cs | 2 +- .../RabbitMQ/RabbitMQProducer.other.cs | 2 +- 15 files changed, 137 insertions(+), 47 deletions(-) diff --git a/src/ThingsGateway.Gateway.ASPNetCore/Controler/RuntimeInfoControler.cs b/src/ThingsGateway.Gateway.ASPNetCore/Controler/RuntimeInfoControler.cs index 37cc6a7d4..8ec007aab 100644 --- a/src/ThingsGateway.Gateway.ASPNetCore/Controler/RuntimeInfoControler.cs +++ b/src/ThingsGateway.Gateway.ASPNetCore/Controler/RuntimeInfoControler.cs @@ -58,7 +58,7 @@ public class RuntimeInfoControler : ControllerBase [DisplayName("获取实时报警信息")] public SqlSugarPagedList GetRealAlarmList([FromQuery] VariablePageInput input) { - var data = GlobalData.ReadOnlyRealAlarmVariables + var data = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value) .WhereIF(!input.Name.IsNullOrEmpty(), a => a.Name == input.Name) .WhereIF(input.DeviceId != null, a => a.DeviceId == input.DeviceId) .ToPagedList(input); diff --git a/src/ThingsGateway.Gateway.Application/Entity/Variable.cs b/src/ThingsGateway.Gateway.Application/Entity/Variable.cs index cfa88dcb2..42b5ea71b 100644 --- a/src/ThingsGateway.Gateway.Application/Entity/Variable.cs +++ b/src/ThingsGateway.Gateway.Application/Entity/Variable.cs @@ -131,6 +131,12 @@ public class Variable : PrimaryIdEntity public ConcurrentDictionary>? VariablePropertys { get; set; } #region 报警 + /// + /// 报警延时 + /// + [SugarColumn(ColumnDescription = "报警延时")] + [AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)] + public int AlarmDelay { get; set; } /// /// 布尔开报警使能 diff --git a/src/ThingsGateway.Gateway.Application/Enums/EventTypeEnum.cs b/src/ThingsGateway.Gateway.Application/Enums/EventTypeEnum.cs index dfd02d18b..a35dc50d9 100644 --- a/src/ThingsGateway.Gateway.Application/Enums/EventTypeEnum.cs +++ b/src/ThingsGateway.Gateway.Application/Enums/EventTypeEnum.cs @@ -15,6 +15,11 @@ namespace ThingsGateway.Gateway.Application; /// public enum EventTypeEnum { + /// + /// 准备报警 + /// + Prepare, + /// /// 报警产生 /// diff --git a/src/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs b/src/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs index 7154e4da0..4ea53490b 100644 --- a/src/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs +++ b/src/ThingsGateway.Gateway.Application/GlobalData/GlobalData.cs @@ -69,7 +69,7 @@ public static class GlobalData /// /// 实时报警列表 /// - public static IEnumerable ReadOnlyRealAlarmVariables => HostedServiceUtil.AlarmHostedService.RealAlarmVariables; + public static IReadOnlyDictionary ReadOnlyRealAlarmVariables => HostedServiceUtil.AlarmHostedService.RealAlarmVariables; /// /// 只读的变量字典,提供对变量的只读访问 diff --git a/src/ThingsGateway.Gateway.Application/HostService/AlarmHostedService.cs b/src/ThingsGateway.Gateway.Application/HostService/AlarmHostedService.cs index 14dcd1275..6459aba5e 100644 --- a/src/ThingsGateway.Gateway.Application/HostService/AlarmHostedService.cs +++ b/src/ThingsGateway.Gateway.Application/HostService/AlarmHostedService.cs @@ -14,12 +14,11 @@ using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; -using ThingsGateway.Core.Extension; +using System.Collections.Concurrent; + using ThingsGateway.Gateway.Application.Extensions; using ThingsGateway.NewLife.X; -using TouchSocket.Core; - namespace ThingsGateway.Gateway.Application; /// @@ -49,7 +48,7 @@ public class AlarmHostedService : BackgroundService /// /// 实时报警列表 /// - internal ConcurrentList RealAlarmVariables { get; } = new(); + internal ConcurrentDictionary RealAlarmVariables { get; } = new(); private IEnumerable _deviceVariables => GlobalData.Variables.Select(a => a.Value).Where(a => a.IsOnline && a.AlarmEnable); @@ -209,6 +208,7 @@ public class AlarmHostedService : BackgroundService string ex; // 报警约束表达式 string text; // 报警文本 AlarmTypeEnum? alarmEnum; // 报警类型枚举 + int delay = item.AlarmDelay; // 获取报警延迟时间 // 检查变量的数据类型 if (item.DataType.GetSystemType() == typeof(bool)) @@ -231,7 +231,7 @@ public class AlarmHostedService : BackgroundService if (alarmEnum == null) { // 如果仍未获取到报警类型,则触发需恢复报警事件(如果存在) - AlarmChange(item, null, text, EventTypeEnum.Finish, alarmEnum); + AlarmChange(item, null, text, EventTypeEnum.Finish, alarmEnum, delay); } else { @@ -246,14 +246,14 @@ public class AlarmHostedService : BackgroundService if (result) { // 如果表达式结果为true,则触发报警事件 - AlarmChange(item, limit, text, EventTypeEnum.Alarm, alarmEnum); + AlarmChange(item, limit, text, EventTypeEnum.Alarm, alarmEnum, delay); } } } else { // 如果不存在报警约束表达式,则直接触发报警事件 - AlarmChange(item, limit, text, EventTypeEnum.Alarm, alarmEnum); + AlarmChange(item, limit, text, EventTypeEnum.Alarm, alarmEnum, delay); } } } @@ -266,13 +266,15 @@ public class AlarmHostedService : BackgroundService /// 报警文本 /// 报警事件类型枚举 /// 报警类型枚举 - private void AlarmChange(VariableRunTime item, object limit, string text, EventTypeEnum eventEnum, AlarmTypeEnum? alarmEnum) + /// 报警延时 + private void AlarmChange(VariableRunTime item, object limit, string text, EventTypeEnum eventEnum, AlarmTypeEnum? alarmEnum, int delay) { + bool changed = false; if (eventEnum == EventTypeEnum.Finish) { // 如果是需恢复报警事件 // 如果实时报警列表中不存在该变量,则直接返回 - if (!RealAlarmVariables.Any(it => it.Id == item.Id)) + if (!RealAlarmVariables.ContainsKey(item.Name)) { return; } @@ -281,8 +283,7 @@ public class AlarmHostedService : BackgroundService { // 如果是触发报警事件 // 在实时报警列表中查找该变量 - var variable = RealAlarmVariables.FirstOrDefault(it => it.Id == item.Id); - if (variable != null) + if (RealAlarmVariables.TryGetValue(item.Name, out var variable)) { // 如果变量已经处于相同的报警类型,则直接返回 if (item.AlarmType == alarmEnum) @@ -293,26 +294,88 @@ public class AlarmHostedService : BackgroundService // 更新变量的报警信息和事件时间 if (eventEnum == EventTypeEnum.Alarm) { - // 如果是触发报警事件 - item.AlarmType = alarmEnum; - item.EventType = eventEnum; - item.AlarmLimit = limit.ToString(); - item.AlarmCode = item.Value.ToString(); - item.AlarmText = text; - item.AlarmTime = DateTime.Now; - item.EventTime = DateTime.Now; + //添加报警延时策略 + if (delay > 0) + { + if (item.EventType != EventTypeEnum.Alarm && item.EventType != EventTypeEnum.Prepare) + { + item.EventType = EventTypeEnum.Prepare;//准备报警 + item.PrepareEventTime = DateTime.Now; + } + else + { + if (item.EventType == EventTypeEnum.Prepare) + { + if ((DateTime.Now - item.PrepareEventTime!.Value).TotalSeconds > delay) + { + //超过延时时间,触发报警 + item.EventType = EventTypeEnum.Alarm; + item.AlarmTime = DateTime.Now; + item.EventTime = DateTime.Now; + item.AlarmType = alarmEnum; + item.AlarmLimit = limit.ToString(); + item.AlarmCode = item.Value.ToString(); + item.AlarmText = text; + item.PrepareEventTime = null; + + changed = true; + } + } + else if (item.EventType == EventTypeEnum.Alarm && item.AlarmType != alarmEnum) + { + //报警类型改变,重新计时 + if (item.PrepareEventTime == null) + item.PrepareEventTime = DateTime.Now; + if ((DateTime.Now - item.PrepareEventTime!.Value).TotalSeconds > delay) + { + //超过延时时间,触发报警 + item.EventType = EventTypeEnum.Alarm; + item.AlarmTime = DateTime.Now; + item.EventTime = DateTime.Now; + item.AlarmType = alarmEnum; + item.AlarmLimit = limit.ToString(); + item.AlarmCode = item.Value.ToString(); + item.AlarmText = text; + item.PrepareEventTime = null; + changed = true; + } + + } + else + { + return; + } + } + } + else + { + // 如果是触发报警事件 + item.EventType = eventEnum; + item.AlarmTime = DateTime.Now; + item.EventTime = DateTime.Now; + item.AlarmType = alarmEnum; + item.AlarmLimit = limit.ToString(); + item.AlarmCode = item.Value.ToString(); + item.AlarmText = text; + changed = true; + } + + } else if (eventEnum == EventTypeEnum.Finish) { // 如果是需恢复报警事件 // 获取旧的报警信息 - var oldAlarm = RealAlarmVariables.FirstOrDefault(it => it.Id == item.Id); - item.AlarmType = oldAlarm.AlarmType; - item.EventType = eventEnum; - item.AlarmLimit = oldAlarm.AlarmLimit; - item.AlarmCode = item.Value.ToString(); - item.AlarmText = text; - item.EventTime = DateTime.Now; + if (RealAlarmVariables.TryGetValue(item.Name, out var oldAlarm)) + { + item.AlarmType = oldAlarm.AlarmType; + item.EventType = eventEnum; + item.AlarmLimit = oldAlarm.AlarmLimit; + item.AlarmCode = item.Value.ToString(); + item.AlarmText = text; + item.EventTime = DateTime.Now; + } + changed = true; } else if (eventEnum == EventTypeEnum.Check) { @@ -323,26 +386,30 @@ public class AlarmHostedService : BackgroundService item.AlarmCode = item.Value.ToString(); item.AlarmText = text; item.EventTime = DateTime.Now; + changed = true; } // 触发报警变化事件 - OnAlarmChanged?.Invoke(item.Adapt()); - - if (eventEnum == EventTypeEnum.Alarm) + if (changed) { - // 如果是触发报警事件 - //lock (RealAlarmVariables) + if (item.EventType == EventTypeEnum.Alarm) { - // 从实时报警列表中移除旧的报警信息,并添加新的报警信息 - RealAlarmVariables.RemoveWhere(it => it.Id == item.Id); - RealAlarmVariables.Add(item); + // 如果是触发报警事件 + //lock (RealAlarmVariables) + { + // 从实时报警列表中移除旧的报警信息,并添加新的报警信息 + RealAlarmVariables.AddOrUpdate(item.Name, a => item, (a, b) => item); + } } + else + { + // 如果是需恢复报警事件或检查报警事件,则从实时报警列表中移除该变量 + RealAlarmVariables.TryRemove(item.Name, out _); + } + OnAlarmChanged?.Invoke(item.Adapt()); } - else - { - // 如果是需恢复报警事件或检查报警事件,则从实时报警列表中移除该变量 - RealAlarmVariables.RemoveWhere(it => it.Id == item.Id); - } + + } #endregion 核心实现 diff --git a/src/ThingsGateway.Gateway.Application/Locales/en-US.json b/src/ThingsGateway.Gateway.Application/Locales/en-US.json index 54abb53ad..a481a85c6 100644 --- a/src/ThingsGateway.Gateway.Application/Locales/en-US.json +++ b/src/ThingsGateway.Gateway.Application/Locales/en-US.json @@ -93,6 +93,7 @@ "WriteExpressions": "WriteExpressions", "RpcWriteEnable": "RpcWriteEnable", + "AlarmDelay": "AlarmDelay", "BoolOpenAlarmEnable": "BoolOpenAlarmEnable", "BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions", "BoolOpenAlarmText": "BoolOpenAlarmText", @@ -336,6 +337,7 @@ "ReadExpressions": "ReadExpressions", "WriteExpressions": "WriteExpressions", "RpcWriteEnable": "RpcWriteEnable", + "AlarmDelay": "AlarmDelay", "BoolOpenAlarmEnable": "BoolOpenAlarmEnable", "BoolOpenRestrainExpressions": "BoolOpenRestrainExpressions", "BoolOpenAlarmText": "BoolOpenAlarmText", diff --git a/src/ThingsGateway.Gateway.Application/Locales/zh-CN.json b/src/ThingsGateway.Gateway.Application/Locales/zh-CN.json index 6de7618dd..a591a3708 100644 --- a/src/ThingsGateway.Gateway.Application/Locales/zh-CN.json +++ b/src/ThingsGateway.Gateway.Application/Locales/zh-CN.json @@ -121,6 +121,7 @@ "WriteExpressions": "写入表达式", "RpcWriteEnable": "远程写入", + "AlarmDelay": "报警延时", "BoolOpenAlarmEnable": "布尔开报警使能", "BoolOpenRestrainExpressions": "布尔开报警约束", "BoolOpenAlarmText": "布尔开报警文本", @@ -398,6 +399,7 @@ "WriteExpressions": "写入表达式", "RpcWriteEnable": "远程写入", + "AlarmDelay": "报警延时", "BoolOpenAlarmEnable": "布尔开报警使能", "BoolOpenRestrainExpressions": "布尔开报警约束", "BoolOpenAlarmText": "布尔开报警文本", diff --git a/src/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs b/src/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs index a3310365f..b6df94144 100644 --- a/src/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs +++ b/src/ThingsGateway.Gateway.Application/Model/VariableRunTime.cs @@ -320,6 +320,11 @@ public class VariableRunTime : Variable, IVariable /// [AutoGenerateColumn(Visible = false)] public DateTime? EventTime { get; set; } + /// + /// 事件时间 + /// + [AutoGenerateColumn(Visible = false)] + public DateTime? PrepareEventTime { get; set; } /// /// 事件类型 diff --git a/src/ThingsGateway.Gateway.Razor/Pages/Config/Variable/VariableEditComponent.razor b/src/ThingsGateway.Gateway.Razor/Pages/Config/Variable/VariableEditComponent.razor index 0d26ad476..f0f8c84b7 100644 --- a/src/ThingsGateway.Gateway.Razor/Pages/Config/Variable/VariableEditComponent.razor +++ b/src/ThingsGateway.Gateway.Razor/Pages/Config/Variable/VariableEditComponent.razor @@ -82,6 +82,7 @@ + @@ -108,6 +109,7 @@ + @@ -219,6 +221,7 @@ else + diff --git a/src/ThingsGateway.Gateway.Razor/Pages/Runtime/RealAlarmPage.razor.cs b/src/ThingsGateway.Gateway.Razor/Pages/Runtime/RealAlarmPage.razor.cs index 94970fbc2..e1a2339da 100644 --- a/src/ThingsGateway.Gateway.Razor/Pages/Runtime/RealAlarmPage.razor.cs +++ b/src/ThingsGateway.Gateway.Razor/Pages/Runtime/RealAlarmPage.razor.cs @@ -20,7 +20,7 @@ public partial class RealAlarmPage private Task> OnQueryAsync(QueryPageOptions options) { - var data = GlobalData.ReadOnlyRealAlarmVariables.GetQueryData(options); + var data = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).GetQueryData(options); return Task.FromResult(data); } diff --git a/src/Version.props b/src/Version.props index 5dd87f78c..0c66ff03d 100644 --- a/src/Version.props +++ b/src/Version.props @@ -1,6 +1,6 @@ - 6.0.5.13 + 6.0.5.14 diff --git a/src/plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.other.cs b/src/plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.other.cs index 65c984acd..4e4c8ecb4 100644 --- a/src/plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.other.cs +++ b/src/plugin/ThingsGateway.Plugin.Kafka/Kafka/KafkaProducer.other.cs @@ -113,7 +113,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); var devData = CollectDevices.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); - var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt>().ChunkBetter(_driverPropertys.SplitSize); + var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); foreach (var item in varData) { if (!success) diff --git a/src/plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs b/src/plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs index ce136770f..8e7129545 100644 --- a/src/plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs +++ b/src/plugin/ThingsGateway.Plugin.Mqtt/MqttClient/MqttClient.other.cs @@ -122,7 +122,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); var devData = CollectDevices.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); - var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt>().ChunkBetter(_driverPropertys.SplitSize); + var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); foreach (var item in varData) { if (!success) diff --git a/src/plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.other.cs b/src/plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.other.cs index f0bc2893e..fd4b490d5 100644 --- a/src/plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.other.cs +++ b/src/plugin/ThingsGateway.Plugin.Mqtt/MqttServer/MqttServer.other.cs @@ -157,7 +157,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); var devData = CollectDevices.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); - var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt>().ChunkBetter(_driverPropertys.SplitSize); + var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); List Messages = new(); foreach (var item in varData) { diff --git a/src/plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.other.cs b/src/plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.other.cs index 0782ae15c..634716840 100644 --- a/src/plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.other.cs +++ b/src/plugin/ThingsGateway.Plugin.RabbitMQ/RabbitMQ/RabbitMQProducer.other.cs @@ -115,7 +115,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); var devData = CollectDevices.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); - var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt>().ChunkBetter(_driverPropertys.SplitSize); + var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt>().ChunkBetter(_driverPropertys.SplitSize); foreach (var item in varData) { if (!success)