# Client CLI ## Overview `ZB.MOM.WW.OtOpcUa.Client.CLI` is a cross-platform command-line client for the OtOpcUa OPC UA server. It targets .NET 10 and uses the shared `IOpcUaClientService` from `Client.Shared` for all OPC UA operations. Commands are routed and parsed by [CliFx](https://github.com/Tyrrrz/CliFx). The CLI is the primary tool for operators and developers to test and interact with the server from a terminal. It supports all core operations: connectivity testing, browsing, reading, writing, subscriptions, alarm monitoring, history reads, and redundancy queries. Any driver surface exposed by the server (Galaxy, Modbus, S7, AB CIP, AB Legacy, TwinCAT, FOCAS, OPC UA Client) is reachable through these commands — the CLI is driver-agnostic because everything below the OPC UA endpoint is. ## Build and Run ```bash cd src/ZB.MOM.WW.OtOpcUa.Client.CLI dotnet build dotnet run -- [options] ``` The executable name is still `lmxopcua-cli` — a residual from the pre-v2 rename (`Program.cs:SetExecutableName`). Scripts + operator muscle memory depend on the name; flipping it to `otopcua-cli` is a follow-up that also needs to move the client-side PKI store folder ({LocalAppData}/LmxOpcUaClient/pki/ — used by the shared client for its application certificate) so trust relationships survive the rename. ## Architecture All commands inherit from `CommandBase`, which provides common connection options and helper methods. Every command follows the same lifecycle: 1. Build `ConnectionSettings` from common options 2. Create an `IOpcUaClientService` through the factory 3. Call `ConnectAsync` to establish a session 4. Perform the command-specific operation 5. Call `DisconnectAsync` in a `finally` block No command accesses the OPC UA `Session` directly; all operations go through the shared service abstraction. This ensures consistent behavior with the desktop UI client. ## Common Options All commands accept these options: | Flag | Description | |------|-------------| | `-u` / `--url` | OPC UA server endpoint URL (required) | | `-U` / `--username` | Username for `UserName` token authentication | | `-P` / `--password` | Password for `UserName` token authentication | | `-S` / `--security` | Transport security mode: `none`, `sign`, `encrypt`, `signandencrypt` (default: `none`) | | `-F` / `--failover-urls` | Comma-separated failover endpoint URLs for redundancy | | `--verbose` | Enable debug-level Serilog console logging (default: warning) | ### Authentication When `-U` and `-P` are provided, the shared service passes a `UserIdentity(username, password)` to the OPC UA session. Without credentials, anonymous identity is used. ```bash lmxopcua-cli write -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -v 42 -U operator -P op123 ``` ### Failover When `-F` is provided, the shared service tries the primary URL first, then each failover URL in order. For long-running commands (`subscribe`, `alarms`), the service monitors the session via keep-alive and automatically reconnects to the next available server on failure. ```bash lmxopcua-cli connect -u opc.tcp://localhost:4840/OtOpcUa -F opc.tcp://localhost:4841/OtOpcUa ``` ### Transport Security When `sign` or `encrypt` is specified, the shared service: 1. Ensures a client application certificate exists under `{LocalAppData}/LmxOpcUaClient/pki/` (auto-created if missing) 2. Discovers server endpoints and selects one matching the requested security mode 3. Prefers `Basic256Sha256` when multiple matching endpoints exist 4. Fails with a clear error if no matching endpoint is found ```bash lmxopcua-cli browse -u opc.tcp://localhost:4840/OtOpcUa -S encrypt -U admin -P secret -r -d 2 ``` ### Verbose Logging The `--verbose` flag switches Serilog output from `Warning` to `Debug` level, showing internal connection lifecycle, endpoint discovery, and OPC UA SDK diagnostics on the console. ## Commands ### connect Tests connectivity to an OPC UA server. Creates a session, prints connection metadata, and disconnects. ```bash lmxopcua-cli connect -u opc.tcp://localhost:4840/OtOpcUa -U admin -P admin123 ``` Output: ```text Connected to: opc.tcp://localhost:4840/OtOpcUa Server: OtOpcUa Server Security Mode: None Security Policy: http://opcfoundation.org/UA/SecurityPolicy#None Connection successful. ``` ### read Reads the current value of a single node and prints the value, status code, and timestamps. ```bash lmxopcua-cli read -u opc.tcp://localhost:4840/OtOpcUa -n "ns=3;s=DEV.ScanState" -U admin -P admin123 ``` | Flag | Description | |------|-------------| | `-n` / `--node` | Node ID to read (required) | Output: ```text Node: ns=3;s=DEV.ScanState Value: True Status: 0x00000000 Source Time: 2026-03-30T19:58:38.0961252Z Server Time: 2026-03-30T19:58:38.0971257Z ``` ### write Writes a value to a node. The shared service reads the current value first to determine the target data type, then converts the supplied string value using `ValueConverter.ConvertValue()`. ```bash lmxopcua-cli write -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -v 42 ``` | Flag | Description | |------|-------------| | `-n` / `--node` | Node ID to write to (required) | | `-v` / `--value` | Value to write (required) | ### browse Browses the OPC UA address space starting from the Objects folder or a specified node. Supports recursive traversal with a configurable depth limit. Output uses tree-style indentation with `[Object]`, `[Variable]`, and `[Method]` markers. ```bash # Browse top-level Objects folder lmxopcua-cli browse -u opc.tcp://localhost:4840/OtOpcUa -U admin -P admin123 # Browse a specific node recursively to depth 3 lmxopcua-cli browse -u opc.tcp://localhost:4840/OtOpcUa -U admin -P admin123 -r -d 3 -n "ns=3;s=ZB" ``` | Flag | Description | |------|-------------| | `-n` / `--node` | Node ID to browse (default: Objects folder) | | `-d` / `--depth` | Maximum browse depth (default: 1) | | `-r` / `--recursive` | Browse recursively using `-d` as max depth | ### subscribe Monitors a node for value changes using OPC UA subscriptions. Prints each data change notification with timestamp, value, and status code. Runs until Ctrl+C, then unsubscribes and disconnects cleanly. ```bash lmxopcua-cli subscribe -u opc.tcp://localhost:4840 -n "ns=2;s=MyNode" -i 500 ``` | Flag | Description | |------|-------------| | `-n` / `--node` | Node ID to monitor (required) | | `-i` / `--interval` | Sampling/publishing interval in milliseconds (default: 1000) | ### historyread Reads historical data from a node. Supports raw history reads and aggregate (processed) history reads. ```bash # Raw history lmxopcua-cli historyread -u opc.tcp://localhost:4840/OtOpcUa \ -n "ns=1;s=TestMachine_001.TestHistoryValue" \ --start "2026-03-25" --end "2026-03-30" # Aggregate: 1-hour average lmxopcua-cli historyread -u opc.tcp://localhost:4840/OtOpcUa \ -n "ns=1;s=TestMachine_001.TestHistoryValue" \ --start "2026-03-25" --end "2026-03-30" \ --aggregate Average --interval 3600000 ``` | Flag | Description | |------|-------------| | `-n` / `--node` | 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) | #### Aggregate mapping | Name | OPC UA Node ID | |------|---------------| | `Average` | `AggregateFunction_Average` | | `Minimum` | `AggregateFunction_Minimum` | | `Maximum` | `AggregateFunction_Maximum` | | `Count` | `AggregateFunction_Count` | | `Start` | `AggregateFunction_Start` | | `End` | `AggregateFunction_End` | ### alarms Subscribes to alarm events on a node. Prints structured alarm output including source, condition, severity, active/acknowledged state, and message. Runs until Ctrl+C, then unsubscribes and disconnects cleanly. ```bash # Subscribe to alarm events on the Server node lmxopcua-cli alarms -u opc.tcp://localhost:4840/OtOpcUa # Subscribe to a specific source node with condition refresh lmxopcua-cli alarms -u opc.tcp://localhost:4840/OtOpcUa \ -n "ns=1;s=TestMachine_001" --refresh ``` | Flag | Description | |------|-------------| | `-n` / `--node` | Node ID to monitor for events (default: Server node) | | `-i` / `--interval` | Publishing interval in milliseconds (default: 1000) | | `--refresh` | Request a `ConditionRefresh` after subscribing to get current retained alarm states | ### redundancy Reads the OPC UA redundancy state from a server: redundancy mode, service level, server URIs, and application URI. ```bash lmxopcua-cli redundancy -u opc.tcp://localhost:4840/OtOpcUa -U admin -P admin123 ``` Example output: ```text Redundancy Mode: Warm Service Level: 200 Server URIs: - urn:localhost:OtOpcUa:instance1 - urn:localhost:OtOpcUa:instance2 Application URI: urn:localhost:OtOpcUa:instance1 ``` ## Testing The Client CLI has 52 unit tests covering option parsing, service invocation, output formatting, and cleanup behavior: ```bash dotnet test tests/ZB.MOM.WW.OtOpcUa.Client.CLI.Tests ```