Files
lmxopcua/docs/CliTool.md
Joseph Doherty afd6c33d9d Add client-side failover to CLI tool for redundancy testing
All commands gain --failover-urls (-F) to specify alternate endpoints.
Short-lived commands try each URL in order on initial connect. The
subscribe command monitors KeepAlive and automatically reconnects to
the next available server, re-creating the subscription on failover.
Verified with live service start/stop: primary down triggers failover
to secondary, primary restart allows failback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 14:41:06 -04:00

11 KiB

CLI Tool

Overview

The OPC UA CLI tool at tools/opcuacli-dotnet/ is a command-line utility for testing OPC UA server functions. It targets .NET 10 and uses the OPC Foundation UA .NET Standard client library for OPC UA operations and CliFx for command routing and argument parsing.

The tool is not part of the production service. It exists to verify that the LmxOpcUa server correctly exposes browse nodes, reads, writes, subscriptions, historical data, and alarm events without requiring a full OPC UA client application.

Build and Run

cd tools/opcuacli-dotnet
dotnet build
dotnet run -- <command> [options]

Shared Session Creation

OpcUaHelper.ConnectAsync() creates an OPC UA client session used by all commands. It configures the application identity, sets up directory-based certificate stores under %LocalAppData%\OpcUaCli\pki\, and auto-accepts untrusted server certificates. The session timeout is 60 seconds.

OpcUaHelper.ConvertValue() converts a raw string from the command line into the runtime type expected by the target node. It uses the current node value to infer the type (bool, byte, short, int, float, double, etc.) and falls back to string if the type is not recognized.

Authentication Options

All commands accept optional credentials for UserName token authentication:

Flag Description
-U / --username Username for OPC UA UserName token authentication
-P / --password Password for OPC UA UserName token authentication

When -U and -P are provided, OpcUaHelper.ConnectAsync() passes a UserIdentity(username, password) to Session.Create. Without credentials, an anonymous UserIdentity is used.

Example:

dotnet run -- write -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -v 42 -U operator -P op123

Failover Options

All commands accept the -F / --failover-urls flag for automatic redundancy failover:

Flag Description
-F / --failover-urls Comma-separated list of alternate OPC UA endpoint URLs to try if the primary is unreachable

When failover URLs are provided, the CLI tries the primary URL first, then each failover URL in order until one connects. For long-running commands (subscribe), the CLI monitors the session and automatically reconnects to the next available server if the current one drops.

Examples:

# Connect with failover
dotnet run -- connect -u opc.tcp://localhost:4840/LmxOpcUa -F opc.tcp://localhost:4841/LmxOpcUa

# Subscribe with automatic failover on disconnect
dotnet run -- subscribe -u opc.tcp://localhost:4840/LmxOpcUa -F opc.tcp://localhost:4841/LmxOpcUa -n "ns=1;s=MyNode"

# Read redundancy state with failover
dotnet run -- redundancy -u opc.tcp://localhost:4840/LmxOpcUa -F opc.tcp://localhost:4841/LmxOpcUa

Transport Security Options

All commands accept the -S / --security flag to select the transport security mode:

Flag Values Description
-S / --security none, sign, encrypt Transport security mode (default: none)

When sign or encrypt is specified, the CLI tool:

  1. Ensures a client application certificate exists (auto-created if missing)
  2. Discovers server endpoints and selects one matching the requested MessageSecurityMode
  3. Prefers Basic256Sha256 when multiple matching endpoints exist
  4. Fails with a clear error if no matching endpoint is found

Examples:

# Connect with encrypted transport
dotnet run -- connect -u opc.tcp://localhost:4840/LmxOpcUa -S encrypt

# Browse with signed transport and credentials
dotnet run -- browse -u opc.tcp://localhost:4840/LmxOpcUa -S sign -U admin -P secret -r -d 2

Commands

connect

Tests connectivity to an OPC UA server endpoint. Creates a session and immediately disconnects.

dotnet run -- connect -u opc.tcp://localhost:4840

browse

Browses the OPC UA address space starting from the Objects folder or a specified node. Supports recursive traversal with a configurable depth limit.

# Browse top-level Objects folder
dotnet run -- browse -u opc.tcp://localhost:4840

# Browse a specific node
dotnet run -- browse -u opc.tcp://localhost:4840 -n "ns=2;s=MyFolder"

# Browse recursively to depth 3
dotnet run -- browse -u opc.tcp://localhost:4840 -r -d 3
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to browse (default: Objects folder)
-d Maximum browse depth (default: 1)
-r Browse recursively using -d as max depth

read

Reads the current value of a single node and prints the value, data type, status code, and timestamps.

dotnet run -- read -u opc.tcp://localhost:4840 -n "ns=2;s=TestMachine_001.SomeAttribute"
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to read (required)

write

