fix(alarms): route native alarms by ConditionId (dotted FullName), not bare SourceNodeId (integration review)
v2-ci / build (push) Failing after 46s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 46s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
This commit is contained in:
@@ -111,7 +111,7 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers
|
||||
private readonly Dictionary<string, (string DriverInstanceId, string FullName)> _driverRefByNodeId =
|
||||
new(StringComparer.Ordinal);
|
||||
|
||||
/// <summary>(DriverInstanceId, FullName = alarm SourceNodeId) → folder-scoped condition NodeId(s).
|
||||
/// <summary>(DriverInstanceId, FullName = alarm ConditionId / AlarmFullReference) → folder-scoped condition NodeId(s).
|
||||
/// Built from EquipmentTags whose plan carries Alarm, alongside the value maps; resolves a native
|
||||
/// alarm transition to the materialised Part 9 condition node(s). Alarm tags are conditions, not
|
||||
/// value variables, so they are kept OUT of the value maps + value-subscription set.</summary>
|
||||
@@ -497,10 +497,11 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers
|
||||
/// <summary>
|
||||
/// Routes a native alarm transition (published by a driver child as
|
||||
/// <see cref="DriverInstanceActor.AttributeAlarmPublished"/>) to its materialised Part 9 condition
|
||||
/// node(s). The alarm path analogue of <see cref="ForwardToMux"/>: the driver fires keyed by the
|
||||
/// alarm source's <c>SourceNodeId</c> (the equipment tag's wire-ref FullName), which the
|
||||
/// <see cref="_alarmNodeIdByDriverRef"/> map — built each apply from the alarm-bearing EquipmentTags —
|
||||
/// resolves to the folder-scoped condition NodeId(s) the materialiser placed the condition(s) at.
|
||||
/// node(s). The alarm path analogue of <see cref="ForwardToMux"/>: the transition's <c>ConditionId</c>
|
||||
/// (the dotted alarm full-reference, which equals the authored equipment-tag FullName — NOT the bare
|
||||
/// <c>SourceNodeId</c> owning object) is resolved by the <see cref="_alarmNodeIdByDriverRef"/> map —
|
||||
/// built each apply from the alarm-bearing EquipmentTags — to the folder-scoped condition NodeId(s)
|
||||
/// the materialiser placed the condition(s) at.
|
||||
/// For each node the <see cref="_nativeAlarmProjector"/> projects the transition delta into a full
|
||||
/// <c>AlarmConditionSnapshot</c>, then this Tells <see cref="ZB.MOM.WW.OtOpcUa.Runtime.OpcUa.OpcUaPublishActor.AlarmStateUpdate"/>
|
||||
/// — the SAME message scripted alarms use, so it routes through <c>WriteAlarmCondition</c>. An
|
||||
@@ -518,10 +519,13 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers
|
||||
private void ForwardNativeAlarm(DriverInstanceActor.AttributeAlarmPublished msg)
|
||||
{
|
||||
if (_opcUaPublishActor is null) return;
|
||||
if (!_alarmNodeIdByDriverRef.TryGetValue((msg.DriverInstanceId, msg.Args.SourceNodeId), out var nodeIds))
|
||||
// Resolve on ConditionId, NOT SourceNodeId: for Galaxy the dotted alarm full-reference — which
|
||||
// equals the authored equipment-tag FullName the map is keyed by — is carried in ConditionId
|
||||
// (AlarmFullReference), while SourceNodeId is the bare owning object (SourceObjectReference).
|
||||
if (!_alarmNodeIdByDriverRef.TryGetValue((msg.DriverInstanceId, msg.Args.ConditionId), out var nodeIds))
|
||||
{
|
||||
_log.Debug("DriverHost {Node}: no alarm condition for ({Driver},{Ref}) — transition dropped",
|
||||
_localNode, msg.DriverInstanceId, msg.Args.SourceNodeId);
|
||||
_localNode, msg.DriverInstanceId, msg.Args.ConditionId);
|
||||
return;
|
||||
}
|
||||
foreach (var nodeId in nodeIds)
|
||||
@@ -862,7 +866,7 @@ public sealed class DriverHostActor : ReceiveActor, IWithTimers
|
||||
// reflected. Each NodeId maps to exactly one driver ref (a variable is backed by a single driver
|
||||
// attribute), so last-writer-wins on the rare duplicate is harmless.
|
||||
_driverRefByNodeId.Clear();
|
||||
// Alarm condition routing map: (DriverInstanceId, FullName = alarm SourceNodeId) → folder-scoped
|
||||
// Alarm condition routing map: (DriverInstanceId, FullName = alarm ConditionId/AlarmFullReference) → folder-scoped
|
||||
// condition NodeId(s). Built from the SAME EquipmentTags pass (alarm-bearing tags only) so
|
||||
// ForwardNativeAlarm can land a native transition on the right condition node. Clear-and-rebuild
|
||||
// every apply; the projector is Clear()'d too so stale per-condition state never leaks across
|
||||
|
||||
Reference in New Issue
Block a user