607dc51dec
v2-ci / build (push) Failing after 42s
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 (push) Has been skipped
Phase7Composer now carries UnsAreaProjection + UnsLineProjection lists so the applier can materialise the full UNS topology in the OPC UA address space. New IOpcUaAddressSpaceSink.EnsureFolder(folderNodeId, parentNodeId, displayName) seam (no-op default, recorded in tests, forwarded by DeferredAddressSpaceSink, implemented by SdkAddressSpaceSink). The SDK- side OtOpcUaNodeManager gains an EnsureFolder API that creates FolderState nodes with proper parent linkage; RebuildAddressSpace now clears folders too so re-applies don't accumulate stale topology. Phase7Applier.MaterialiseHierarchy walks composition.UnsAreas → composition.UnsLines → composition.EquipmentNodes, calling EnsureFolder with the correct parent at each level. Idempotent — calling twice with the same composition is a no-op. OpcUaPublishActor.HandleRebuild invokes it after Phase7Applier.Apply so OPC UA clients browsing the server now see Area/Line/Equipment as proper folders rather than flat tag ids. DeploymentArtifact.ParseComposition reads UnsAreas + UnsLines from the JSON snapshot the ControlPlane emits, populating the new fields when present. Phase7Composer.Compose now accepts UnsAreas + UnsLines; a 3-arg overload preserves the old signature for legacy callers + existing tests. The Phase7CompositionResult convenience ctor likewise keeps the planner tests working without UNS data. 3 new hierarchy tests (pure unit + boot-verify against a real OtOpcUaSdkServer); OpcUaServer suite is 48/48 green (was 45, +3), Runtime 74/74 unchanged. Closes #85.
47 lines
2.5 KiB
C#
47 lines
2.5 KiB
C#
namespace ZB.MOM.WW.OtOpcUa.Commons.OpcUa;
|
|
|
|
/// <summary>
|
|
/// Abstraction over the OPC UA SDK's address space. <c>OpcUaPublishActor</c> consumes this
|
|
/// so the Runtime project doesn't reference <c>Opc.Ua.Server</c> directly — production
|
|
/// binds a real SDK-backed sink in the fused Host's wiring, dev/Mac binds the
|
|
/// <see cref="NullOpcUaAddressSpaceSink"/> no-op.
|
|
/// </summary>
|
|
public interface IOpcUaAddressSpaceSink
|
|
{
|
|
/// <summary>Write a Variable node's current value + quality + source timestamp.</summary>
|
|
void WriteValue(string nodeId, object? value, OpcUaQuality quality, DateTime sourceTimestampUtc);
|
|
|
|
/// <summary>Write an alarm-condition Variable's active/acknowledged state.</summary>
|
|
void WriteAlarmState(string alarmNodeId, bool active, bool acknowledged, DateTime sourceTimestampUtc);
|
|
|
|
/// <summary>
|
|
/// Ensure a folder node exists under the given parent. Used by <c>Phase7Applier</c> to
|
|
/// materialise the UNS Area/Line/Equipment hierarchy in the address space. When
|
|
/// <paramref name="parentNodeId"/> is null the folder is parented under the namespace
|
|
/// root. Idempotent: calling twice with the same id is safe.
|
|
/// </summary>
|
|
void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName);
|
|
|
|
/// <summary>
|
|
/// Tear down + repopulate the address space. Called by <c>OpcUaPublishActor</c> after a
|
|
/// successful deployment apply so the node manager reflects the new config. Idempotent.
|
|
/// </summary>
|
|
void RebuildAddressSpace();
|
|
}
|
|
|
|
/// <summary>OPC UA status code projection — Good / Uncertain / Bad. Real SDK has finer-grained
|
|
/// codes; the engine actors only need this 3-state classification.</summary>
|
|
public enum OpcUaQuality { Good, Uncertain, Bad }
|
|
|
|
/// <summary>No-op sink. Bound by default so the actors are safe to run in dev / Mac /
|
|
/// integration tests without a real SDK behind them.</summary>
|
|
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 WriteAlarmState(string alarmNodeId, bool active, bool acknowledged, DateTime sourceTimestampUtc) { }
|
|
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) { }
|
|
public void RebuildAddressSpace() { }
|
|
}
|