Writes a value to a node. The command reads the current value first to determine the target data type, then converts the supplied string value to that type using OpcUaHelper.ConvertValue().

dotnet run -- write -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -v 42
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to write to (required)
-v Value to write (required)

subscribe

Monitors a node for value changes using OPC UA subscriptions. Creates a MonitoredItem with the specified sampling interval and prints each notification with its source timestamp, value, and status code. Prints periodic tick lines showing session state, subscription ID, publishing status, and last notification value. Runs until Ctrl+C.

dotnet run -- subscribe -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -i 500
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to monitor (required)
-i Sampling/publishing interval in milliseconds (default: 1000)

historyread

Reads historical data from a node. Supports both raw history reads and aggregate (processed) history reads.

# Raw history
dotnet run -- historyread -u opc.tcp://localhost:4840/LmxOpcUa \
  -n "ns=1;s=TestMachine_001.TestHistoryValue" \
  --start "2026-03-25" --end "2026-03-30"

# Aggregate: 1-hour average
dotnet run -- historyread -u opc.tcp://localhost:4840/LmxOpcUa \
  -n "ns=1;s=TestMachine_001.TestHistoryValue" \
  --start "2026-03-25" --end "2026-03-30" \
  --aggregate Average --interval 3600000
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to read history for (required)
--start Start time, ISO 8601 or date string (default: 24 hours ago)
--end End time, ISO 8601 or date string (default: now)
--max Maximum number of values (default: 1000)
--aggregate Aggregate function: Average, Minimum, Maximum, Count, Start, End
--interval Processing interval in milliseconds for aggregates (default: 3600000)

Continuation points

When reading raw history, the server may return more values than fit in a single response. The command handles this by checking the ContinuationPoint on each result. If a continuation point is present, it issues follow-up HistoryRead calls with ReleaseContinuationPoints = false (i.e., continuationPoint != null is passed to the next read) until either the continuation point is empty or the --max limit is reached. This ensures that large result sets are fetched in full without requiring the caller to manage pagination.

Aggregate mapping

The --aggregate option maps human-readable names to OPC UA aggregate function node IDs:

Name OPC UA Node ID
average AggregateFunction_Average
minimum / min AggregateFunction_Minimum
maximum / max AggregateFunction_Maximum
count AggregateFunction_Count
start / first AggregateFunction_Start
end / last AggregateFunction_End

alarms

Subscribes to alarm events on a node using OPC UA event subscriptions. Creates a MonitoredItem with AttributeId = EventNotifier and an EventFilter that selects alarm-relevant fields from the event stream. Runs until Ctrl+C.

# Subscribe to alarm events
dotnet run -- alarms -u opc.tcp://localhost:4840/LmxOpcUa \
  -n "ns=1;s=TestMachine_001"

# With condition refresh to get current alarm states
dotnet run -- alarms -u opc.tcp://localhost:4840/LmxOpcUa \
  -n "ns=1;s=TestMachine_001" --refresh
Flag Description
-u OPC UA server endpoint URL (required)
-n Node ID to monitor for events (default: Server node)
-i Publishing interval in milliseconds (default: 1000)
--refresh Request a ConditionRefresh after subscribing to get current retained alarm states

EventFilter and alarm display

The command builds an EventFilter with select clauses for 12 fields from the OPC UA alarm type hierarchy:

Index Type Field
0 BaseEventType EventId
1 BaseEventType EventType
2 BaseEventType SourceName
3 BaseEventType Time
4 BaseEventType Message
5 BaseEventType Severity
6 ConditionType ConditionName
7 ConditionType Retain
8 AcknowledgeableConditionType AckedState/Id
9 AlarmConditionType ActiveState/Id
10 AlarmConditionType EnabledState/Id
11 AlarmConditionType SuppressedOrShelved

When an EventFieldList notification arrives, the handler extracts these fields by index and prints a structured alarm event to the console showing the source name, condition name, active/acknowledged state, severity, message, retain flag, and suppressed/shelved status.

The --refresh flag calls subscription.ConditionRefreshAsync() after the subscription is created, which asks the server to re-emit retained condition events so the operator sees the current alarm state immediately rather than waiting for the next transition.

redundancy

Reads the OPC UA redundancy state from a server: RedundancySupport, ServiceLevel, ServerUriArray, and ApplicationUri.

dotnet run -- redundancy -u opc.tcp://localhost:4840/LmxOpcUa

Example output:

Redundancy Mode:  Warm
Service Level:    200
Server URIs:
  - urn:localhost:LmxOpcUa:instance1
  - urn:localhost:LmxOpcUa:instance2
Application URI:  urn:localhost:LmxOpcUa:instance1
Flag Description
-u OPC UA server endpoint URL (required)
-S Transport security mode (default: none)
-U Username for authentication
-P Password for authentication