build: 10.9.67

feat: 报警恢复增加延时功能
refactor: 移除通讯任务时,设置设备、变量离线状态

fix: 罗克韦尔PLC通讯超时错误
This commit is contained in:
Diego
2025-07-24 13:25:55 +08:00
parent a4aa000cf0
commit 4ce843182f
12 changed files with 91 additions and 32 deletions

View File

@@ -13,7 +13,7 @@
<ItemGroup>
<PackageReference Include="BootstrapBlazor.TableExport" Version="9.2.6" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
<PackageReference Include="BootstrapBlazor" Version="9.8.1" />
<PackageReference Include="BootstrapBlazor" Version="9.8.2" />
</ItemGroup>
<ItemGroup>

View File

@@ -5,7 +5,7 @@
<TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.0.2" />
<PackageReference Include="BootstrapBlazor.FontAwesome" Version="9.1.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -1,10 +1,10 @@
<Project>
<PropertyGroup>
<PluginVersion>10.9.66</PluginVersion>
<ProPluginVersion>10.9.66</ProPluginVersion>
<DefaultVersion>10.9.66</DefaultVersion>
<AuthenticationVersion>2.9.24</AuthenticationVersion>
<PluginVersion>10.9.67</PluginVersion>
<ProPluginVersion>10.9.67</ProPluginVersion>
<DefaultVersion>10.9.67</DefaultVersion>
<AuthenticationVersion>2.9.27</AuthenticationVersion>
<SourceGeneratorVersion>10.9.24</SourceGeneratorVersion>
<NET8Version>8.0.18</NET8Version>
<NET9Version>9.0.7</NET9Version>

View File

@@ -238,7 +238,7 @@ public abstract class TcpCustomDataHandlingAdapter<TRequest> : SingleStreamDataH
// 如果缓存的数据长度超过设定的最大包大小,则抛出异常。
if (this.m_tempByteBlock.Length > this.MaxPackageSize)
{
throw new Exception("缓存的数据长度大于设定值的情况下未收到解析信号");
throw new Exception($"The parsed signal was not received when the cached data length {m_tempByteBlock.Length} exceeds the set value {MaxPackageSize}");
}
// 将字节块指针移到末尾。
@@ -306,7 +306,7 @@ public abstract class TcpCustomDataHandlingAdapter<TRequest> : SingleStreamDataH
if (this.m_tempByteBlock.Length > this.MaxPackageSize)
{
this.OnError(default, "缓存的数据长度大于设定值的情况下未收到解析信号", true, true);
this.OnError(default, $"The parsed signal was not received when the cached data length {m_tempByteBlock.Length} exceeds the set value {MaxPackageSize}", true, true);
}
}
if (this.UpdateCacheTimeWhenRev)

View File

@@ -18,7 +18,7 @@ public enum EventTypeEnum
/// <summary>
/// 准备报警
/// </summary>
Prepare,
PrepareAlarm,
/// <summary>
/// 报警产生
@@ -34,4 +34,9 @@ public enum EventTypeEnum
/// 报警恢复
/// </summary>
Finish,
/// <summary>
/// 准备恢复
/// </summary>
PrepareFinish,
}

View File

