mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-27 05:37:10 +08:00
release:6.0.5.14
feat: 添加报警延时逻辑 feat: mqtt脚本添加检查按钮 fix(opcuamaster): 服务端时间戳选项在轮询模式下不生效 refactor: aop插入日志ip字段 非null
This commit is contained in:
@@ -58,7 +58,7 @@ public class RuntimeInfoControler : ControllerBase
|
||||
[DisplayName("获取实时报警信息")]
|
||||
public SqlSugarPagedList<VariableData> 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);
|
||||
|
||||
@@ -131,6 +131,12 @@ public class Variable : PrimaryIdEntity
|
||||
public ConcurrentDictionary<long, Dictionary<string, string>>? VariablePropertys { get; set; }
|
||||
|
||||
#region 报警
|
||||
/// <summary>
|
||||
/// 报警延时
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "报警延时")]
|
||||
[AutoGenerateColumn(Visible = false, Filterable = true, Sortable = true)]
|
||||
public int AlarmDelay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 布尔开报警使能
|
||||
|
||||
@@ -15,6 +15,11 @@ namespace ThingsGateway.Gateway.Application;
|
||||
/// </summary>
|
||||
public enum EventTypeEnum
|
||||
{
|
||||
/// <summary>
|
||||
/// 准备报警
|
||||
/// </summary>
|
||||
Prepare,
|
||||
|
||||
/// <summary>
|
||||
/// 报警产生
|
||||
/// </summary>
|
||||
|
||||
@@ -69,7 +69,7 @@ public static class GlobalData
|
||||
/// <summary>
|
||||
/// 实时报警列表
|
||||
/// </summary>
|
||||
public static IEnumerable<VariableRunTime> ReadOnlyRealAlarmVariables => HostedServiceUtil.AlarmHostedService.RealAlarmVariables;
|
||||
public static IReadOnlyDictionary<string, VariableRunTime> ReadOnlyRealAlarmVariables => HostedServiceUtil.AlarmHostedService.RealAlarmVariables;
|
||||
|
||||
/// <summary>
|
||||
/// 只读的变量字典,提供对变量的只读访问
|
||||
|
||||
@@ -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;
|
||||
|
||||
/// <summary>
|
||||
@@ -49,7 +48,7 @@ public class AlarmHostedService : BackgroundService
|
||||
/// <summary>
|
||||
/// 实时报警列表
|
||||
/// </summary>
|
||||
internal ConcurrentList<VariableRunTime> RealAlarmVariables { get; } = new();
|
||||
internal ConcurrentDictionary<string, VariableRunTime> RealAlarmVariables { get; } = new();
|
||||
|
||||
private IEnumerable<VariableRunTime> _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
|
||||
/// <param name="text">报警文本</param>
|
||||
/// <param name="eventEnum">报警事件类型枚举</param>
|
||||
/// <param name="alarmEnum">报警类型枚举</param>
|
||||
private void AlarmChange(VariableRunTime item, object limit, string text, EventTypeEnum eventEnum, AlarmTypeEnum? alarmEnum)
|
||||
/// <param name="delay">报警延时</param>
|
||||
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<AlarmVariable>());
|
||||
|
||||
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<AlarmVariable>());
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果是需恢复报警事件或检查报警事件,则从实时报警列表中移除该变量
|
||||
RealAlarmVariables.RemoveWhere(it => it.Id == item.Id);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endregion 核心实现
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -121,6 +121,7 @@
|
||||
"WriteExpressions": "写入表达式",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
|
||||
"AlarmDelay": "报警延时",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
@@ -398,6 +399,7 @@
|
||||
"WriteExpressions": "写入表达式",
|
||||
"RpcWriteEnable": "远程写入",
|
||||
|
||||
"AlarmDelay": "报警延时",
|
||||
"BoolOpenAlarmEnable": "布尔开报警使能",
|
||||
"BoolOpenRestrainExpressions": "布尔开报警约束",
|
||||
"BoolOpenAlarmText": "布尔开报警文本",
|
||||
|
||||
@@ -320,6 +320,11 @@ public class VariableRunTime : Variable, IVariable
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime? EventTime { get; set; }
|
||||
/// <summary>
|
||||
/// 事件时间
|
||||
/// </summary>
|
||||
[AutoGenerateColumn(Visible = false)]
|
||||
public DateTime? PrepareEventTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件类型
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
<TabItem Text=@Localizer["AlarmInformation"]>
|
||||
<EditorForm class="p-2" AutoGenerateAllItem="false" RowType=RowType.Inline ItemsPerRow=2 LabelWidth=250 Model="Model">
|
||||
<FieldItems>
|
||||
|
||||
<EditorItem @bind-Field="@context.BoolCloseAlarmText" />
|
||||
<EditorItem @bind-Field="@context.BoolCloseRestrainExpressions" />
|
||||
<EditorItem @bind-Field="@context.BoolCloseAlarmEnable" Rows="1" />
|
||||
@@ -108,6 +109,7 @@
|
||||
<EditorItem @bind-Field="@context.CustomAlarmCode" />
|
||||
<EditorItem @bind-Field="@context.CustomRestrainExpressions" />
|
||||
<EditorItem @bind-Field="@context.CustomAlarmEnable" />
|
||||
<EditorItem @bind-Field="@context.AlarmDelay" />
|
||||
</FieldItems>
|
||||
</EditorForm>
|
||||
</TabItem>
|
||||
@@ -219,6 +221,7 @@ else
|
||||
<EditorItem @bind-Field="@context.CustomAlarmCode" />
|
||||
<EditorItem @bind-Field="@context.CustomRestrainExpressions" />
|
||||
<EditorItem @bind-Field="@context.CustomAlarmEnable" />
|
||||
<EditorItem @bind-Field="@context.AlarmDelay" />
|
||||
</FieldItems>
|
||||
</EditorForm>
|
||||
</TabItem>
|
||||
|
||||
@@ -20,7 +20,7 @@ public partial class RealAlarmPage
|
||||
|
||||
private Task<QueryData<VariableRunTime>> OnQueryAsync(QueryPageOptions options)
|
||||
{
|
||||
var data = GlobalData.ReadOnlyRealAlarmVariables.GetQueryData(options);
|
||||
var data = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).GetQueryData(options);
|
||||
return Task.FromResult(data);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>6.0.5.13</Version>
|
||||
<Version>6.0.5.14</Version>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -113,7 +113,7 @@ public partial class KafkaProducer : BusinessBaseWithCacheIntervalScript<Variabl
|
||||
//分解List,避免超出字节大小限制
|
||||
var varData = CurrentDevice.VariableRunTimes.Select(a => a.Value).Adapt<List<VariableData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var devData = CollectDevices.Select(a => a.Value).Adapt<List<DeviceData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
if (!success)
|
||||
|
||||
@@ -122,7 +122,7 @@ public partial class MqttClient : BusinessBaseWithCacheIntervalScript<VariableDa
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = CurrentDevice.VariableRunTimes.Select(a => a.Value).Adapt<List<VariableData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var devData = CollectDevices.Select(a => a.Value).Adapt<List<DeviceData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
if (!success)
|
||||
|
||||
@@ -157,7 +157,7 @@ public partial class MqttServer : BusinessBaseWithCacheIntervalScript<VariableDa
|
||||
//分解List,避免超出mqtt字节大小限制
|
||||
var varData = CurrentDevice.VariableRunTimes.Select(a => a.Value).Adapt<List<VariableData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var devData = CollectDevices.Select(a => a.Value).Adapt<List<DeviceData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
List<MqttApplicationMessage> Messages = new();
|
||||
foreach (var item in varData)
|
||||
{
|
||||
|
||||
@@ -115,7 +115,7 @@ public partial class RabbitMQProducer : BusinessBaseWithCacheIntervalScript<Vari
|
||||
//分解List,避免超出字节大小限制
|
||||
var varData = CurrentDevice.VariableRunTimes.Select(a => a.Value).Adapt<List<VariableData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var devData = CollectDevices.Select(a => a.Value).Adapt<List<DeviceData>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
var alramData = GlobalData.ReadOnlyRealAlarmVariables.Select(a => a.Value).Adapt<List<AlarmVariable>>().ChunkBetter(_driverPropertys.SplitSize);
|
||||
foreach (var item in varData)
|
||||
{
|
||||
if (!success)
|
||||
|
||||
Reference in New Issue
Block a user