Add enable/disable configuration for alarm tracking and historian integration
Both features now default to disabled and require explicit opt-in via OpcUa.AlarmTrackingEnabled and Historian.Enabled in appsettings.json, preventing errors in environments without a Historian database or alarm setup. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,11 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.Configuration
|
||||
/// </summary>
|
||||
public class HistorianConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether OPC UA historical data access is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the connection string for the Wonderware Historian Runtime database.
|
||||
/// </summary>
|
||||
|
||||
@@ -34,5 +34,11 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.Configuration
|
||||
/// Gets or sets the session timeout, in minutes, before idle client sessions are closed.
|
||||
/// </summary>
|
||||
public int SessionTimeoutMinutes { get; set; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether alarm tracking is enabled.
|
||||
/// When enabled, AlarmConditionState nodes are created for alarm attributes and InAlarm transitions are monitored.
|
||||
/// </summary>
|
||||
public bool AlarmTrackingEnabled { get; set; } = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
private readonly IMxAccessClient _mxAccessClient;
|
||||
private readonly PerformanceMetrics _metrics;
|
||||
private readonly HistorianDataSource? _historianDataSource;
|
||||
private readonly bool _alarmTrackingEnabled;
|
||||
private readonly string _namespaceUri;
|
||||
|
||||
// NodeId → full_tag_reference for read/write resolution
|
||||
@@ -123,13 +124,15 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
string namespaceUri,
|
||||
IMxAccessClient mxAccessClient,
|
||||
PerformanceMetrics metrics,
|
||||
HistorianDataSource? historianDataSource = null)
|
||||
HistorianDataSource? historianDataSource = null,
|
||||
bool alarmTrackingEnabled = false)
|
||||
: base(server, configuration, namespaceUri)
|
||||
{
|
||||
_namespaceUri = namespaceUri;
|
||||
_mxAccessClient = mxAccessClient;
|
||||
_metrics = metrics;
|
||||
_historianDataSource = historianDataSource;
|
||||
_alarmTrackingEnabled = alarmTrackingEnabled;
|
||||
|
||||
// Wire up data change delivery
|
||||
_mxAccessClient.OnTagValueChanged += OnMxAccessDataChange;
|
||||
@@ -280,7 +283,7 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
}
|
||||
|
||||
// Build alarm tracking: create AlarmConditionState for each alarm attribute
|
||||
foreach (var obj in sorted)
|
||||
if (_alarmTrackingEnabled) foreach (var obj in sorted)
|
||||
{
|
||||
if (obj.IsArea) continue;
|
||||
if (!attrsByObject.TryGetValue(obj.GobjectId, out var objAttrs)) continue;
|
||||
@@ -354,7 +357,8 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
}
|
||||
|
||||
// Auto-subscribe to InAlarm tags so we detect alarm transitions
|
||||
SubscribeAlarmTags();
|
||||
if (_alarmTrackingEnabled)
|
||||
SubscribeAlarmTags();
|
||||
|
||||
Log.Information("Address space built: {Objects} objects, {Variables} variables, {Mappings} tag references, {Alarms} alarm tags",
|
||||
ObjectNodeCount, VariableNodeCount, _nodeIdToTagReference.Count, _alarmInAlarmTags.Count);
|
||||
|
||||
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
private readonly IMxAccessClient _mxAccessClient;
|
||||
private readonly PerformanceMetrics _metrics;
|
||||
private readonly HistorianDataSource? _historianDataSource;
|
||||
private readonly bool _alarmTrackingEnabled;
|
||||
private LmxNodeManager? _nodeManager;
|
||||
|
||||
/// <summary>
|
||||
@@ -42,19 +43,20 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
/// <param name="mxAccessClient">The runtime client used by the node manager for live data access.</param>
|
||||
/// <param name="metrics">The metrics collector shared with the node manager.</param>
|
||||
public LmxOpcUaServer(string galaxyName, IMxAccessClient mxAccessClient, PerformanceMetrics metrics,
|
||||
HistorianDataSource? historianDataSource = null)
|
||||
HistorianDataSource? historianDataSource = null, bool alarmTrackingEnabled = false)
|
||||
{
|
||||
_galaxyName = galaxyName;
|
||||
_mxAccessClient = mxAccessClient;
|
||||
_metrics = metrics;
|
||||
_historianDataSource = historianDataSource;
|
||||
_alarmTrackingEnabled = alarmTrackingEnabled;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override MasterNodeManager CreateMasterNodeManager(IServerInternal server, ApplicationConfiguration configuration)
|
||||
{
|
||||
var namespaceUri = $"urn:{_galaxyName}:LmxOpcUa";
|
||||
_nodeManager = new LmxNodeManager(server, configuration, namespaceUri, _mxAccessClient, _metrics, _historianDataSource);
|
||||
_nodeManager = new LmxNodeManager(server, configuration, namespaceUri, _mxAccessClient, _metrics, _historianDataSource, _alarmTrackingEnabled);
|
||||
|
||||
var nodeManagers = new List<INodeManager> { _nodeManager };
|
||||
return new MasterNodeManager(server, configuration, null, nodeManagers.ToArray());
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
certOk = await _application.CheckApplicationInstanceCertificate(false, 2048);
|
||||
}
|
||||
|
||||
_server = new LmxOpcUaServer(_config.GalaxyName, _mxAccessClient, _metrics, _historianDataSource);
|
||||
_server = new LmxOpcUaServer(_config.GalaxyName, _mxAccessClient, _metrics, _historianDataSource, _config.AlarmTrackingEnabled);
|
||||
await _application.Start(_server);
|
||||
|
||||
Log.Information("OPC UA server started on opc.tcp://localhost:{Port}{EndpointPath} (namespace={Namespace})",
|
||||
|
||||
@@ -153,7 +153,9 @@ namespace ZB.MOM.WW.LmxOpcUa.Host
|
||||
|
||||
// Step 8: Create OPC UA server host + node manager
|
||||
var effectiveMxClient = (IMxAccessClient?)_mxAccessClient ?? _mxAccessClientForWiring ?? new NullMxAccessClient();
|
||||
var historianDataSource = new Historian.HistorianDataSource(_config.Historian);
|
||||
var historianDataSource = _config.Historian.Enabled
|
||||
? new Historian.HistorianDataSource(_config.Historian)
|
||||
: null;
|
||||
_serverHost = new OpcUaServerHost(_config.OpcUa, effectiveMxClient, _metrics, historianDataSource);
|
||||
|
||||
// Step 9-10: Query hierarchy, start server, build address space
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
"ServerName": "LmxOpcUa",
|
||||
"GalaxyName": "ZB",
|
||||
"MaxSessions": 100,
|
||||
"SessionTimeoutMinutes": 30
|
||||
"SessionTimeoutMinutes": 30,
|
||||
"AlarmTrackingEnabled": false
|
||||
},
|
||||
"MxAccess": {
|
||||
"ClientName": "LmxOpcUa",
|
||||
@@ -31,6 +32,7 @@
|
||||
"RefreshIntervalSeconds": 10
|
||||
},
|
||||
"Historian": {
|
||||
"Enabled": false,
|
||||
"ConnectionString": "Server=localhost;Database=Runtime;Integrated Security=true;",
|
||||
"CommandTimeoutSeconds": 30,
|
||||
"MaxValuesPerRead": 10000
|
||||
|
||||
Reference in New Issue
Block a user