diff --git a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Cli/Commands/SubscribeCommand.cs b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Cli/Commands/SubscribeCommand.cs
index f4645ef2..429c0a4b 100644
--- a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Cli/Commands/SubscribeCommand.cs
+++ b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Cli/Commands/SubscribeCommand.cs
@@ -12,20 +12,20 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.AbLegacy.Cli.Commands;
[Command("subscribe", Description = "Watch a PCCC file address via polled subscription until Ctrl+C.")]
public sealed class SubscribeCommand : AbLegacyCommandBase
{
- [CommandOption("address", 'a', Description = "PCCC file address — same format as `read`.", IsRequired = true)]
/// Gets or sets the PCCC file address to subscribe to.
+ [CommandOption("address", 'a', Description = "PCCC file address — same format as `read`.", IsRequired = true)]
public string Address { get; init; } = default!;
+ /// Gets or sets the data type of the address.
[CommandOption("type", 't', Description =
"Bit / Int / Long / Float / AnalogInt / String / TimerElement / CounterElement / " +
"ControlElement (default Int).")]
- /// Gets or sets the data type of the address.
public AbLegacyDataType DataType { get; init; } = AbLegacyDataType.Int;
+ /// Gets or sets the polling interval in milliseconds.
[CommandOption("interval-ms", 'i', Description =
"Publishing interval in milliseconds (default 1000). PollGroupEngine floors " +
"sub-250ms values.")]
- /// Gets or sets the polling interval in milliseconds.
public int IntervalMs { get; init; } = 1000;
///
diff --git a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/Commands/ProbeCommand.cs b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/Commands/ProbeCommand.cs
index f76b4929..4e1aaf23 100644
--- a/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/Commands/ProbeCommand.cs
+++ b/src/Drivers/Cli/ZB.MOM.WW.OtOpcUa.Driver.S7.Cli/Commands/ProbeCommand.cs
@@ -13,14 +13,14 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Commands;
[Command("probe", Description = "Verify the S7 endpoint is reachable and a sample read succeeds.")]
public sealed class ProbeCommand : S7CommandBase
{
+ /// Gets or sets the S7 address to probe.
[CommandOption("address", 'a', Description =
"Probe address (default MW0 — merker word 0). DB1.DBW0 if your PLC project " +
"reserves a fingerprint DB.")]
- /// Gets or sets the S7 address to probe.
public string Address { get; init; } = "MW0";
- [CommandOption("type", Description = "Probe data type (default Int16).")]
/// Gets or sets the data type of the probe address.
+ [CommandOption("type", Description = "Probe data type (default Int16).")]
public S7DataType DataType { get; init; } = S7DataType.Int16;
///
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs
index 25324ace..1961e3c8 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/DeferredAddressSpaceSinkTests.cs
@@ -84,6 +84,9 @@ public sealed class DeferredAddressSpaceSinkTests
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName)
=> CallQueue.Enqueue($"EF:{folderNodeId}");
///
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType)
+ => CallQueue.Enqueue($"EV:{variableNodeId}");
+ ///
public void RebuildAddressSpace() => CallQueue.Enqueue("RB");
}
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs
index 316aa466..9f914e9b 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierHierarchyTests.cs
@@ -149,6 +149,12 @@ public sealed class Phase7ApplierHierarchyTests : IDisposable
/// The display name of the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName)
=> _calls.Enqueue((folderNodeId, parentNodeId, displayName));
+ /// Ensures a variable exists (stub implementation for testing).
+ /// The node ID of the variable.
+ /// The node ID of the parent folder, or null for root.
+ /// The display name of the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType) { }
/// Rebuilds the address space (stub implementation for testing).
public void RebuildAddressSpace() { }
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs
index 01c825a5..5d7d02eb 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests/Phase7ApplierTests.cs
@@ -133,6 +133,8 @@ public sealed class Phase7ApplierTests
public ConcurrentQueue<(string NodeId, bool Active, bool Acknowledged)> AlarmQueue { get; } = new();
/// Gets the queue of folder creation calls.
public ConcurrentQueue<(string NodeId, string? Parent, string DisplayName)> FolderQueue { get; } = new();
+ /// Gets the queue of variable creation calls.
+ public ConcurrentQueue<(string NodeId, string? Parent, string DisplayName, string DataType)> VariableQueue { get; } = new();
/// Gets the number of rebuild calls made on this sink.
public int RebuildCalls;
@@ -140,6 +142,8 @@ public sealed class Phase7ApplierTests
public List<(string NodeId, bool Active, bool Acknowledged)> AlarmWrites => AlarmQueue.ToList();
/// Gets the list of recorded folder creation calls.
public List<(string NodeId, string? Parent, string DisplayName)> FolderCalls => FolderQueue.ToList();
+ /// Gets the list of recorded variable creation calls.
+ public List<(string NodeId, string? Parent, string DisplayName, string DataType)> VariableCalls => VariableQueue.ToList();
/// Records a value write (no-op in this recording sink).
/// The node ID.
@@ -160,6 +164,13 @@ public sealed class Phase7ApplierTests
/// The display name for the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName)
=> FolderQueue.Enqueue((folderNodeId, parentNodeId, displayName));
+ /// Records a variable creation call.
+ /// The variable node ID.
+ /// The parent folder node ID, if any.
+ /// The display name for the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType)
+ => VariableQueue.Enqueue((variableNodeId, parentFolderNodeId, displayName, dataType));
/// Records a rebuild address space call.
public void RebuildAddressSpace() => Interlocked.Increment(ref RebuildCalls);
}
@@ -192,6 +203,12 @@ public sealed class Phase7ApplierTests
/// The parent folder node ID, if any.
/// The display name for the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) { }
+ /// No-op variable creation call.
+ /// The variable node ID.
+ /// The parent folder node ID, if any.
+ /// The display name for the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType) { }
/// No-op rebuild address space call.
public void RebuildAddressSpace() { }
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Observability/OtOpcUaTelemetryHookTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Observability/OtOpcUaTelemetryHookTests.cs
index 8629ffae..62e08ee6 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Observability/OtOpcUaTelemetryHookTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/Observability/OtOpcUaTelemetryHookTests.cs
@@ -206,6 +206,12 @@ public sealed class OtOpcUaTelemetryHookTests : RuntimeActorTestBase
/// The parent folder node identifier.
/// The display name for the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) { }
+ /// Ensures variable exists (stub implementation).
+ /// The variable node identifier.
+ /// The parent folder node identifier.
+ /// The display name for the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType) { }
/// Rebuilds address space (recorded via span).
public void RebuildAddressSpace() { /* recorded via span */ }
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs
index 6e3abb09..618c1672 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorRebuildTests.cs
@@ -161,6 +161,13 @@ public sealed class OpcUaPublishActorRebuildTests : RuntimeActorTestBase
/// The display name of the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName)
=> Calls.Enqueue($"EF:{folderNodeId}");
+ /// Records a variable ensure call.
+ /// The variable node ID.
+ /// The parent folder node ID, or null if this is a root variable.
+ /// The display name of the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType)
+ => Calls.Enqueue($"EV:{variableNodeId}");
/// Records a rebuild address space call.
public void RebuildAddressSpace() => Interlocked.Increment(ref RebuildCalls);
}
diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorTests.cs
index 00680064..f89033a2 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests/OpcUa/OpcUaPublishActorTests.cs
@@ -182,6 +182,13 @@ public sealed class OpcUaPublishActorTests : RuntimeActorTestBase
/// The display name of the folder.
public void EnsureFolder(string folderNodeId, string? parentNodeId, string displayName) { }
+ /// Ensures a variable exists (no-op in test).
+ /// The OPC UA variable node identifier.
+ /// The parent folder node identifier, or null for root.
+ /// The display name of the variable.
+ /// The OPC UA built-in type name.
+ public void EnsureVariable(string variableNodeId, string? parentFolderNodeId, string displayName, string dataType) { }
+
/// Records a rebuild call.
public void RebuildAddressSpace() => Interlocked.Increment(ref RebuildCalls);
}