Propagate alarm events up the full notifier chain so subscribers at any ancestor see them
Previously alarms were only reported to the immediate parent node and the Server node. Now ReportEventUpNotifierChain walks the full parent chain so clients subscribed at TestArea see alarms from TestMachine_001, and EventNotifier is set on all ancestors of alarm-containing nodes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -423,14 +423,9 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
hasAlarms = true;
|
||||
}
|
||||
|
||||
// Enable EventNotifier on object nodes that contain alarms
|
||||
// Enable EventNotifier on this node and all ancestors so alarm events propagate
|
||||
if (hasAlarms && _nodeMap.TryGetValue(obj.GobjectId, out var objNode))
|
||||
{
|
||||
if (objNode is BaseObjectState objState)
|
||||
objState.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
else if (objNode is FolderState folderState)
|
||||
folderState.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
}
|
||||
EnableEventNotifierUpChain(objNode);
|
||||
}
|
||||
|
||||
// Auto-subscribe to InAlarm tags so we detect alarm transitions
|
||||
@@ -519,14 +514,9 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
if (active)
|
||||
condition.SetAcknowledgedState(SystemContext, false);
|
||||
|
||||
// Report through the source node hierarchy so events reach subscribers on parent objects
|
||||
if (_tagToVariableNode.TryGetValue(info.SourceTagReference, out var sourceVar) && sourceVar.Parent != null)
|
||||
{
|
||||
sourceVar.Parent.ReportEvent(SystemContext, condition);
|
||||
}
|
||||
|
||||
// Also report to Server node for clients subscribed at server level
|
||||
Server.ReportEvent(SystemContext, condition);
|
||||
// Walk up the notifier chain so events reach subscribers at any ancestor level
|
||||
if (_tagToVariableNode.TryGetValue(info.SourceTagReference, out var sourceVar))
|
||||
ReportEventUpNotifierChain(sourceVar, condition);
|
||||
|
||||
Log.Information("Alarm {State}: {Source} (Severity={Severity}, Message={Message})",
|
||||
active ? "ACTIVE" : "CLEARED", info.SourceName, severity, message);
|
||||
@@ -879,12 +869,7 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
}
|
||||
|
||||
if (hasAlarms && _nodeMap.TryGetValue(obj.GobjectId, out var objNode))
|
||||
{
|
||||
if (objNode is BaseObjectState objState)
|
||||
objState.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
else if (objNode is FolderState folderState)
|
||||
folderState.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
}
|
||||
EnableEventNotifierUpChain(objNode);
|
||||
}
|
||||
|
||||
// Subscribe alarm tags for new subtree
|
||||
@@ -1192,6 +1177,23 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
return roles != null && roles.Contains(requiredRole);
|
||||
}
|
||||
|
||||
private static void EnableEventNotifierUpChain(NodeState node)
|
||||
{
|
||||
for (var current = node as BaseInstanceState; current != null; current = current.Parent as BaseInstanceState)
|
||||
{
|
||||
if (current is BaseObjectState obj)
|
||||
obj.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
else if (current is FolderState folder)
|
||||
folder.EventNotifier = EventNotifiers.SubscribeToEvents;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReportEventUpNotifierChain(BaseInstanceState sourceNode, IFilterTarget eventInstance)
|
||||
{
|
||||
for (var current = sourceNode.Parent; current != null; current = (current as BaseInstanceState)?.Parent)
|
||||
current.ReportEvent(SystemContext, eventInstance);
|
||||
}
|
||||
|
||||
private bool TryApplyArrayElementWrite(string tagRef, object? writeValue, string indexRange, out object updatedArray)
|
||||
{
|
||||
updatedArray = null!;
|
||||
@@ -1761,9 +1763,8 @@ namespace ZB.MOM.WW.LmxOpcUa.Host.OpcUa
|
||||
condition.SetAcknowledgedState(SystemContext, acked);
|
||||
condition.Retain.Value = (condition.ActiveState?.Id?.Value == true) || !acked;
|
||||
|
||||
if (_tagToVariableNode.TryGetValue(info.SourceTagReference, out var src) && src.Parent != null)
|
||||
src.Parent.ReportEvent(SystemContext, condition);
|
||||
Server.ReportEvent(SystemContext, condition);
|
||||
if (_tagToVariableNode.TryGetValue(info.SourceTagReference, out var src))
|
||||
ReportEventUpNotifierChain(src, condition);
|
||||
|
||||
Log.Information("Alarm {AckState}: {Source}",
|
||||
acked ? "ACKNOWLEDGED" : "UNACKNOWLEDGED", info.SourceName);
|
||||
|
||||
Reference in New Issue
Block a user