@@ -21,7 +21,8 @@ namespace ThingsGateway.Gateway.Application;
/// </summary>
public partial class VariableRuntime : Variable, IVariable, IDisposable
{
private DateTime? prepareEventTime;
private DateTime? prepareAlarmEventTime;
private DateTime? prepareFinishEventTime;
private EventTypeEnum? eventType;
private AlarmTypeEnum? alarmType { get; set; }

View File

@@ -55,7 +55,12 @@ public partial class VariableRuntime : Variable, IVariable, IDisposable
/// 事件时间
/// </summary>
[AutoGenerateColumn(Ignore = true)]
internal DateTime? PrepareEventTime { get => prepareEventTime; set => prepareEventTime = value; }
internal DateTime? PrepareAlarmEventTime { get => prepareAlarmEventTime; set => prepareAlarmEventTime = value; }
/// <summary>
/// 事件时间
/// </summary>
[AutoGenerateColumn(Ignore = true)]
internal DateTime? PrepareFinishEventTime { get => prepareFinishEventTime; set => prepareFinishEventTime = value; }
/// <summary>
/// 变化时间

View File

@@ -284,16 +284,16 @@ internal sealed class AlarmTask : IDisposable
//添加报警延时策略
if (delay > 0)
{
if (item.EventType != EventTypeEnum.Alarm && item.EventType != EventTypeEnum.Prepare)
if (item.EventType != EventTypeEnum.Alarm && item.EventType != EventTypeEnum.PrepareAlarm)
{
item.EventType = EventTypeEnum.Prepare;//准备报警
item.PrepareEventTime = now;
item.EventType = EventTypeEnum.PrepareAlarm;//准备报警
item.PrepareAlarmEventTime = now;
}
else
{
if (item.EventType == EventTypeEnum.Prepare)
if (item.EventType == EventTypeEnum.PrepareAlarm)
{
if ((now - item.PrepareEventTime!.Value).TotalSeconds > delay)
if ((now - item.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
{
//超过延时时间,触发报警
item.EventType = EventTypeEnum.Alarm;
@@ -304,7 +304,7 @@ internal sealed class AlarmTask : IDisposable
item.AlarmCode = item.Value.ToString();
item.RecoveryCode = string.Empty;
item.AlarmText = text;
item.PrepareEventTime = null;
item.PrepareAlarmEventTime = null;
changed = true;
}
@@ -312,9 +312,9 @@ internal sealed class AlarmTask : IDisposable
else if (item.EventType == EventTypeEnum.Alarm && item.AlarmType != alarmEnum)
{
//报警类型改变,重新计时
if (item.PrepareEventTime == null)
item.PrepareEventTime = now;
if ((now - item.PrepareEventTime!.Value).TotalSeconds > delay)
if (item.PrepareAlarmEventTime == null)
item.PrepareAlarmEventTime = now;
if ((now - item.PrepareAlarmEventTime!.Value).TotalMilliseconds > delay)
{
//超过延时时间,触发报警
item.EventType = EventTypeEnum.Alarm;
@@ -325,7 +325,7 @@ internal sealed class AlarmTask : IDisposable
item.AlarmCode = item.Value.ToString();
item.RecoveryCode = string.Empty;
item.AlarmText = text;
item.PrepareEventTime = null;
item.PrepareAlarmEventTime = null;
changed = true;
}
}
@@ -346,24 +346,64 @@ internal sealed class AlarmTask : IDisposable
item.AlarmCode = item.Value.ToString();
item.RecoveryCode = string.Empty;
item.AlarmText = text;
item.PrepareAlarmEventTime = null;
changed = true;
}
}
else if (eventEnum == EventTypeEnum.Finish)
{
// 如果是需恢复报警事件
// 获取旧的报警信息
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
var now = DateTime.Now;
//添加报警延时策略
if (delay > 0)
{
item.AlarmType = oldAlarm.AlarmType;
item.EventType = eventEnum;
item.AlarmLimit = oldAlarm.AlarmLimit;
item.AlarmCode = oldAlarm.AlarmCode;
item.RecoveryCode = item.Value.ToString();
item.AlarmText = oldAlarm.AlarmText;
item.EventTime = DateTime.Now;
if (item.EventType != EventTypeEnum.Finish && item.EventType != EventTypeEnum.PrepareFinish)
{
item.EventType = EventTypeEnum.PrepareFinish;//准备报警
item.PrepareFinishEventTime = now;
}
else
{
if (item.EventType == EventTypeEnum.PrepareFinish)
{
if ((now - item.PrepareFinishEventTime!.Value).TotalMilliseconds > delay)
{
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
{
item.AlarmType = oldAlarm.AlarmType;
item.EventType = eventEnum;
item.AlarmLimit = oldAlarm.AlarmLimit;
item.AlarmCode = oldAlarm.AlarmCode;
item.RecoveryCode = item.Value.ToString();
item.AlarmText = oldAlarm.AlarmText;
item.EventTime = DateTime.Now;
item.PrepareFinishEventTime = null;
changed = true;
}
}
}
else
{
return;
}
}
}
else
{
// 如果是需恢复报警事件
// 获取旧的报警信息
if (GlobalData.RealAlarmIdVariables.TryGetValue(item.Id, out var oldAlarm))
{
item.AlarmType = oldAlarm.AlarmType;
item.EventType = eventEnum;
item.AlarmLimit = oldAlarm.AlarmLimit;
item.AlarmCode = oldAlarm.AlarmCode;
item.RecoveryCode = item.Value.ToString();
item.AlarmText = oldAlarm.AlarmText;
item.EventTime = DateTime.Now;
item.PrepareFinishEventTime = null;
changed = true;
}
}
changed = true;
}
// 触发报警变化事件

View File

@@ -333,6 +333,8 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
}
}
driver.IdVariableRuntimes.ForEach(a => a.Value.SetErrorMessage(null));
CancellationTokenSources.TryAdd(driver.DeviceId, cts);
_ = Task.Factory.StartNew((state) => DriverStart(state, token), driver, token);
@@ -395,17 +397,21 @@ internal sealed class DeviceThreadManage : IAsyncDisposable, IDeviceThreadManage
// 查找具有指定设备ID的驱动程序对象
if (Drivers.TryRemove(deviceId, out var driver))
{
driver.CurrentDevice.SetDeviceStatus(now, false, "Communication connection has been removed");
if (IsCollectChannel == true)
{
foreach (var a in driver.IdVariableRuntimes)
{
a.Value.SetValue(a.Value.Value, now, false);
a.Value.SetErrorMessage("Communication connection has been removed");
if (a.Value.SaveValue && !a.Value.DynamicVariable)
{
saveVariableRuntimes.Add(a.Value);
}
}
}
}
// 取消驱动程序的操作

View File

@@ -53,6 +53,8 @@
<TableColumn Field="@context.BindUrl" FieldExpression=@(() => context.BindUrl) ShowTips=true Filterable=true Sortable=true Visible=false />
<TableColumn Field="@context.MaxClientCount" FieldExpression=@(() => context.MaxClientCount) ShowTips=true Filterable=true Sortable=true Visible=false />
<TableColumn Field="@context.MaxConcurrentCount" FieldExpression=@(() => context.MaxConcurrentCount) ShowTips=true Filterable=true Sortable=true Visible=false />
<TableColumn Field="@context.DtuIdHex" FieldExpression=@(() => context.DtuIdHex) ShowTips=true Filterable=true Sortable=true Visible=false />
<TableColumn Field="@context.HeartbeatHex" FieldExpression=@(() => context.HeartbeatHex) ShowTips=true Filterable=true Sortable=true Visible=false />
<TableColumn @bind-Field="@context.Id" Filterable=true Sortable=true Visible="false" DefaultSort=true DefaultSortOrder="SortOrder.Asc" />