测试完成OpcUa后台服务功能
This commit is contained in:
@@ -15,18 +15,7 @@ namespace DMS.Infrastructure.Extensions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static IServiceCollection AddOpcUaServices(this IServiceCollection services)
|
public static IServiceCollection AddOpcUaServices(this IServiceCollection services)
|
||||||
{
|
{
|
||||||
// 注册配置选项
|
|
||||||
services.Configure<OpcUaServiceOptions>(
|
|
||||||
options => {
|
|
||||||
// 可以从配置文件或其他来源加载配置
|
|
||||||
});
|
|
||||||
|
|
||||||
// 注册服务
|
|
||||||
services.AddSingleton<IOpcUaServiceManager, OpcUaServiceManager>();
|
|
||||||
|
|
||||||
// 注册后台服务
|
|
||||||
services.AddHostedService<OptimizedOpcUaBackgroundService>();
|
|
||||||
|
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -211,12 +211,31 @@ namespace DMS.Infrastructure.Services
|
|||||||
_logger.LogInformation("正在为设备 {DeviceName} 设置订阅,变量数: {VariableCount}",
|
_logger.LogInformation("正在为设备 {DeviceName} 设置订阅,变量数: {VariableCount}",
|
||||||
context.Device.Name, context.Variables.Count);
|
context.Device.Name, context.Variables.Count);
|
||||||
|
|
||||||
var opcUaNodes = context.Variables.Values
|
// 按PollLevel对变量进行分组
|
||||||
.Select(v => new OpcUaNode { NodeId = v.OpcUaNodeId })
|
var variablesByPollLevel = context.Variables.Values
|
||||||
.ToList();
|
.GroupBy(v => v.PollLevel)
|
||||||
|
.ToDictionary(g => g.Key, g => g.ToList());
|
||||||
|
|
||||||
context.OpcUaService.SubscribeToNode(opcUaNodes, HandleDataChanged,
|
// 为每个PollLevel组设置单独的订阅
|
||||||
_options.SubscriptionPublishingIntervalMs, _options.SubscriptionSamplingIntervalMs);
|
foreach (var group in variablesByPollLevel)
|
||||||
|
{
|
||||||
|
PollLevelType pollLevel = group.Key;
|
||||||
|
var variables = group.Value;
|
||||||
|
|
||||||
|
_logger.LogInformation("为设备 {DeviceName} 设置PollLevel {PollLevel} 的订阅,变量数: {VariableCount}",
|
||||||
|
context.Device.Name, pollLevel, variables.Count);
|
||||||
|
|
||||||
|
// 根据PollLevel计算发布间隔和采样间隔(毫秒)
|
||||||
|
var publishingInterval = GetPublishingIntervalFromPollLevel(pollLevel);
|
||||||
|
// var samplingInterval = GetSamplingIntervalFromPollLevel(pollLevel);
|
||||||
|
|
||||||
|
var opcUaNodes = variables
|
||||||
|
.Select(v => new OpcUaNode { NodeId = v.OpcUaNodeId })
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
context.OpcUaService.SubscribeToNode(opcUaNodes, HandleDataChanged,
|
||||||
|
publishingInterval, publishingInterval);
|
||||||
|
}
|
||||||
|
|
||||||
_logger.LogInformation("设备 {DeviceName} 订阅设置完成", context.Device.Name);
|
_logger.LogInformation("设备 {DeviceName} 订阅设置完成", context.Device.Name);
|
||||||
}
|
}
|
||||||
@@ -227,6 +246,32 @@ namespace DMS.Infrastructure.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 根据PollLevel获取发布间隔(毫秒)
|
||||||
|
/// </summary>
|
||||||
|
private int GetPublishingIntervalFromPollLevel(PollLevelType pollLevel)
|
||||||
|
{
|
||||||
|
// 根据PollLevelType枚举值映射到发布间隔
|
||||||
|
return pollLevel switch
|
||||||
|
{
|
||||||
|
PollLevelType.HundredMilliseconds => 100, // TenMilliseconds -> 100ms发布间隔
|
||||||
|
PollLevelType.FiveHundredMilliseconds => 500, // HundredMilliseconds -> 500ms发布间隔
|
||||||
|
PollLevelType.OneSecond => 1000, // FiveHundredMilliseconds -> 1000ms发布间隔
|
||||||
|
PollLevelType.FiveSeconds => 5000, // OneSecond -> 2000ms发布间隔
|
||||||
|
PollLevelType.TenSeconds => 10000, // TenSeconds -> 10000ms发布间隔
|
||||||
|
PollLevelType.TwentySeconds => 20000, // TwentySeconds -> 20000ms发布间隔
|
||||||
|
PollLevelType.ThirtySeconds => 30000, // ThirtySeconds -> 30000ms发布间隔
|
||||||
|
PollLevelType.OneMinute => 60000, // OneMinute -> 60000ms发布间隔
|
||||||
|
PollLevelType.FiveMinutes => 300000, // ThreeMinutes -> 120000ms发布间隔
|
||||||
|
PollLevelType.TenMinutes => 600000, // FiveMinutes -> 180000ms发布间隔
|
||||||
|
PollLevelType.ThirtyMinutes => 1800000, // TenMinutes -> 300000ms发布间隔
|
||||||
|
PollLevelType.OneHour => 3600000, // ThirtyMinutes -> 600000ms发布间隔
|
||||||
|
_ => _options.SubscriptionPublishingIntervalMs // 默认值
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理数据变化
|
/// 处理数据变化
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -279,7 +324,10 @@ namespace DMS.Infrastructure.Services
|
|||||||
|
|
||||||
foreach (var deviceId in deviceIds)
|
foreach (var deviceId in deviceIds)
|
||||||
{
|
{
|
||||||
connectTasks.Add(ConnectDeviceAsync(deviceId, cancellationToken));
|
if (_deviceContexts.TryGetValue(deviceId, out var context))
|
||||||
|
{
|
||||||
|
connectTasks.Add(ConnectDeviceAsync(context, cancellationToken));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(connectTasks);
|
await Task.WhenAll(connectTasks);
|
||||||
@@ -305,10 +353,7 @@ namespace DMS.Infrastructure.Services
|
|||||||
|
|
||||||
foreach (var deviceId in deviceIds)
|
foreach (var deviceId in deviceIds)
|
||||||
{
|
{
|
||||||
if (_deviceContexts.TryGetValue(deviceId, out var context))
|
disconnectTasks.Add(DisconnectDeviceAsync(deviceId, cancellationToken));
|
||||||
{
|
|
||||||
disconnectTasks.Add(DisconnectDeviceAsync(deviceId, cancellationToken));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
await Task.WhenAll(disconnectTasks);
|
await Task.WhenAll(disconnectTasks);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ using DMS.Application.Services.Processors;
|
|||||||
using DMS.Core.Interfaces;
|
using DMS.Core.Interfaces;
|
||||||
using DMS.Core.Interfaces.Repositories;
|
using DMS.Core.Interfaces.Repositories;
|
||||||
using DMS.Core.Interfaces.Services;
|
using DMS.Core.Interfaces.Services;
|
||||||
|
using DMS.Infrastructure.Configuration;
|
||||||
using DMS.Infrastructure.Configurations;
|
using DMS.Infrastructure.Configurations;
|
||||||
using DMS.Infrastructure.Data;
|
using DMS.Infrastructure.Data;
|
||||||
using DMS.Infrastructure.Interfaces.Services;
|
using DMS.Infrastructure.Interfaces.Services;
|
||||||
@@ -109,9 +110,13 @@ public partial class App : System.Windows.Application
|
|||||||
});
|
});
|
||||||
|
|
||||||
// 注册数据处理服务和处理器
|
// 注册数据处理服务和处理器
|
||||||
services.AddHostedService<OpcUaBackgroundService>();
|
// services.AddHostedService<OpcUaBackgroundService>();
|
||||||
services.Configure<DMS.Infrastructure.Configuration.OpcUaServiceOptions>(options => { });
|
services.Configure<OpcUaServiceOptions>(options => { });
|
||||||
|
// 注册服务
|
||||||
services.AddSingleton<IOpcUaServiceManager, OpcUaServiceManager>();
|
services.AddSingleton<IOpcUaServiceManager, OpcUaServiceManager>();
|
||||||
|
// 注册后台服务
|
||||||
|
services.AddHostedService<OptimizedOpcUaBackgroundService>();
|
||||||
|
|
||||||
services.AddSingleton<IDataProcessingService, DataProcessingService>();
|
services.AddSingleton<IDataProcessingService, DataProcessingService>();
|
||||||
services.AddHostedService(provider => (DataProcessingService)provider.GetRequiredService<IDataProcessingService>());
|
services.AddHostedService(provider => (DataProcessingService)provider.GetRequiredService<IDataProcessingService>());
|
||||||
services.AddSingleton<CheckValueChangedProcessor>();
|
services.AddSingleton<CheckValueChangedProcessor>();
|
||||||
@@ -155,6 +160,10 @@ public partial class App : System.Windows.Application
|
|||||||
// 注册WPF中的服务
|
// 注册WPF中的服务
|
||||||
services.AddSingleton<DataServices>();
|
services.AddSingleton<DataServices>();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// 注册视图模型
|
// 注册视图模型
|
||||||
services.AddSingleton<SplashViewModel>();
|
services.AddSingleton<SplashViewModel>();
|
||||||
services.AddSingleton<MainViewModel>();
|
services.AddSingleton<MainViewModel>();
|
||||||
|
|||||||
Reference in New Issue
Block a user