namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa; /// /// Abstraction over the OPC UA SDK's address space. OpcUaPublishActor consumes this /// so the Runtime project doesn't reference Opc.Ua.Server directly — production /// binds a real SDK-backed sink in the fused Host's wiring, dev/Mac binds the /// no-op. /// public interface IOpcUaAddressSpaceSink { /// Write a Variable node's current value + quality + source timestamp. /// The OPC UA node ID of the variable. /// The value to write. /// The quality status of the value. /// The source timestamp in UTC. void WriteValue(string nodeId, object? value, OpcUaQuality quality, DateTime sourceTimestampUtc); /// Write an alarm-condition's full Part 9 state. When a real condition node has been /// materialised for via , /// this projects the whole /// (Enabled/Active/Acked/Confirmed/Shelving/Severity/Message) onto it and recomputes Retain; /// otherwise it falls back to the legacy two-element [Active, Acknowledged] placeholder /// variable. A materialised condition also fires a Part 9 condition event on each transition (T16) /// so subscribed clients receive the alarm event, not just the changed attributes. /// The OPC UA node ID of the alarm (== ScriptedAlarmId for materialised conditions). /// The full condition state to project onto the node. /// The source timestamp in UTC. void WriteAlarmCondition(string alarmNodeId, AlarmConditionSnapshot state, DateTime sourceTimestampUtc); /// /// Materialise a real OPC UA Part 9 alarm-condition node under its equipment folder so clients /// can browse it as a proper condition (with basic Active/Ack state). The node id equals the /// alarm node id (the ScriptedAlarmId) so subsequent calls update /// it. Used by AddressSpaceApplier.MaterialiseScriptedAlarms. Idempotent. /// /// The alarm node ID (== ScriptedAlarmId); becomes the condition's NodeId. /// The equipment folder node ID the condition parents under. /// Human-readable condition name (BrowseName / DisplayName / Message). /// Domain alarm type — mapped to the SDK condition subtype by the sink. /// Domain severity (OPC UA 1..1000 scale); mapped to the SDK severity buckets. /// When true this is a driver-fed (native, e.g. Galaxy) equipment-tag alarm; when /// false (default) it is a scripted alarm. The node manager tracks native condition node ids so a later /// task can route a native condition's inbound Acknowledge to the driver instead of the scripted engine. void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false); /// /// Ensure a folder node exists under the given parent. Used by AddressSpaceApplier to /// materialise the UNS Area/Line/Equipment hierarchy in the address space. When /// is null the folder is parented under the namespace /// root. Idempotent: calling twice with the same id is safe. /// /// The OPC UA node ID for the folder. /// The parent folder node ID, or null for namespace root. /// The display name for the folder. void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName); /// /// Ensure a Variable node exists at , parented under /// (or the namespace root when null). Created with /// Bad quality + null value; subsequent calls update both. /// Used by AddressSpaceApplier to materialise equipment-namespace tags ahead of any /// driver-side subscribe so OPC UA clients can browse them. Idempotent. /// /// The OPC UA node ID for the variable. /// The parent folder node ID, or null for namespace root. /// The display name for the variable. /// OPC UA built-in type name ("Boolean" / "Int32" / "Float" / etc.). /// When true the node is created CurrentReadWrite (an authored /// ReadWrite equipment tag); when false it stays CurrentRead (read-only). Non-equipment-tag /// variables (folders' children, alarm placeholders) always pass false. /// null ⇒ the variable is not historized; non-null ⇒ create it /// Historizing with the HistoryRead access bit and register the (already default-resolved) /// historian tagname. /// When true the node is created as a 1-D array (ValueRank=OneDimension /// with ArrayDimensions=[arrayLength]); when false (default) it stays scalar /// (ValueRank=Scalar). Array elements share the scalar's base — /// rank + dimensions carry the array-ness. /// The declared length of the 1-D array when is /// true; ignored for scalars. Null ⇒ length 0 (unbounded). void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null); /// /// Tear down + repopulate the address space. Called by OpcUaPublishActor after a /// successful deployment apply so the node manager reflects the new config. Idempotent. /// void RebuildAddressSpace(); /// /// Announce that nodes were added at runtime (discovered-node injection) under /// so subscribed clients refresh their browse /// (Part 3 GeneralModelChangeEvent, verb NodeAdded). /// /// The node under which discovered nodes were added. void RaiseNodesAddedModelChange(string affectedNodeId); } /// OPC UA status code projection — Good / Uncertain / Bad. Real SDK has finer-grained /// codes; the engine actors only need this 3-state classification. public enum OpcUaQuality { Good, Uncertain, Bad } /// No-op sink. Bound by default so the actors are safe to run in dev / Mac / /// integration tests without a real SDK behind them. public sealed class NullOpcUaAddressSpaceSink : IOpcUaAddressSpaceSink { public static readonly NullOpcUaAddressSpaceSink Instance = new(); private NullOpcUaAddressSpaceSink() { } /// public void WriteValue(string nodeId, object? value, OpcUaQuality quality, DateTime sourceTimestampUtc) { } /// public void WriteAlarmCondition(string alarmNodeId, AlarmConditionSnapshot state, DateTime sourceTimestampUtc) { } /// public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false) { } /// public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) { } /// public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null) { } /// public void RebuildAddressSpace() { } /// public void RaiseNodesAddedModelChange(string affectedNodeId) { } }