diff --git a/DMS.Infrastructure/Services/OpcUa/OpcUaServiceManager.cs b/DMS.Infrastructure/Services/OpcUa/OpcUaServiceManager.cs index b4027a8..fba08dc 100644 --- a/DMS.Infrastructure/Services/OpcUa/OpcUaServiceManager.cs +++ b/DMS.Infrastructure/Services/OpcUa/OpcUaServiceManager.cs @@ -48,6 +48,7 @@ namespace DMS.Infrastructure.Services.OpcUa _eventService.OnDeviceStateChanged += OnDeviceStateChanged; _eventService.OnDeviceChanged += OnDeviceChanged; _eventService.OnBatchImportVariables += OnBatchImportVariables; + _eventService.OnVariableChanged += OnVariableChanged; } private async void OnDeviceStateChanged(object? sender, DeviceStateChangedEventArgs e) @@ -232,6 +233,22 @@ namespace DMS.Infrastructure.Services.OpcUa } } + /// + /// 获取需要订阅的变量列表 + /// + /// 设备上下文 + /// 需要订阅的变量列表 + private List GetSubscribableVariables(DeviceContext context) + { + if (context?.Variables == null) + return new List(); + + // 返回所有激活且OPC UA更新类型不是None的变量 + return context.Variables.Values + .Where(v => v.IsActive ) + .ToList(); + } + /// /// 处理批量导入变量事件 /// @@ -471,16 +488,25 @@ namespace DMS.Infrastructure.Services.OpcUa /// private async Task SetupSubscriptionsAsync(DeviceContext context, CancellationToken cancellationToken = default) { - if (!context.IsConnected || !context.Variables.Any()) + if (!context.IsConnected) return; try { - _logger.LogInformation("正在为设备 {DeviceName} 设置订阅,变量数: {VariableCount}", - context.Device.Name, context.Variables.Count); + // 获取需要订阅的变量 + var subscribableVariables = GetSubscribableVariables(context); + + if (!subscribableVariables.Any()) + { + _logger.LogInformation("设备 {DeviceName} 没有需要订阅的变量", context.Device.Name); + return; + } + + _logger.LogInformation("正在为设备 {DeviceName} 设置订阅,需要订阅的变量数: {VariableCount}", + context.Device.Name, subscribableVariables.Count); // 按PollingInterval对变量进行分组 - var variablesByPollingInterval = context.Variables.Values + var variablesByPollingInterval = subscribableVariables .GroupBy(v => v.PollingInterval) .ToDictionary(g => g.Key, g => g.ToList()); @@ -494,7 +520,6 @@ namespace DMS.Infrastructure.Services.OpcUa "为设备 {DeviceName} 设置PollingInterval {PollingInterval} 的订阅,变量数: {VariableCount}", context.Device.Name, pollingInterval, variables.Count); - var opcUaNodes = variables .Select(v => new OpcUaNode { NodeId = v.OpcUaNodeId }) .ToList(); @@ -512,29 +537,6 @@ namespace DMS.Infrastructure.Services.OpcUa } } - /// - /// 根据PollingInterval获取发布间隔(毫秒) - /// - private int GetPublishingIntervalFromPollLevel(int pollingInterval) - { - // 根据轮询间隔值映射到发布间隔 - return pollingInterval switch - { - 100 => 100, // HundredMilliseconds -> 100ms发布间隔 - 500 => 500, // FiveHundredMilliseconds -> 500ms发布间隔 - 1000 => 1000, // OneSecond -> 1000ms发布间隔 - 5000 => 5000, // FiveSeconds -> 5000ms发布间隔 - 10000 => 10000, // TenSeconds -> 10000ms发布间隔 - 20000 => 20000, // TwentySeconds -> 20000ms发布间隔 - 30000 => 30000, // ThirtySeconds -> 30000ms发布间隔 - 60000 => 60000, // OneMinute -> 60000ms发布间隔 - 300000 => 300000, // FiveMinutes -> 300000ms发布间隔 - 600000 => 600000, // TenMinutes -> 600000ms发布间隔 - 1800000 => 1800000, // ThirtyMinutes -> 1800000ms发布间隔 - 3600000 => 3600000, // OneHour -> 3600000ms发布间隔 - _ => _options.SubscriptionPublishingIntervalMs // 默认值 - }; - } /// @@ -661,6 +663,80 @@ namespace DMS.Infrastructure.Services.OpcUa _logger.LogInformation("OPC UA服务管理器资源已释放"); } } + + /// + /// 处理变量变更事件 + /// + private void OnVariableChanged(object? sender, VariableChangedEventArgs e) + { + try + { + _logger.LogDebug("处理变量变更事件: 变量ID={VariableId}, 变更类型={ChangeType}, 变更属性={PropertyType}", + e.Variable.Id, e.ChangeType, e.PropertyType); + + // 根据变更类型和属性类型进行相应处理 + switch (e.ChangeType) + { + case ActionChangeType.Updated: + // 如果变量的OPC UA相关属性发生变化,需要重新设置订阅 + switch (e.PropertyType) + { + case VariablePropertyType.OpcUaNodeId: + case VariablePropertyType.OpcUaUpdateType: + case VariablePropertyType.PollingInterval: + // 重新设置设备的订阅 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context)) + { + _ = Task.Run(async () => + { + try + { + await SetupSubscriptionsAsync(context, CancellationToken.None); + _logger.LogInformation("已更新设备 {DeviceId} 的订阅,因为变量 {VariableId} 的OPC UA属性发生了变化", + e.Variable.VariableTable.DeviceId, e.Variable.Id); + } + catch (Exception ex) + { + _logger.LogError(ex, "更新设备 {DeviceId} 订阅时发生错误", e.Variable.VariableTable.DeviceId); + } + }); + } + break; + + case VariablePropertyType.IsActive: + // 变量激活状态变化,更新变量列表 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context2)) + { + if (e.Variable.IsActive) + { + // 添加变量到监控列表 + context2.Variables.AddOrUpdate(e.Variable.OpcUaNodeId, e.Variable, (key, oldValue) => e.Variable); + } + else + { + // 从监控列表中移除变量 + context2.Variables.Remove(e.Variable.OpcUaNodeId, out _); + } + } + break; + } + break; + + case ActionChangeType.Deleted: + // 变量被删除时,从设备上下文的变量列表中移除 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context3)) + { + context3.Variables.Remove(e.Variable.OpcUaNodeId, out _); + } + break; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "处理变量变更事件时发生错误: 变量ID={VariableId}, 变更类型={ChangeType}", + e.Variable.Id, e.ChangeType); + } + } } /// diff --git a/DMS.Infrastructure/Services/S7/S7ServiceManager.cs b/DMS.Infrastructure/Services/S7/S7ServiceManager.cs index 98fb9e5..086d501 100644 --- a/DMS.Infrastructure/Services/S7/S7ServiceManager.cs +++ b/DMS.Infrastructure/Services/S7/S7ServiceManager.cs @@ -47,6 +47,7 @@ namespace DMS.Infrastructure.Services.S7 _eventService.OnVariableActiveChanged += OnVariableActiveChanged; _eventService.OnBatchImportVariables += OnBatchImportVariables; + _eventService.OnVariableChanged += OnVariableChanged; } private void OnVariableActiveChanged(object? sender, VariablesActiveChangedEventArgs e) @@ -407,6 +408,71 @@ namespace DMS.Infrastructure.Services.S7 _logger.LogError(ex, "处理批量导入变量事件时发生错误"); } } + + /// + /// 处理变量变更事件 + /// + private void OnVariableChanged(object? sender, VariableChangedEventArgs e) + { + try + { + _logger.LogDebug("处理变量变更事件: 变量ID={VariableId}, 变更类型={ChangeType}, 变更属性={PropertyType}", + e.Variable.Id, e.ChangeType, e.PropertyType); + + // 根据变更类型和属性类型进行相应处理 + switch (e.ChangeType) + { + case ActionChangeType.Updated: + // 如果变量的S7相关属性发生变化 + switch (e.PropertyType) + { + case VariablePropertyType.S7Address: + // S7地址变化,需要更新设备上下文中的变量映射 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context)) + { + // 先移除旧地址的变量 + context.Variables.Remove(e.Variable.S7Address, out _); + // 添加新地址的变量 + context.Variables.AddOrUpdate(e.Variable.S7Address, e.Variable, (key, oldValue) => e.Variable); + _logger.LogInformation("已更新设备 {DeviceId} 中变量 {VariableId} 的S7地址映射", + e.Variable.VariableTable.DeviceId, e.Variable.Id); + } + break; + + case VariablePropertyType.IsActive: + // 变量激活状态变化,更新变量列表 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context2)) + { + if (e.Variable.IsActive) + { + // 添加变量到监控列表 + context2.Variables.AddOrUpdate(e.Variable.S7Address, e.Variable, (key, oldValue) => e.Variable); + } + else + { + // 从监控列表中移除变量 + context2.Variables.Remove(e.Variable.S7Address, out _); + } + } + break; + } + break; + + case ActionChangeType.Deleted: + // 变量被删除时,从设备上下文的变量列表中移除 + if (_deviceContexts.TryGetValue(e.Variable.VariableTable.DeviceId, out var context3)) + { + context3.Variables.Remove(e.Variable.S7Address, out _); + } + break; + } + } + catch (Exception ex) + { + _logger.LogError(ex, "处理变量变更事件时发生错误: 变量ID={VariableId}, 变更类型={ChangeType}", + e.Variable.Id, e.ChangeType); + } + } } /// diff --git a/DMS.WPF/ViewModels/VariableTableViewModel.cs b/DMS.WPF/ViewModels/VariableTableViewModel.cs index f9c7d1d..cca154d 100644 --- a/DMS.WPF/ViewModels/VariableTableViewModel.cs +++ b/DMS.WPF/ViewModels/VariableTableViewModel.cs @@ -723,7 +723,7 @@ partial class VariableTableViewModel : ViewModelBase, INavigatable if (result > 0) { - _eventService.RaiseVariableActiveChanged(this,new VariablesActiveChangedEventArgs(validVariables.Select(v=>v.Id).ToList(),CurrentVariableTable.DeviceId,newIsActive.Value)); + // _eventService.RaiseVariableActiveChanged(this,new VariablesActiveChangedEventArgs(validVariables.Select(v=>v.Id).ToList(),CurrentVariableTable.DeviceId,newIsActive.Value)); // 显示成功通知 _notificationService.ShowSuccess($"已成功更新 {validVariables.Count} 个变量的启用状态"); }