特性:为 OpcUaServiceManager 和 S7ServiceManager 添加 VariableChanged 事件订阅
- OpcUaServiceManager 更新:
- 添加了 OnVariableChanged 事件订阅
- 实现了 OnVariableChanged 事件处理方法,根据变量属性变化类型进行相应处理
- 对于 OPC UA Node ID、更新类型或轮询间隔变化,重新设置设备订阅
- 对于激活状态变化,更新设备上下文中的变量列表
- 对于变量删除,从设备上下文中移除对应变量
- S7ServiceManager 更新:
- 添加了 OnVariableChanged 事件订阅
- 实现了 OnVariableChanged 事件处理方法,根据变量属性变化类型进行相应处理
- 对于 S7 地址变化,更新设备上下文中的变量映射
- 对于激活状态变化,更新设备上下文中的变量列表
- 对于变量删除,从设备上下文中移除对应变量
- 改进系统响应性:
- 使 OPC UA 和 S7 服务能够实时响应变量属性变更
- 提高了系统在变量配置更改时的动态适应能力
- 确保服务能够根据变量状态变化及时更新其内部数据结构
This commit is contained in:
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取需要订阅的变量列表
|
||||
/// </summary>
|
||||
/// <param name="context">设备上下文</param>
|
||||
/// <returns>需要订阅的变量列表</returns>
|
||||
private List<VariableDto> GetSubscribableVariables(DeviceContext context)
|
||||
{
|
||||
if (context?.Variables == null)
|
||||
return new List<VariableDto>();
|
||||
|
||||
// 返回所有激活且OPC UA更新类型不是None的变量
|
||||
return context.Variables.Values
|
||||
.Where(v => v.IsActive )
|
||||
.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理批量导入变量事件
|
||||
/// </summary>
|
||||
@@ -471,16 +488,25 @@ namespace DMS.Infrastructure.Services.OpcUa
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据PollingInterval获取发布间隔(毫秒)
|
||||
/// </summary>
|
||||
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 // 默认值
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -661,6 +663,80 @@ namespace DMS.Infrastructure.Services.OpcUa
|
||||
_logger.LogInformation("OPC UA服务管理器资源已释放");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理变量变更事件
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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, "处理批量导入变量事件时发生错误");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理变量变更事件
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -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} 个变量的启用状态");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user