feat(v3-batch4-wp3): raw-only binding + UNS fan-out + write routing
Wave B of Batch 4 — the runtime binding seam for the dual namespace. Applier (both realms, explicit realm at every sink call site): - MaterialiseRawSubtree: Raw containers as folders + Raw tags as variables keyed by RawPath (native-alarm tag → single Part 9 condition at the RawPath), all in AddressSpaceRealm.Raw; historian tagname = override else RawPath. - MaterialiseUnsReferences: each UNS reference Variable under its equipment folder (Uns realm) + an Organizes UNS->Raw edge; inherits writable/array/ historian tagname from the backing raw tag (both NodeIds -> one tagname). - FeedHistorizedRefs / ProvisionHistorizedTags now source RAW tags (mux ref stays single, keyed by RawPath); ApplyPureRemove tears down raw tags + UNS refs in place (raw-container removal falls back to rebuild). DriverHostActor (dual-NodeId, single-source fan-out): - _nodeIdByDriverRef value gains a realm (NodeRealmRef); rebuilt from RawTags UNION UnsReferenceVariables so one (DriverInstanceId, RawPath) fans to the raw NodeId AND every referencing UNS NodeId with identical value/quality/timestamp. Write inverse map keyed by the bare id; the ns-qualified NodeId the write hook passes is normalised (BareNodeId) so a write to either NodeId resolves the same driver ref (-> RawPath write). - Native raw alarm condition routing is realm-tagged (Raw); AttributeValueUpdate + AlarmStateUpdate carry the realm through to the sink. Retire EquipmentNodeIds -> V3NodeIds.Uns (applier/VirtualTagHostActor) and RawPaths.Combine (DiscoveredNodeMapper, discovered nodes are Raw now). DeploymentArtifact.ParseComposition emits the Raw + UNS subtrees byte-parity with the composer (reconstruct entities -> AddressSpaceComposer.Compose). Sink surface: removed the transitional `= AddressSpaceRealm.Uns` defaults from IOpcUaAddressSpaceSink / ISurgicalAddressSpaceSink / SdkAddressSpaceSink / DeferredAddressSpaceSink / NullOpcUaAddressSpaceSink — every call site is now explicit (realm reordered before the trailing optionals on EnsureVariable + MaterialiseAlarmCondition). Node-manager convenience methods keep their defaults (they are not the interface impl; Sdk delegates explicitly). Tests: rewrote DriverHostActorLiveValueTests (fan-out drift, 1:N) + DriverHostActorWriteRoutingTests (dual-NodeId raw/uns write routing) to the v3 raw+uns model; new AddressSpaceApplierRawUnsTests; migrated the EquipmentTags provisioning/feed tests to RawTags; swept EquipmentNodeIds test callers. Claude-Session: https://claude.ai/code/session_01LVneM3eh1UtJxEisFXgmox
This commit is contained in:
@@ -148,7 +148,7 @@ public sealed class AddressSpaceApplierTests
|
||||
// A ReadWrite plan threads Writable: true through the applier to the sink (the node is created CurrentReadWrite).
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Speed", "eq-1", "Speed", "Float", true));
|
||||
// Parity: the materialiser's NodeId is the shared EquipmentNodeIds formula (null/empty FolderPath).
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
}
|
||||
|
||||
/// <summary>Verifies a FolderPath on an equipment tag becomes a sub-folder UNDER the equipment
|
||||
@@ -175,7 +175,7 @@ public sealed class AddressSpaceApplierTests
|
||||
// A Read plan threads Writable: false (the node stays CurrentRead).
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Diagnostics/Temp", "eq-1/Diagnostics", "Temp", "Float", false));
|
||||
// Parity: the materialiser's NodeId is the shared EquipmentNodeIds formula (with FolderPath).
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "Diagnostics", "Temp"));
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Diagnostics", "Temp"));
|
||||
}
|
||||
|
||||
/// <summary>Regression for the FullName-as-NodeId collision: two identical machines exposing the
|
||||
@@ -228,13 +228,13 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
|
||||
// The plain tag drove EnsureVariable at its folder-scoped NodeId, and NOT a condition.
|
||||
var plainNodeId = EquipmentNodeIds.Variable("eq-1", "", "Speed");
|
||||
var plainNodeId = V3NodeIds.Uns("eq-1", "Speed");
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe((plainNodeId, "eq-1", "Speed", "Float", true));
|
||||
sink.AlarmConditionCalls.ShouldNotContain(c => c.AlarmNodeId == plainNodeId);
|
||||
|
||||
// The alarm tag drove MaterialiseAlarmCondition (folder-scoped NodeId, equipment parent,
|
||||
// matching display/type/severity) and did NOT drive EnsureVariable.
|
||||
var alarmNodeId = EquipmentNodeIds.Variable("eq-1", "", "OverTemp");
|
||||
var alarmNodeId = V3NodeIds.Uns("eq-1", "OverTemp");
|
||||
// A native equipment-tag alarm: the call-site threads isNative: true.
|
||||
sink.AlarmConditionCalls.ShouldHaveSingleItem()
|
||||
.ShouldBe((alarmNodeId, "eq-1", "OverTemp", "OffNormalAlarm", 700, true));
|
||||
@@ -264,7 +264,7 @@ public sealed class AddressSpaceApplierTests
|
||||
// The sub-folder is still created for an alarm tag with a FolderPath.
|
||||
sink.FolderCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/Diagnostics", "eq-1", "Diagnostics"));
|
||||
// Condition is parented to the sub-folder, with the folder-scoped NodeId. No value variable.
|
||||
var alarmNodeId = EquipmentNodeIds.Variable("eq-1", "Diagnostics", "OverTemp");
|
||||
var alarmNodeId = V3NodeIds.Uns("eq-1", "Diagnostics", "OverTemp");
|
||||
// A native equipment-tag alarm (with a FolderPath): the call-site still threads isNative: true.
|
||||
sink.AlarmConditionCalls.ShouldHaveSingleItem()
|
||||
.ShouldBe((alarmNodeId, "eq-1/Diagnostics", "OverTemp", "OffNormalAlarm", 500, true));
|
||||
@@ -300,9 +300,9 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
|
||||
var byNode = sink.HistorianCalls.ToDictionary(c => c.NodeId, c => c.HistorianTagname);
|
||||
byNode[EquipmentNodeIds.Variable("eq-1", "", "ADefault")].ShouldBe("T.A"); // default ⇒ FullName
|
||||
byNode[EquipmentNodeIds.Variable("eq-1", "", "BOverride")].ShouldBe("WW.Override"); // override verbatim
|
||||
byNode[EquipmentNodeIds.Variable("eq-1", "", "CPlain")].ShouldBeNull(); // not historized ⇒ null
|
||||
byNode[V3NodeIds.Uns("eq-1", "ADefault")].ShouldBe("T.A"); // default ⇒ FullName
|
||||
byNode[V3NodeIds.Uns("eq-1", "BOverride")].ShouldBe("WW.Override"); // override verbatim
|
||||
byNode[V3NodeIds.Uns("eq-1", "CPlain")].ShouldBeNull(); // not historized ⇒ null
|
||||
}
|
||||
|
||||
/// <summary>Phase C Task 2 — a historized tag whose override is blank/whitespace still falls back to
|
||||
@@ -326,7 +326,7 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
|
||||
var call = sink.HistorianCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
call.HistorianTagname.ShouldBe("40001");
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
|
||||
var call = sink.ArrayCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Buffer"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Buffer"));
|
||||
call.IsArray.ShouldBeTrue();
|
||||
call.ArrayLength.ShouldBe(16u);
|
||||
}
|
||||
@@ -380,7 +380,7 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentTags(composition);
|
||||
|
||||
var call = sink.ArrayCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
call.IsArray.ShouldBeFalse();
|
||||
call.ArrayLength.ShouldBeNull();
|
||||
}
|
||||
@@ -471,11 +471,11 @@ public sealed class AddressSpaceApplierTests
|
||||
// VirtualTags are computed outputs — always read-only (Writable: false).
|
||||
sink.VariableCalls.ShouldHaveSingleItem().ShouldBe(("eq-1/speed-rpm", "eq-1", "speed-rpm", "Float64", false));
|
||||
// Parity: the vtag materialiser's NodeId is the shared EquipmentNodeIds formula.
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "speed-rpm"));
|
||||
sink.VariableCalls.Single().NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "speed-rpm"));
|
||||
}
|
||||
|
||||
/// <summary>Golden/parity guard: the materialiser's Variable NodeId for BOTH the equipment-tag and
|
||||
/// the equipment-VirtualTag pass is byte-identical to <see cref="EquipmentNodeIds.Variable"/> — the
|
||||
/// the equipment-VirtualTag pass is byte-identical to <c>V3NodeIds.Uns</c> — the
|
||||
/// single source of truth AddressSpaceApplier + VirtualTagHostActor both point at. Covers null/empty
|
||||
/// FolderPath (directly under equipment) and a non-empty FolderPath (sub-folder scoped). This test
|
||||
/// LOCKS the formula against drift: any change to the materialiser NodeId that diverges from the
|
||||
@@ -507,10 +507,10 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.MaterialiseEquipmentVirtualTags(composition);
|
||||
|
||||
var nodeIds = sink.VariableCalls.Select(v => v.NodeId).ToList();
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-1", "Diagnostics", "Temp"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-2", "", "Efficiency"));
|
||||
nodeIds.ShouldContain(EquipmentNodeIds.Variable("eq-2", "Calc", "Avg"));
|
||||
nodeIds.ShouldContain(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
nodeIds.ShouldContain(V3NodeIds.Uns("eq-1", "Diagnostics", "Temp"));
|
||||
nodeIds.ShouldContain(V3NodeIds.Uns("eq-2", "Efficiency"));
|
||||
nodeIds.ShouldContain(V3NodeIds.Uns("eq-2", "Calc", "Avg"));
|
||||
}
|
||||
|
||||
/// <summary>Two VirtualTags under the SAME equipment produce two distinct folder-scoped variables
|
||||
@@ -760,7 +760,7 @@ public sealed class AddressSpaceApplierTests
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
sink.RebuildCalls.ShouldBe(0);
|
||||
var call = sink.SurgicalCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
call.Writable.ShouldBeTrue();
|
||||
}
|
||||
|
||||
@@ -815,7 +815,7 @@ public sealed class AddressSpaceApplierTests
|
||||
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
sink.RebuildCalls.ShouldBe(0);
|
||||
var nodeId = EquipmentNodeIds.Variable("eq-1", "", "Speed");
|
||||
var nodeId = V3NodeIds.Uns("eq-1", "Speed");
|
||||
// Terminal Bad written to the removed variable BEFORE the removal.
|
||||
sink.ValueWrites.ShouldContain((nodeId, OpcUaQuality.Bad));
|
||||
sink.RemoveCalls.ShouldHaveSingleItem().ShouldBe(("var", nodeId));
|
||||
@@ -842,7 +842,7 @@ public sealed class AddressSpaceApplierTests
|
||||
var outcome = applier.Apply(plan);
|
||||
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
var nodeId = EquipmentNodeIds.Variable("eq-1", "", "OverTemp");
|
||||
var nodeId = V3NodeIds.Uns("eq-1", "OverTemp");
|
||||
// Terminal RemovedConditionState (inactive/acked/confirmed) written to the condition node.
|
||||
var write = sink.AlarmWrites.ShouldHaveSingleItem();
|
||||
write.NodeId.ShouldBe(nodeId);
|
||||
@@ -953,7 +953,7 @@ public sealed class AddressSpaceApplierTests
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
sink.RebuildCalls.ShouldBe(0);
|
||||
// The removed node is torn down in place; the add is left to the publish actor's materialise passes.
|
||||
sink.RemoveCalls.ShouldHaveSingleItem().ShouldBe(("var", EquipmentNodeIds.Variable("eq-1", "", "Old")));
|
||||
sink.RemoveCalls.ShouldHaveSingleItem().ShouldBe(("var", V3NodeIds.Uns("eq-1", "Old")));
|
||||
outcome.AddedNodes.ShouldBe(1);
|
||||
outcome.RemovedNodes.ShouldBe(1);
|
||||
}
|
||||
@@ -967,7 +967,7 @@ public sealed class AddressSpaceApplierTests
|
||||
var sink = new RecordingSink();
|
||||
var applier = new AddressSpaceApplier(sink, NullLogger<AddressSpaceApplier>.Instance);
|
||||
|
||||
var nodeId = EquipmentNodeIds.Variable("eq-1", "", "Slot");
|
||||
var nodeId = V3NodeIds.Uns("eq-1", "Slot");
|
||||
var plan = EmptyPlan with
|
||||
{
|
||||
// Different TagId, but both resolve to the SAME folder-scoped NodeId (eq-1/Slot).
|
||||
@@ -1457,8 +1457,8 @@ public sealed class AddressSpaceApplierTests
|
||||
sink.RebuildCalls.ShouldBe(0);
|
||||
outcome.RemovedNodes.ShouldBe(2); // both removals counted
|
||||
sink.RemoveCalls.Count.ShouldBe(2);
|
||||
sink.RemoveCalls.ShouldContain(("var", EquipmentNodeIds.Variable("eq-1", "", "Speed")));
|
||||
sink.RemoveCalls.ShouldContain(("var", EquipmentNodeIds.Variable("eq-1", "", "Efficiency")));
|
||||
sink.RemoveCalls.ShouldContain(("var", V3NodeIds.Uns("eq-1", "Speed")));
|
||||
sink.RemoveCalls.ShouldContain(("var", V3NodeIds.Uns("eq-1", "Efficiency")));
|
||||
}
|
||||
|
||||
// ----- F10b: surgical in-place tag-attribute writes (Writable / IsHistorized / HistorianTagname) -----
|
||||
@@ -1490,7 +1490,7 @@ public sealed class AddressSpaceApplierTests
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
sink.RebuildCalls.ShouldBe(0); // NO RebuildAddressSpace — subscriptions preserved
|
||||
var call = sink.SurgicalCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
call.Writable.ShouldBeTrue(); // the NEW Writable value
|
||||
call.Historian.ShouldBeNull(); // not historized
|
||||
outcome.ChangedNodes.ShouldBe(1);
|
||||
@@ -1584,7 +1584,7 @@ public sealed class AddressSpaceApplierTests
|
||||
outcome.RebuildCalled.ShouldBeFalse();
|
||||
sink.RebuildCalls.ShouldBe(0); // NO rebuild — subscriptions preserved
|
||||
var call = sink.SurgicalCalls.ShouldHaveSingleItem();
|
||||
call.NodeId.ShouldBe(EquipmentNodeIds.Variable("eq-1", "", "Speed"));
|
||||
call.NodeId.ShouldBe(V3NodeIds.Uns("eq-1", "Speed"));
|
||||
call.DataType.ShouldBe("Int32"); // the NEW DataType
|
||||
call.Writable.ShouldBeTrue(); // the NEW Writable, applied in the same call
|
||||
call.IsArray.ShouldBeFalse();
|
||||
@@ -1781,8 +1781,8 @@ public sealed class AddressSpaceApplierTests
|
||||
sink.SurgicalCalls.Count.ShouldBe(2);
|
||||
|
||||
// Both expected node ids must appear (order is not guaranteed).
|
||||
var nodeId1 = EquipmentNodeIds.Variable("eq-1", "", "Speed");
|
||||
var nodeId2 = EquipmentNodeIds.Variable("eq-1", "", "Pressure");
|
||||
var nodeId1 = V3NodeIds.Uns("eq-1", "Speed");
|
||||
var nodeId2 = V3NodeIds.Uns("eq-1", "Pressure");
|
||||
sink.SurgicalCalls.ShouldContain(c => c.NodeId == nodeId1 && c.Writable);
|
||||
sink.SurgicalCalls.ShouldContain(c => c.NodeId == nodeId2 && c.Writable);
|
||||
|
||||
@@ -2040,7 +2040,7 @@ public sealed class AddressSpaceApplierTests
|
||||
},
|
||||
};
|
||||
|
||||
applier.ComputeAddAnnouncements(plan).ShouldBe(new[] { EquipmentNodeIds.SubFolder("eq-1", "Diag") });
|
||||
applier.ComputeAddAnnouncements(plan).ShouldBe(new[] { V3NodeIds.Uns("eq-1", "Diag") });
|
||||
}
|
||||
|
||||
/// <summary>An added scripted alarm announces its equipment folder (where its condition node parents).</summary>
|
||||
@@ -2101,7 +2101,7 @@ public sealed class AddressSpaceApplierTests
|
||||
applier.AnnounceAddedNodes(plan);
|
||||
|
||||
sink.ModelChangeCalls.OrderBy(x => x).ShouldBe(
|
||||
new[] { "eq-1", EquipmentNodeIds.SubFolder("eq-1", "Diag"), "line-7" }.OrderBy(x => x));
|
||||
new[] { "eq-1", V3NodeIds.Uns("eq-1", "Diag"), "line-7" }.OrderBy(x => x));
|
||||
}
|
||||
|
||||
private static AddressSpaceComposition CompositionWithAreas(params UnsAreaProjection[] areas) =>
|
||||
@@ -2276,7 +2276,7 @@ public sealed class AddressSpaceApplierTests
|
||||
/// <param name="displayName">The condition display name.</param>
|
||||
/// <param name="alarmType">The domain alarm type.</param>
|
||||
/// <param name="severity">The domain severity.</param>
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false, AddressSpaceRealm realm = AddressSpaceRealm.Uns)
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, AddressSpaceRealm realm, bool isNative = false)
|
||||
=> AlarmConditionQueue.Enqueue((alarmNodeId, equipmentNodeId, displayName, alarmType, severity, isNative));
|
||||
/// <summary>Records a folder creation call.</summary>
|
||||
/// <param name="folderNodeId">The folder node ID.</param>
|
||||
@@ -2291,7 +2291,7 @@ public sealed class AddressSpaceApplierTests
|
||||
/// <param name="dataType">The OPC UA built-in type name.</param>
|
||||
/// <param name="writable">Whether the node is created read/write.</param>
|
||||
/// <param name="historianTagname">The resolved historian tagname (null ⇒ not historized).</param>
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null, AddressSpaceRealm realm = AddressSpaceRealm.Uns)
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, AddressSpaceRealm realm, string? historianTagname = null, bool isArray = false, uint? arrayLength = null)
|
||||
{
|
||||
VariableQueue.Enqueue((variableNodeId, parentFolderNodeId, displayName, dataType, writable));
|
||||
HistorianQueue.Enqueue((variableNodeId, historianTagname));
|
||||
@@ -2323,11 +2323,11 @@ public sealed class AddressSpaceApplierTests
|
||||
/// <summary>No-op alarm condition write call.</summary>
|
||||
public void WriteAlarmCondition(string alarmNodeId, AlarmConditionSnapshot state, DateTime sourceTimestampUtc, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
/// <summary>No-op alarm-condition materialise call.</summary>
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, AddressSpaceRealm realm, bool isNative = false) { }
|
||||
/// <summary>No-op folder creation call.</summary>
|
||||
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
/// <summary>No-op variable creation call.</summary>
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, AddressSpaceRealm realm, string? historianTagname = null, bool isArray = false, uint? arrayLength = null) { }
|
||||
/// <summary>Records a rebuild address space call.</summary>
|
||||
public void RebuildAddressSpace() => Interlocked.Increment(ref RebuildCalls);
|
||||
/// <summary>No-op NodeAdded model-change announcement.</summary>
|
||||
@@ -2363,7 +2363,7 @@ public sealed class AddressSpaceApplierTests
|
||||
/// <param name="displayName">The condition display name.</param>
|
||||
/// <param name="alarmType">The domain alarm type.</param>
|
||||
/// <param name="severity">The domain severity.</param>
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, bool isNative = false, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity, AddressSpaceRealm realm, bool isNative = false) { }
|
||||
/// <summary>No-op folder creation call.</summary>
|
||||
/// <param name="folderNodeId">The folder node ID.</param>
|
||||
/// <param name="parentNodeId">The parent folder node ID, if any.</param>
|
||||
@@ -2376,7 +2376,7 @@ public sealed class AddressSpaceApplierTests
|
||||
/// <param name="dataType">The OPC UA built-in type name.</param>
|
||||
/// <param name="writable">Whether the node is created read/write.</param>
|
||||
/// <param name="historianTagname">The resolved historian tagname (null ⇒ not historized).</param>
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, string? historianTagname = null, bool isArray = false, uint? arrayLength = null, AddressSpaceRealm realm = AddressSpaceRealm.Uns) { }
|
||||
public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType, bool writable, AddressSpaceRealm realm, string? historianTagname = null, bool isArray = false, uint? arrayLength = null) { }
|
||||
/// <summary>No-op rebuild address space call.</summary>
|
||||
public void RebuildAddressSpace() { }
|
||||
/// <summary>No-op NodeAdded model-change announcement.</summary>
|
||||
|
||||
Reference in New Issue
Block a user