diff --git a/DMS.Application/DTOs/VariableDto.cs b/DMS.Application/DTOs/VariableDto.cs
index b39ae39..91085e1 100644
--- a/DMS.Application/DTOs/VariableDto.cs
+++ b/DMS.Application/DTOs/VariableDto.cs
@@ -14,34 +14,6 @@ public class VariableDto
public string DataValue { get; set; }
public double NumericValue { get; set; }
public string DisplayValue { get; set; }
-
- ///
- /// 更新数值属性,根据DataValue的值进行转换。
- ///
- public void UpdateNumericValue()
- {
- if (string.IsNullOrEmpty(DataValue))
- {
- NumericValue = 0.0;
- return;
- }
-
- // 尝试将字符串转换为数值
- if (double.TryParse(DataValue, out double numericValue))
- {
- NumericValue = numericValue;
- }
- // 如果是布尔值
- else if (bool.TryParse(DataValue, out bool boolValue))
- {
- NumericValue = boolValue ? 1.0 : 0.0;
- }
- // 如果无法转换,保持为0.0
- else
- {
- NumericValue = 0.0;
- }
- }
public VariableTableDto? VariableTable { get; set; }
public List? MqttAliases { get; set; } = new List();
public SignalType SignalType { get; set; }
diff --git a/DMS.Application/Events/VariableValueChangedEventArgs.cs b/DMS.Application/Events/VariableValueChangedEventArgs.cs
deleted file mode 100644
index e72e3f2..0000000
--- a/DMS.Application/Events/VariableValueChangedEventArgs.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-using System;
-
-namespace DMS.Application.Events;
-
-///
-/// 变量值改变事件参数
-///
-public class VariableValueChangedEventArgs : EventArgs
-{
- ///
- /// 变量ID
- ///
- public int VariableId { get; }
-
- ///
- /// 变量名称
- ///
- public string VariableName { get; }
-
- ///
- /// 旧值
- ///
- public string OldValue { get; }
-
- ///
- /// 新值
- ///
- public string NewValue { get; }
-
- ///
- /// 值改变时间
- ///
- public DateTime ChangeTime { get; }
-
- ///
- /// 初始化VariableValueChangedEventArgs类的新实例
- ///
- /// 变量ID
- /// 变量名称
- /// 旧值
- /// 新值
- public VariableValueChangedEventArgs(int variableId, string variableName, string oldValue, string newValue)
- {
- VariableId = variableId;
- VariableName = variableName;
- OldValue = oldValue;
- NewValue = newValue;
- ChangeTime = DateTime.Now;
- }
-}
\ No newline at end of file
diff --git a/DMS.Application/Interfaces/IDataProcessingService.cs b/DMS.Application/Interfaces/IDataProcessingService.cs
index 06d21ff..9108724 100644
--- a/DMS.Application/Interfaces/IDataProcessingService.cs
+++ b/DMS.Application/Interfaces/IDataProcessingService.cs
@@ -1,6 +1,7 @@
using DMS.Core.Models;
using System.Threading.Tasks;
using DMS.Application.DTOs;
+using DMS.Application.Models;
namespace DMS.Application.Interfaces;
@@ -21,5 +22,5 @@ public interface IDataProcessingService
///
/// 要入队的变量数据。
/// 一个表示入队操作的 ValueTask。
- ValueTask EnqueueAsync(VariableDto data);
+ ValueTask EnqueueAsync(VariableContext data);
}
\ No newline at end of file
diff --git a/DMS.Application/Interfaces/IEventService.cs b/DMS.Application/Interfaces/IEventService.cs
index a4b95f8..6b96af4 100644
--- a/DMS.Application/Interfaces/IEventService.cs
+++ b/DMS.Application/Interfaces/IEventService.cs
@@ -1,5 +1,7 @@
using System;
+using DMS.Application.DTOs.Events;
using DMS.Application.Events;
+using DMS.Core.Events;
namespace DMS.Application.Interfaces;
@@ -29,7 +31,7 @@ public interface IEventService
///
/// 变量值改变事件
///
- event EventHandler VariableValueChanged;
+ event EventHandler OnVariableValueChanged;
///
/// 触发变量值改变事件
@@ -67,4 +69,16 @@ public interface IEventService
/// 事件发送者
/// 设备状态改变事件参数
void RaiseDeviceConnectChanged(object sender, DeviceConnectChangedEventArgs e);
+
+ ///
+ /// 变量值改变事件
+ ///
+ event EventHandler OnVariableChanged;
+
+ ///
+ /// 触发变量值改变事件
+ ///
+ /// 事件发送者
+ /// 变量值改变事件参数
+ void RaiseVariableChanged(object sender, VariableChangedEventArgs e);
}
\ No newline at end of file
diff --git a/DMS.Application/Models/VariableContext.cs b/DMS.Application/Models/VariableContext.cs
index 1efe679..4a81a1d 100644
--- a/DMS.Application/Models/VariableContext.cs
+++ b/DMS.Application/Models/VariableContext.cs
@@ -6,12 +6,15 @@ namespace DMS.Application.Models
public class VariableContext
{
public VariableDto Data { get; set; }
+
+ public object NewValue { get; set; }
public bool IsHandled { get; set; }
- public VariableContext(VariableDto data)
+ public VariableContext(VariableDto data, object newValue=null)
{
Data = data;
IsHandled = false; // 默认未处理
+ NewValue = newValue;
}
}
}
\ No newline at end of file
diff --git a/DMS.Application/Services/AppDataCenterService.cs b/DMS.Application/Services/AppDataCenterService.cs
index 5fcc80f..f3b4e47 100644
--- a/DMS.Application/Services/AppDataCenterService.cs
+++ b/DMS.Application/Services/AppDataCenterService.cs
@@ -11,6 +11,7 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using System;
using System.Linq;
+using DMS.Core.Events;
namespace DMS.Application.Services;
diff --git a/DMS.Application/Services/EventService.cs b/DMS.Application/Services/EventService.cs
index caf85cf..79b979d 100644
--- a/DMS.Application/Services/EventService.cs
+++ b/DMS.Application/Services/EventService.cs
@@ -1,6 +1,8 @@
using System;
+using DMS.Application.DTOs.Events;
using DMS.Application.Events;
using DMS.Application.Interfaces;
+using DMS.Core.Events;
namespace DMS.Application.Services;
@@ -60,11 +62,26 @@ public class EventService : IEventService
#endregion
#region 变量事件
+ ///
+ /// 变量值改变事件
+ ///
+ public event EventHandler OnVariableChanged;
+
+ ///
+ /// 触发变量值改变事件
+ ///
+ /// 事件发送者
+ /// 变量值改变事件参数
+ public void RaiseVariableChanged(object sender, VariableChangedEventArgs e)
+ {
+ OnVariableChanged?.Invoke(sender, e);
+ }
+
///
/// 变量值改变事件
///
- public event EventHandler VariableValueChanged;
+ public event EventHandler OnVariableValueChanged;
///
/// 触发变量值改变事件
@@ -73,7 +90,7 @@ public class EventService : IEventService
/// 变量值改变事件参数
public void RaiseVariableValueChanged(object sender, VariableValueChangedEventArgs e)
{
- VariableValueChanged?.Invoke(sender, e);
+ OnVariableValueChanged?.Invoke(sender, e);
}
#endregion
diff --git a/DMS.Application/Services/IVariableManagementService.cs b/DMS.Application/Services/IVariableManagementService.cs
index c4df21f..517ef62 100644
--- a/DMS.Application/Services/IVariableManagementService.cs
+++ b/DMS.Application/Services/IVariableManagementService.cs
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
+using DMS.Core.Events;
using DMS.Core.Models;
namespace DMS.Application.Services;
@@ -56,16 +57,4 @@ public interface IVariableManagementService
/// 在内存中删除变量
///
void RemoveVariableFromMemory(int variableId, ConcurrentDictionary variableTables);
-
- void VariableValueChanged(VariableValueChangedEventArgs eventArgs);
-
- ///
- /// 当变量数据发生变化时触发
- ///
- event EventHandler OnVariableChanged;
-
- ///
- /// 当变量数据发生变化时触发
- ///
- event EventHandler OnVariableValueChanged;
}
\ No newline at end of file
diff --git a/DMS.Application/Services/Processors/DataProcessingService.cs b/DMS.Application/Services/Processors/DataProcessingService.cs
index 8ad84f4..605c4e3 100644
--- a/DMS.Application/Services/Processors/DataProcessingService.cs
+++ b/DMS.Application/Services/Processors/DataProcessingService.cs
@@ -50,14 +50,13 @@ public class DataProcessingService : BackgroundService, IDataProcessingService
/// 将一个变量数据项异步推入处理队列。
///
/// 要入队的变量数据。
- public async ValueTask EnqueueAsync(VariableDto data)
+ public async ValueTask EnqueueAsync(VariableContext context)
{
- if (data == null)
+ if (context == null)
{
return;
}
- var context = new VariableContext(data);
// 将数据项写入 Channel,供后台服务处理。
await _queue.Writer.WriteAsync(context);
}
diff --git a/DMS.Application/Services/Processors/TriggerProcessor.cs b/DMS.Application/Services/Processors/TriggerProcessor.cs
new file mode 100644
index 0000000..d828f51
--- /dev/null
+++ b/DMS.Application/Services/Processors/TriggerProcessor.cs
@@ -0,0 +1,34 @@
+using DMS.Application.Interfaces;
+using DMS.Application.Models;
+using DMS.Application.Services.Triggers;
+using Microsoft.Extensions.Logging;
+
+namespace DMS.Application.Services.Processors;
+
+public class TriggerProcessor : IVariableProcessor
+{
+ private readonly ITriggerEvaluationService _triggerEvaluationService;
+ private readonly ILogger _logger;
+
+ public TriggerProcessor(ITriggerEvaluationService triggerEvaluationService, ILogger logger)
+ {
+ _triggerEvaluationService = triggerEvaluationService;
+ _logger = logger;
+ }
+
+ public async Task ProcessAsync(VariableContext context)
+ {
+ // try
+ // {
+ // // 调用触发器评估服务来评估与变量关联的所有激活状态的触发器
+ // await _triggerEvaluationService.EvaluateTriggersAsync(context.Data.Id, context.Data.DataValue);
+ //
+ // _logger.LogDebug("触发器评估完成,变量 ID: {VariableId}", context.Data.Id);
+ // }
+ // catch (Exception ex)
+ // {
+ // _logger.LogError(ex, "评估变量 {VariableId} 的触发器时发生错误", context.Data.Id);
+ // // 不抛出异常,避免影响其他处理器
+ // }
+ }
+}
\ No newline at end of file
diff --git a/DMS.Application/Services/Processors/UpdateViewProcessor.cs b/DMS.Application/Services/Processors/UpdateViewProcessor.cs
new file mode 100644
index 0000000..ae45de2
--- /dev/null
+++ b/DMS.Application/Services/Processors/UpdateViewProcessor.cs
@@ -0,0 +1,29 @@
+using DMS.Application.Interfaces;
+using DMS.Application.Models;
+using DMS.Core.Events;
+
+namespace DMS.Application.Services.Processors;
+
+public class UpdateViewProcessor: IVariableProcessor
+{
+ private readonly IEventService _eventService;
+
+ public UpdateViewProcessor(IEventService eventService)
+ {
+ _eventService = eventService;
+ }
+
+ public async Task ProcessAsync(VariableContext context)
+ {
+ // 触发变量值变更事件
+ var eventArgs = new VariableValueChangedEventArgs(
+ context.Data.Id,
+ context.Data.Name,
+ context.Data.DataValue,
+ context.NewValue.ToString()??"",
+ DateTime.Now);
+
+ _eventService.RaiseVariableValueChanged(this,eventArgs);
+
+ }
+}
\ No newline at end of file
diff --git a/DMS.Application/Services/Processors/ValueConvertProcessor.cs b/DMS.Application/Services/Processors/ValueConvertProcessor.cs
new file mode 100644
index 0000000..ca8cd42
--- /dev/null
+++ b/DMS.Application/Services/Processors/ValueConvertProcessor.cs
@@ -0,0 +1,136 @@
+using System.Globalization;
+using DMS.Application.DTOs;
+using DMS.Application.Interfaces;
+using DMS.Application.Models;
+using Microsoft.Extensions.Logging;
+
+namespace DMS.Application.Services.Processors;
+
+public class ValueConvertProcessor : IVariableProcessor
+{
+ private readonly ILogger _logger;
+
+ public ValueConvertProcessor(ILogger logger)
+ {
+ _logger = logger;
+ }
+ public async Task ProcessAsync(VariableContext context)
+ {
+ var oldValue = context.Data.DataValue;
+ ConvertS7ValueToStringAndNumeric(context.Data, context.NewValue);
+ context.Data.UpdatedAt = DateTime.Now;
+ // 如何值没有变化则中断处理
+ if (context.Data.DataValue!=oldValue)
+ {
+ context.IsHandled = true;
+ }
+ }
+ ///
+ /// 将从 S7 读取的对象值转换为字符串表示和数值表示
+ ///
+ /// 关联的变量 DTO
+ /// 从 S7 读取的原始对象值
+ /// (字符串表示, 数值表示)
+ private void ConvertS7ValueToStringAndNumeric(VariableDto variable, object value)
+ {
+ if (value == null)
+ return ;
+
+ // 首先根据 value 的实际运行时类型进行匹配和转换
+ string directConversion = null;
+ double numericValue = 0.0;
+ bool numericParsed = false;
+
+ switch (value)
+ {
+ case double d:
+ directConversion = d.ToString("G17", CultureInfo.InvariantCulture);
+ numericValue = d;
+ numericParsed = true;
+ break;
+ case float f:
+ directConversion = f.ToString("G9", CultureInfo.InvariantCulture);
+ numericValue = f;
+ numericParsed = true;
+ break;
+ case int i:
+ directConversion = i.ToString(CultureInfo.InvariantCulture);
+ numericValue = i;
+ numericParsed = true;
+ break;
+ case uint ui:
+ directConversion = ui.ToString(CultureInfo.InvariantCulture);
+ numericValue = ui;
+ numericParsed = true;
+ break;
+ case short s:
+ directConversion = s.ToString(CultureInfo.InvariantCulture);
+ numericValue = s;
+ numericParsed = true;
+ break;
+ case ushort us:
+ directConversion = us.ToString(CultureInfo.InvariantCulture);
+ numericValue = us;
+ numericParsed = true;
+ break;
+ case byte b:
+ directConversion = b.ToString(CultureInfo.InvariantCulture);
+ numericValue = b;
+ numericParsed = true;
+ break;
+ case sbyte sb:
+ directConversion = sb.ToString(CultureInfo.InvariantCulture);
+ numericValue = sb;
+ numericParsed = true;
+ break;
+ case long l:
+ directConversion = l.ToString(CultureInfo.InvariantCulture);
+ numericValue = l;
+ numericParsed = true;
+ break;
+ case ulong ul:
+ directConversion = ul.ToString(CultureInfo.InvariantCulture);
+ numericValue = ul;
+ numericParsed = true;
+ break;
+ case bool boolValue:
+ directConversion = boolValue.ToString().ToLowerInvariant();
+ numericValue = boolValue ? 1.0 : 0.0;
+ numericParsed = true;
+ break;
+ case string str:
+ directConversion = str;
+ // 尝试从字符串解析数值
+ if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedFromStr))
+ {
+ numericValue = parsedFromStr;
+ numericParsed = true;
+ }
+ break;
+ default:
+ // 对于未预期的类型,记录日志
+ _logger.LogWarning($"变量 {variable.Name} 读取到未预期的数据类型: {value.GetType().Name}, 值: {value}");
+ directConversion = value.ToString() ?? string.Empty;
+ // 尝试从 ToString() 结果解析数值
+ if (double.TryParse(directConversion, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsedFromObj))
+ {
+ numericValue = parsedFromObj;
+ numericParsed = true;
+ }
+ break;
+ }
+
+ // 如果直接转换成功,直接返回
+
+ // 如果直接转换未能解析数值,并且变量有明确的 DataType,可以尝试更精细的解析
+ // (这部分逻辑在上面的 switch 中已经处理了大部分情况,这里作为后备)
+ // 在这个实现中,我们主要依赖于 value 的实际类型进行转换,因为这通常更可靠。
+ // 如果需要,可以根据 variable.DataType 添加额外的解析逻辑。
+
+ // 返回最终结果
+ variable.DataValue = directConversion ?? value.ToString() ?? string.Empty;
+ variable.NumericValue = numericValue;
+ }
+
+
+}
\ No newline at end of file
diff --git a/DMS.Application/Services/VariableManagementService.cs b/DMS.Application/Services/VariableManagementService.cs
index 47e0e9e..493f36c 100644
--- a/DMS.Application/Services/VariableManagementService.cs
+++ b/DMS.Application/Services/VariableManagementService.cs
@@ -1,14 +1,8 @@
-using AutoMapper;
+using System.Collections.Concurrent;
using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
-using DMS.Core.Models;
using DMS.Application.Interfaces;
-using DMS.Core.Interfaces;
-using DMS.Core.Enums;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-using System;
+using DMS.Core.Events;
namespace DMS.Application.Services;
@@ -18,24 +12,18 @@ namespace DMS.Application.Services;
public class VariableManagementService : IVariableManagementService
{
private readonly IVariableAppService _variableAppService;
+ private readonly IEventService _eventService;
private readonly IAppDataStorageService _appDataStorageService;
private readonly IDataProcessingService _dataProcessingService;
- ///
- /// 当变量数据发生变化时触发
- ///
- public event EventHandler OnVariableChanged;
-
- ///
- /// 当变量数据发生变化时触发
- ///
- public event EventHandler OnVariableValueChanged;
public VariableManagementService(IVariableAppService variableAppService,
+ IEventService eventService,
IAppDataStorageService appDataStorageService,
IDataProcessingService dataProcessingService)
{
_variableAppService = variableAppService;
+ _eventService = eventService;
_appDataStorageService = appDataStorageService;
_dataProcessingService = dataProcessingService;
}
@@ -111,7 +99,7 @@ public class VariableManagementService : IVariableManagementService
if (_appDataStorageService.Variables.TryAdd(variableDto.Id, variableDto))
{
- OnVariableChanged?.Invoke(
+ _eventService.RaiseVariableChanged(
this, new VariableChangedEventArgs(DataChangeType.Added, variableDto, variableTableDto));
}
}
@@ -129,7 +117,7 @@ public class VariableManagementService : IVariableManagementService
}
_appDataStorageService.Variables.AddOrUpdate(variableDto.Id, variableDto, (key, oldValue) => variableDto);
- OnVariableChanged?.Invoke(
+ _eventService.RaiseVariableChanged(
this, new VariableChangedEventArgs(DataChangeType.Updated, variableDto, variableTableDto));
}
@@ -147,14 +135,8 @@ public class VariableManagementService : IVariableManagementService
variableTable.Variables.Remove(variableDto);
}
- OnVariableChanged?.Invoke(
+ _eventService.RaiseVariableChanged(
this, new VariableChangedEventArgs(DataChangeType.Deleted, variableDto, variableTableDto));
}
}
-
- public void VariableValueChanged(VariableValueChangedEventArgs eventArgs)
- {
- // 触发事件,通知DataEventService等监听者
- OnVariableValueChanged?.Invoke(this, eventArgs);
- }
}
\ No newline at end of file
diff --git a/DMS.Core/Models/VariableValueChangedEventArgs.cs b/DMS.Core/Events/VariableValueChangedEventArgs.cs
similarity index 97%
rename from DMS.Core/Models/VariableValueChangedEventArgs.cs
rename to DMS.Core/Events/VariableValueChangedEventArgs.cs
index 76f8376..ed9067e 100644
--- a/DMS.Core/Models/VariableValueChangedEventArgs.cs
+++ b/DMS.Core/Events/VariableValueChangedEventArgs.cs
@@ -1,4 +1,4 @@
-namespace DMS.Core.Models
+namespace DMS.Core.Events
{
///
/// 变量值变更事件参数
diff --git a/DMS.Infrastructure/Interfaces/Services/IS7ServiceManager.cs b/DMS.Infrastructure/Interfaces/Services/IS7ServiceManager.cs
index f1f4ae4..6e490c4 100644
--- a/DMS.Infrastructure/Interfaces/Services/IS7ServiceManager.cs
+++ b/DMS.Infrastructure/Interfaces/Services/IS7ServiceManager.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using DMS.Application.DTOs;
+using DMS.Infrastructure.Services;
namespace DMS.Infrastructure.Interfaces.Services
{
@@ -65,5 +66,10 @@ namespace DMS.Infrastructure.Interfaces.Services
/// 批量断开设备连接
///
Task DisconnectDevicesAsync(IEnumerable deviceIds, CancellationToken cancellationToken = default);
+
+ ///
+ /// 获取所有监控的设备ID
+ ///
+ List GetAllDeviceContexts();
}
}
\ No newline at end of file
diff --git a/DMS.Infrastructure/Services/OpcUaServiceManager.cs b/DMS.Infrastructure/Services/OpcUaServiceManager.cs
index 69d40c7..4ed44de 100644
--- a/DMS.Infrastructure/Services/OpcUaServiceManager.cs
+++ b/DMS.Infrastructure/Services/OpcUaServiceManager.cs
@@ -3,13 +3,14 @@ using System.Diagnostics;
using DMS.Application.DTOs;
using DMS.Application.Events;
using DMS.Application.Interfaces;
+using DMS.Application.Models;
using DMS.Core.Enums;
using DMS.Infrastructure.Configuration;
using DMS.Infrastructure.Interfaces.Services;
using DMS.Infrastructure.Models;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
-using VariableValueChangedEventArgs = DMS.Core.Models.VariableValueChangedEventArgs;
+using VariableValueChangedEventArgs = DMS.Core.Events.VariableValueChangedEventArgs;
namespace DMS.Infrastructure.Services
{
@@ -329,30 +330,8 @@ namespace DMS.Infrastructure.Services
{
if (context.Variables.TryGetValue(opcUaNode.NodeId.ToString(), out var variable))
{
- // 保存旧值
- var oldValue = variable.DataValue;
- var newValue = opcUaNode.Value.ToString();
-
- // 更新变量值
- variable.DataValue = newValue;
- variable.DisplayValue = newValue;
- variable.UpdateNumericValue(); // 更新数值属性
- variable.UpdatedAt = DateTime.Now;
-
- _logger.LogDebug($"节点:{variable.OpcUaNodeId}值发生了变化:{newValue}");
-
- // 触发变量值变更事件
- var eventArgs = new VariableValueChangedEventArgs(
- variable.Id,
- variable.Name,
- oldValue,
- newValue,
- variable.UpdatedAt);
-
- _appDataCenterService.VariableManagementService.VariableValueChanged(eventArgs);
-
// 推送到数据处理队列
- await _dataProcessingService.EnqueueAsync(variable);
+ await _dataProcessingService.EnqueueAsync(new VariableContext(variable,opcUaNode.Value));
break;
}
}
diff --git a/DMS.Infrastructure/Services/OptimizedS7BackgroundService.cs b/DMS.Infrastructure/Services/OptimizedS7BackgroundService.cs
index 3695902..6918c43 100644
--- a/DMS.Infrastructure/Services/OptimizedS7BackgroundService.cs
+++ b/DMS.Infrastructure/Services/OptimizedS7BackgroundService.cs
@@ -12,6 +12,8 @@ using Microsoft.Extensions.Logging;
using DMS.Core.Interfaces;
using DMS.Infrastructure.Interfaces.Services;
using System.Diagnostics;
+using System.Globalization;
+using DMS.Application.Models;
namespace DMS.Infrastructure.Services;
@@ -32,25 +34,8 @@ public class OptimizedS7BackgroundService : BackgroundService
// 存储每个设备的变量按轮询间隔分组
private readonly ConcurrentDictionary>> _variablesByPollingInterval = new();
-
- // 模拟 PollingIntervals,实际应用中可能从配置或数据库加载
- private static readonly Dictionary PollingIntervals = new Dictionary
- {
- { 10, TimeSpan.FromMilliseconds(10) }, // TenMilliseconds
- { 100, TimeSpan.FromMilliseconds(100) }, // HundredMilliseconds
- { 500, TimeSpan.FromMilliseconds(500) }, // FiveHundredMilliseconds
- { 1000, TimeSpan.FromMilliseconds(1000) }, // OneSecond
- { 5000, TimeSpan.FromMilliseconds(5000) }, // FiveSeconds
- { 10000, TimeSpan.FromMilliseconds(10000) }, // TenSeconds
- { 20000, TimeSpan.FromMilliseconds(20000) }, // TwentySeconds
- { 30000, TimeSpan.FromMilliseconds(30000) }, // ThirtySeconds
- { 60000, TimeSpan.FromMilliseconds(60000) }, // OneMinute
- { 180000, TimeSpan.FromMilliseconds(180000) }, // ThreeMinutes
- { 300000, TimeSpan.FromMilliseconds(300000) }, // FiveMinutes
- { 600000, TimeSpan.FromMilliseconds(600000) }, // TenMinutes
- { 1800000, TimeSpan.FromMilliseconds(1800000) } // ThirtyMinutes
- };
-
+
+
///
/// 构造函数,注入数据服务和数据处理服务。
///
@@ -108,7 +93,7 @@ public class OptimizedS7BackgroundService : BackgroundService
// 持续轮询,直到取消请求或需要重新加载
while (!stoppingToken.IsCancellationRequested && _reloadSemaphore.CurrentCount == 0)
{
- await PollS7VariablesByPollingIntervalAsync(stoppingToken);
+ await PollS7VariablesAsync(stoppingToken);
await Task.Delay(_s7PollOnceSleepTimeMs, stoppingToken);
}
}
@@ -136,28 +121,27 @@ public class OptimizedS7BackgroundService : BackgroundService
{
_variablesByPollingInterval.Clear();
_logger.LogInformation("开始加载S7变量....");
-
+
var s7Devices = _appDataStorageService
.Devices.Values.Where(d => d.Protocol == ProtocolType.S7 && d.IsActive == true)
.ToList();
-
+
foreach (var s7Device in s7Devices)
{
_s7ServiceManager.AddDevice(s7Device);
-
+
// 查找设备中所有要轮询的变量
- var variables = s7Device.VariableTables?.SelectMany(vt => vt.Variables)
- .Where(v => v.IsActive == true && v.Protocol == ProtocolType.S7)
- .ToList() ?? new List();
-
+ var variables = new List();
+
+ foreach (var variableTable in s7Device.VariableTables)
+ {
+ if (variableTable.IsActive && variableTable.Protocol == ProtocolType.S7)
+ {
+ variables.AddRange(variableTable.Variables.Where(v => v.IsActive));
+ }
+ }
+
_s7ServiceManager.UpdateVariables(s7Device.Id, variables);
-
- // 按轮询间隔分组变量
- var variablesByPollingInterval = variables
- .GroupBy(v => v.PollingInterval)
- .ToDictionary(g => g.Key, g => g.ToList());
-
- _variablesByPollingInterval.AddOrUpdate(s7Device.Id, variablesByPollingInterval, (key, oldValue) => variablesByPollingInterval);
}
_logger.LogInformation($"S7 变量加载成功,共加载S7设备:{s7Devices.Count}个");
@@ -175,102 +159,96 @@ public class OptimizedS7BackgroundService : BackgroundService
///
private async Task ConnectS7ServiceAsync(CancellationToken stoppingToken)
{
-
var s7Devices = _appDataStorageService
.Devices.Values.Where(d => d.Protocol == ProtocolType.S7 && d.IsActive == true)
.ToList();
- var deviceIds = s7Devices.Select(d => d.Id).ToList();
+ var deviceIds = s7Devices.Select(d => d.Id)
+ .ToList();
await _s7ServiceManager.ConnectDevicesAsync(deviceIds, stoppingToken);
-
+
_logger.LogInformation("已连接所有S7设备");
}
///
/// 按轮询间隔轮询S7变量
///
- private async Task PollS7VariablesByPollingIntervalAsync(CancellationToken stoppingToken)
+ private async Task PollS7VariablesAsync(CancellationToken stoppingToken)
{
try
{
- var pollTasks = new List();
-
- // 为每个设备创建轮询任务
- foreach (var deviceEntry in _variablesByPollingInterval)
+ var s7DeviceContexts = _s7ServiceManager.GetAllDeviceContexts();
+ foreach (var context in s7DeviceContexts)
{
- var deviceId = deviceEntry.Key;
- var variablesByPollingInterval = deviceEntry.Value;
+ if (stoppingToken.IsCancellationRequested) break;
- // 为每个轮询间隔创建轮询任务
- foreach (var pollingIntervalEntry in variablesByPollingInterval)
+ // 收集该设备所有需要轮询的变量
+ var variablesToPoll = context.Variables.Values.ToList();
+
+ if (variablesToPoll.Any())
{
- var pollingInterval = pollingIntervalEntry.Key;
- var variables = pollingIntervalEntry.Value;
-
- // 检查是否达到轮询时间
- if (ShouldPollVariables(variables, pollingInterval))
- {
- pollTasks.Add(PollVariablesForDeviceAsync(deviceId, variables, stoppingToken));
- }
+ await PollVariablesForDeviceAsync(context, variablesToPoll, stoppingToken);
}
}
-
- await Task.WhenAll(pollTasks);
}
catch (Exception ex)
{
_logger.LogError(ex, $"按轮询间隔轮询S7变量时发生错误:{ex.Message}");
}
}
-
- ///
- /// 检查是否应该轮询变量
- ///
- private bool ShouldPollVariables(List variables, int pollingInterval)
- {
- if (!PollingIntervals.TryGetValue(pollingInterval, out var interval))
- return false;
-
- // 检查是否有任何一个变量需要轮询
- return variables.Any(v => (DateTime.Now - v.UpdatedAt) >= interval);
- }
-
+
+
+
///
/// 轮询设备的变量
///
- private async Task PollVariablesForDeviceAsync(int deviceId, List variables, CancellationToken stoppingToken)
+ private async Task PollVariablesForDeviceAsync(S7DeviceContext context, List variables,
+ CancellationToken stoppingToken)
{
- if (!_appDataStorageService.Devices.TryGetValue(deviceId, out var device))
+ if (!_appDataStorageService.Devices.TryGetValue(context.Device.Id, out var device))
{
- _logger.LogWarning($"轮询时没有找到设备ID:{deviceId}");
+ _logger.LogWarning($"轮询时没有找到设备ID:{context.Device.Id}");
return;
}
-
- if (!_s7ServiceManager.IsDeviceConnected(deviceId))
+
+ var s7Service = context.S7Service;
+ if (s7Service == null || !s7Service.IsConnected)
{
- _logger.LogWarning($"轮询时设备 {device.Name} 没有连接");
+ _logger.LogWarning($"轮询时设备 {device.Name} 没有连接或服务不可用");
return;
}
-
+
try
{
var stopwatch = Stopwatch.StartNew();
-
+
// 按地址分组变量以进行批量读取
- var addresses = variables.Select(v => v.S7Address).ToList();
-
- // 这里应该使用IS7Service来读取变量
- // 由于接口限制,我们暂时跳过实际读取,仅演示逻辑
-
+ var addresses = variables.Where(v=>(DateTime.Now-v.UpdatedAt)>=TimeSpan.FromMilliseconds(v.PollingInterval)).Select(v => v.S7Address)
+ .ToList();
+ if (!addresses.Any())
+ {
+ return;
+ }
+
+ // 批量读取变量值
+ var readResults = await s7Service.ReadVariablesAsync(addresses);
+
stopwatch.Stop();
_logger.LogDebug($"设备 {device.Name} 轮询 {variables.Count} 个变量耗时 {stopwatch.ElapsedMilliseconds} ms");
-
+
// 更新变量值并推送到处理队列
foreach (var variable in variables)
{
- // 模拟读取到的值
- var value = DateTime.Now.Ticks.ToString();
- await UpdateAndEnqueueVariable(variable, value);
+ if (readResults.TryGetValue(variable.S7Address, out var value))
+ {
+
+ // 将更新后的数据推入处理队列。
+ await _dataProcessingService.EnqueueAsync(new VariableContext(variable, value));
+ }
+ else
+ {
+ _logger.LogWarning($"未能从设备 {device.Name} 读取变量 {variable.S7Address} 的值");
+ }
}
}
catch (Exception ex)
@@ -279,26 +257,7 @@ public class OptimizedS7BackgroundService : BackgroundService
}
}
- ///
- /// 更新变量数据,并将其推送到数据处理队列。
- ///
- private async Task UpdateAndEnqueueVariable(VariableDto variable, string value)
- {
- try
- {
- // 更新变量的原始数据值和显示值。
- variable.DataValue = value;
- variable.DisplayValue = value;
- variable.UpdatedAt = DateTime.Now;
-
- // 将更新后的数据推入处理队列。
- await _dataProcessingService.EnqueueAsync(variable);
- }
- catch (Exception ex)
- {
- _logger.LogError(ex, $"更新变量 {variable.Name} 并入队失败:{ex.Message}");
- }
- }
+
///
/// 断开所有 S7 会话。
@@ -306,10 +265,10 @@ public class OptimizedS7BackgroundService : BackgroundService
private async Task DisconnectAllS7SessionsAsync()
{
_logger.LogInformation("正在断开所有 S7 会话...");
-
+
var deviceIds = _s7ServiceManager.GetMonitoredDeviceIds();
await _s7ServiceManager.DisconnectDevicesAsync(deviceIds);
-
+
_logger.LogInformation("已断开所有 S7 会话");
}
}
\ No newline at end of file
diff --git a/DMS.Infrastructure/Services/S7Service.cs b/DMS.Infrastructure/Services/S7Service.cs
index 5876afc..8da82f6 100644
--- a/DMS.Infrastructure/Services/S7Service.cs
+++ b/DMS.Infrastructure/Services/S7Service.cs
@@ -11,6 +11,8 @@ namespace DMS.Infrastructure.Services
///
public class S7Service : IS7Service
{
+ private const int ReadMultipleVarsCount = 10;
+
private Plc _plc;
private readonly ILogger _logger;
@@ -91,13 +93,16 @@ namespace DMS.Infrastructure.Services
{
throw new InvalidOperationException("PLC未连接");
}
+
try
- {
+ {
+ var result = new Dictionary();
var dataItems = addresses.Select(DataItem.FromAddress).ToList();
+
await _plc.ReadMultipleVarsAsync(dataItems);
- var result = new Dictionary();
+
for (int i = 0; i < addresses.Count; i++)
{
result[addresses[i]] = dataItems[i].Value;
diff --git a/DMS.Infrastructure/Services/S7ServiceManager.cs b/DMS.Infrastructure/Services/S7ServiceManager.cs
index a5d4136..fb76c94 100644
--- a/DMS.Infrastructure/Services/S7ServiceManager.cs
+++ b/DMS.Infrastructure/Services/S7ServiceManager.cs
@@ -135,6 +135,13 @@ namespace DMS.Infrastructure.Services
{
return _deviceContexts.Keys.ToList();
}
+ ///
+ /// 获取所有监控的设备ID
+ ///
+ public List GetAllDeviceContexts()
+ {
+ return _deviceContexts.Values.ToList();
+ }
///
/// 连接设备
diff --git a/DMS.WPF/App.xaml.cs b/DMS.WPF/App.xaml.cs
index e6b3e9b..57328f5 100644
--- a/DMS.WPF/App.xaml.cs
+++ b/DMS.WPF/App.xaml.cs
@@ -72,6 +72,8 @@ public partial class App : System.Windows.Application
DeviceItemViewModel.EventService = Host.Services.GetRequiredService();
// 初始化数据处理链
var dataProcessingService = Host.Services.GetRequiredService();
+ dataProcessingService.AddProcessor(Host.Services.GetRequiredService());
+ dataProcessingService.AddProcessor(Host.Services.GetRequiredService());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService());
dataProcessingService.AddProcessor(Host.Services.GetRequiredService());
@@ -194,6 +196,8 @@ public partial class App : System.Windows.Application
services.AddSingleton();
services.AddHostedService(provider =>
(DataProcessingService)provider.GetRequiredService());
+ services.AddSingleton();
+ services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
services.AddSingleton();
diff --git a/DMS.WPF/Services/DataEventService.cs b/DMS.WPF/Services/DataEventService.cs
index bf28dda..b91a760 100644
--- a/DMS.WPF/Services/DataEventService.cs
+++ b/DMS.WPF/Services/DataEventService.cs
@@ -6,6 +6,7 @@ using DMS.Application.DTOs;
using DMS.Application.DTOs.Events;
using DMS.Application.Interfaces;
using DMS.Core.Enums;
+using DMS.Core.Events;
using DMS.Core.Models;
using DMS.Message;
using DMS.WPF.Interfaces;
@@ -20,6 +21,7 @@ public class DataEventService : IDataEventService
{
private readonly IMapper _mapper;
private readonly IDataStorageService _dataStorageService;
+ private readonly IEventService _eventService;
private readonly IAppDataCenterService _appDataCenterService;
private readonly IWPFDataService _wpfDataService;
@@ -28,16 +30,18 @@ public class DataEventService : IDataEventService
///
public DataEventService(IMapper mapper,
IDataStorageService dataStorageService,
+ IEventService eventService,
IAppDataCenterService appDataCenterService,
IWPFDataService wpfDataService)
{
_mapper = mapper;
_dataStorageService = dataStorageService;
+ _eventService = eventService;
_appDataCenterService = appDataCenterService;
_wpfDataService = wpfDataService;
// 监听变量值变更事件
- _appDataCenterService.VariableManagementService.OnVariableValueChanged += OnVariableValueChanged;
+ _eventService.OnVariableValueChanged += OnVariableValueChanged;
_appDataCenterService.DataLoaderService.OnLoadDataCompleted += OnLoadDataCompleted;
// 监听日志变更事件
// _appDataCenterService.OnLogChanged += _logDataService.OnNlogChanged;