feat(scripted-alarms): richer AlarmConditionState bridge to the OPC UA node (T15)

This commit is contained in:
Joseph Doherty
2026-06-10 19:41:16 -04:00
parent b31d7cb03f
commit 4eb1d65e2b
16 changed files with 349 additions and 108 deletions
@@ -30,7 +30,15 @@ public sealed class OpcUaPublishActor : ReceiveActor
public const string RedundancyStateTopic = "redundancy-state";
public sealed record AttributeValueUpdate(string NodeId, object? Value, OpcUaQuality Quality, DateTime TimestampUtc);
public sealed record AlarmStateUpdate(string AlarmNodeId, bool Active, bool Acknowledged, DateTime TimestampUtc);
/// <summary>Carries the full Part 9 condition state for a scripted alarm to the sink. The
/// <paramref name="State"/> snapshot is the Commons projection the Runtime host maps from the engine's
/// Core <c>AlarmConditionState</c> + severity/message — the actor stays decoupled from
/// <c>Core.ScriptedAlarms</c>.</summary>
/// <param name="AlarmNodeId">The alarm node id (== ScriptedAlarmId for materialised conditions).</param>
/// <param name="State">The full condition state to project onto the node.</param>
/// <param name="TimestampUtc">The source timestamp of the transition in UTC.</param>
public sealed record AlarmStateUpdate(string AlarmNodeId, AlarmConditionSnapshot State, DateTime TimestampUtc);
/// <summary>
/// Triggers an address-space rebuild. <paramref name="DeploymentId"/> is the deployment
/// just applied by the host; the rebuild loads THAT artifact so materialisation matches the
@@ -167,13 +175,13 @@ public sealed class OpcUaPublishActor : ReceiveActor
{
try
{
_sink.WriteAlarmState(msg.AlarmNodeId, msg.Active, msg.Acknowledged, msg.TimestampUtc);
_sink.WriteAlarmCondition(msg.AlarmNodeId, msg.State, msg.TimestampUtc);
Interlocked.Increment(ref _writes);
OtOpcUaTelemetry.OpcUaSinkWrite.Add(1, new KeyValuePair<string, object?>("kind", "alarm"));
}
catch (Exception ex)
{
_log.Warning(ex, "OpcUaPublish: sink.WriteAlarmState threw for {Node}", msg.AlarmNodeId);
_log.Warning(ex, "OpcUaPublish: sink.WriteAlarmCondition threw for {Node}", msg.AlarmNodeId);
}
}