release:6.0.5.14

feat: 添加报警延时逻辑
feat: mqtt脚本添加检查按钮
fix(opcuamaster): 服务端时间戳选项在轮询模式下不生效
refactor:  aop插入日志ip字段 非null
This commit is contained in:
Diego
2024-08-21 19:44:34 +08:00
parent e9dc963805
commit 36f9386e8d
15 changed files with 137 additions and 47 deletions

View File

@@ -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);

View File

@@ -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>
/// 布尔开报警使能

View File

@@ -15,6 +15,11 @@ namespace ThingsGateway.Gateway.Application;
/// </summary>
public enum EventTypeEnum
{
/// <summary>
/// 准备报警
/// </summary>
Prepare,
/// <summary>
/// 报警产生
/// </summary>

View File

@@ -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>
/// 只读的变量字典,提供对变量的只读访问

View File

@@ -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

View File

@@ -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",

View File

@@ -121,6 +121,7 @@
"WriteExpressions": "写入表达式",
"RpcWriteEnable": "远程写入",
"AlarmDelay": "报警延时",
"BoolOpenAlarmEnable": "布尔开报警使能",
"BoolOpenRestrainExpressions": "布尔开报警约束",
"BoolOpenAlarmText": "布尔开报警文本",
@@ -398,6 +399,7 @@
"WriteExpressions": "写入表达式",
"RpcWriteEnable": "远程写入",
"AlarmDelay": "报警延时",
"BoolOpenAlarmEnable": "布尔开报警使能",
"BoolOpenRestrainExpressions": "布尔开报警约束",
"BoolOpenAlarmText": "布尔开报警文本",

View File

@@ -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>
/// 事件类型

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>6.0.5.13</Version>
<Version>6.0.5.14</Version>
</PropertyGroup>
<ItemGroup>

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)
{

View File

@@ -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)