diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/AlarmConditionState.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/AlarmConditionState.cs new file mode 100644 index 00000000..b8b57a63 --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/AlarmConditionState.cs @@ -0,0 +1,24 @@ +using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms; + +/// +/// Unified, read-only alarm condition state. The OPC UA Part 9 sub-conditions +/// are orthogonal, and MxAccess's ACTIVE / ACTIVE_ACKED / INACTIVE map cleanly +/// onto them, so they are modeled as independent flags plus a 0–1000 severity. +/// Computed alarms populate this from State + Priority; native alarms mirror it +/// from the source. +/// +/// Active vs Inactive. +/// Acked vs Unacked. +/// Confirmed vs Unconfirmed; null when the condition is not confirmable. +/// Shelving sub-state. +/// Whether the source has suppressed the condition. +/// Severity on the unified 0–1000 scale. +public record AlarmConditionState( + bool Active, + bool Acknowledged, + bool? Confirmed, + AlarmShelveState Shelve, + bool Suppressed, + int Severity); diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/NativeAlarmTransition.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/NativeAlarmTransition.cs new file mode 100644 index 00000000..02cbeb6e --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Alarms/NativeAlarmTransition.cs @@ -0,0 +1,39 @@ +using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms; + +/// +/// Protocol-neutral alarm transition emitted by an +/// IAlarmSubscribableConnection adapter (OPC UA A&C or MxGateway). +/// Keyed by ; routed to instances by +/// . +/// +/// Stable per-condition key (e.g. "Tank01.Level.HiHi"). +/// Owning source object used for instance routing (e.g. "Tank01"). +/// Source alarm type (e.g. "AnalogLimitAlarm.HiHi"). +/// Transition classification, incl. snapshot replay sentinels. +/// Mirrored condition state. +/// Source taxonomy/category. +/// Human-readable description from the source template. +/// Event message text. +/// Operator principal on ack transitions (display-only). +/// Operator comment on ack transitions (display-only). +/// When the condition originally became active, if known. +/// When this transition occurred. +/// Current source value (display-only). +/// Limit/threshold value for limit alarms (display-only). +public record NativeAlarmTransition( + string SourceReference, + string SourceObjectReference, + string AlarmTypeName, + AlarmTransitionKind Kind, + AlarmConditionState Condition, + string Category, + string Description, + string Message, + string OperatorUser, + string OperatorComment, + DateTimeOffset? OriginalRaiseTime, + DateTimeOffset TransitionTime, + string CurrentValue, + string LimitValue); diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmKind.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmKind.cs new file mode 100644 index 00000000..cb99bbc7 --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmKind.cs @@ -0,0 +1,17 @@ +namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +/// +/// Distinguishes how an alarm's state is produced: computed at the site from +/// attribute triggers, or mirrored read-only from a native source. +/// +public enum AlarmKind +{ + /// Evaluated at the site by an AlarmActor from attribute triggers. + Computed, + + /// Mirrored from an OPC UA Alarms & Conditions server. + NativeOpcUa, + + /// Mirrored from the MxAccess Gateway alarm feed. + NativeMxAccess +} diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmShelveState.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmShelveState.cs new file mode 100644 index 00000000..d6f28274 --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmShelveState.cs @@ -0,0 +1,13 @@ +namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +/// +/// OPC UA Part 9 shelving sub-state of an alarm condition. Mirrored read-only +/// from the source; computed alarms are always . +/// +public enum AlarmShelveState +{ + Unshelved, + OneShotShelved, + TimedShelved, + PermanentShelved +} diff --git a/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmTransitionKind.cs b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmTransitionKind.cs new file mode 100644 index 00000000..96cb23e6 --- /dev/null +++ b/src/ZB.MOM.WW.ScadaBridge.Commons/Types/Enums/AlarmTransitionKind.cs @@ -0,0 +1,18 @@ +namespace ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +/// +/// Classifies a NativeAlarmTransition emitted by an +/// IAlarmSubscribableConnection adapter. and +/// carry the initial active-condition replay +/// produced on every (re)subscribe so consumers can re-seed state. +/// +public enum AlarmTransitionKind +{ + Snapshot, + SnapshotComplete, + Raise, + Acknowledge, + Clear, + Retrigger, + StateChange +} diff --git a/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Alarms/AlarmConditionStateTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Alarms/AlarmConditionStateTests.cs new file mode 100644 index 00000000..376a52e5 --- /dev/null +++ b/tests/ZB.MOM.WW.ScadaBridge.Commons.Tests/Types/Alarms/AlarmConditionStateTests.cs @@ -0,0 +1,36 @@ +using ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms; +using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; + +namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Types.Alarms; + +public class AlarmConditionStateTests +{ + [Fact] + public void AlarmConditionState_DefaultsAreNormalUnshelved() + { + var s = new AlarmConditionState( + Active: false, Acknowledged: true, Confirmed: null, + Shelve: AlarmShelveState.Unshelved, Suppressed: false, Severity: 0); + + Assert.False(s.Active); + Assert.Equal(AlarmShelveState.Unshelved, s.Shelve); + Assert.Equal(0, s.Severity); + } + + [Fact] + public void NativeAlarmTransition_CarriesSourceAndCondition() + { + var t = new NativeAlarmTransition( + SourceReference: "Tank01.Level.HiHi", SourceObjectReference: "Tank01", + AlarmTypeName: "AnalogLimitAlarm.HiHi", Kind: AlarmTransitionKind.Raise, + Condition: new AlarmConditionState(true, false, null, AlarmShelveState.Unshelved, false, 800), + Category: "Process", Description: "High level", Message: "level high", + OperatorUser: "", OperatorComment: "", + OriginalRaiseTime: null, TransitionTime: DateTimeOffset.UnixEpoch, + CurrentValue: "92.1", LimitValue: "90"); + + Assert.Equal("Tank01", t.SourceObjectReference); + Assert.Equal(800, t.Condition.Severity); + Assert.Equal(AlarmTransitionKind.Raise, t.Kind); + } +}