Task #249 — Driver test-client CLIs: shared lib + Modbus CLI first #203

Merged
dohertj2 merged 1 commits from task-249-driver-cli-common-modbus into v2 2026-04-21 08:17:22 -04:00
Owner

Mirrors the v1 otopcua-cli value prop (ad-hoc shell-level PLC validation) for the Modbus-TCP driver + lays down the shared scaffolding that AB CIP / AB Legacy / S7 / TwinCAT CLIs will inherit.

New projects

  • src/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/DriverCommandBase (verbose + Serilog) + SnapshotFormatter (single-tag / table / write-result renders).
  • src/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli/otopcua-modbus-cli exe. Commands: probe, read, write, subscribe.

Coverage

  • probe — single FC03 + health pretty-print.
  • read — region × address × type synthesised into one driver tag; supports all Modbus data types incl. Float32/String/BCD + byte-order flags.
  • write — same shape + --value parsed per --type (invariant culture).
  • subscribe — polled-subscription stream until Ctrl+C.

Tests (38 total)

  • 16 SnapshotFormatterTests (status shortnames, null/timestamp placeholders, bool lowercase, float invariant culture, table columns, UTC normalisation).
  • 22 Modbus CLI tests (tag-name synthesis 5 cases, value parser 17 cases).

Next

Repeat pattern for AB CIP → AB Legacy → S7 → TwinCAT. Shared base stays as-is unless one exposes a gap.

Mirrors the v1 `otopcua-cli` value prop (ad-hoc shell-level PLC validation) for the Modbus-TCP driver + lays down the shared scaffolding that AB CIP / AB Legacy / S7 / TwinCAT CLIs will inherit. ## New projects - `src/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/` — `DriverCommandBase` (verbose + Serilog) + `SnapshotFormatter` (single-tag / table / write-result renders). - `src/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli/` — `otopcua-modbus-cli` exe. Commands: `probe`, `read`, `write`, `subscribe`. ## Coverage - `probe` — single FC03 + health pretty-print. - `read` — region × address × type synthesised into one driver tag; supports all Modbus data types incl. Float32/String/BCD + byte-order flags. - `write` — same shape + `--value` parsed per `--type` (invariant culture). - `subscribe` — polled-subscription stream until Ctrl+C. ## Tests (38 total) - 16 SnapshotFormatterTests (status shortnames, null/timestamp placeholders, bool lowercase, float invariant culture, table columns, UTC normalisation). - 22 Modbus CLI tests (tag-name synthesis 5 cases, value parser 17 cases). ## Next Repeat pattern for AB CIP → AB Legacy → S7 → TwinCAT. Shared base stays as-is unless one exposes a gap.
dohertj2 added 1 commit 2026-04-21 08:17:10 -04:00
Mirrors the v1 otopcua-cli value prop (ad-hoc shell-level PLC validation) for
the Modbus-TCP driver, and lays down the shared scaffolding that AB CIP, AB
Legacy, S7, and TwinCAT CLIs will build on.

New projects:
  - src/ZB.MOM.WW.OtOpcUa.Driver.Cli.Common/ — DriverCommandBase (verbose
    flag + Serilog config) + SnapshotFormatter (single-tag + table +
    write-result renders with invariant-culture value formatting + OPC UA
    status-code shortnames + UTC-normalised timestamps).
  - src/ZB.MOM.WW.OtOpcUa.Driver.Modbus.Cli/ — otopcua-modbus-cli executable.
    Commands: probe, read, write, subscribe. ModbusCommandBase carries the
    host/port/unit-id flags + builds ModbusDriverOptions with Probe.Enabled
    =false (CLI runs are one-shot; driver-internal keep-alive would race).

Commands + coverage:
  - probe              single FC03 + GetHealth() + pretty-print
  - read               region × address × type synth into one driver tag
  - write              same shape + --value parsed per --type
  - subscribe          polled-subscription stream until Ctrl+C

Tests (38 total):
  - 16 SnapshotFormatterTests covering: status-code shortnames, unknown
    codes fall back to hex, null value + timestamp placeholders, bool
    lowercase, float invariant culture, string quoting, write-result shape,
    aligned table columns, mismatched-length rejection, UTC normalisation.
  - 22 Modbus CLI tests:
      · ReadCommandTests.SynthesiseTagName (5 theory cases)
      · WriteCommandParseValueTests (17 cases: bool aliases, unknown rejected,
        Int16 bounds, UInt16/Bcd16 type, Float32/64 invariant culture,
        String passthrough, BitInRegister, Int32 MinValue, non-numeric reject)

Wiring:
  - ZB.MOM.WW.OtOpcUa.slnx grew 4 entries (2 src + 2 tests).
  - docs/Driver.Modbus.Cli.md — operator-facing runbook with examples per
    command + output format + typical workflows.

Regression: full-solution build clean; shared-lib tests 16/0, Modbus CLI tests
22/0.

Next up: repeat the pattern for AB CIP (shares ~40% more with Modbus via
libplctag), then AB Legacy, S7, TwinCAT. The shared base stays as-is unless
one of those exposes a gap the Modbus-first pass missed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dohertj2 merged commit 9020b5854c into v2 2026-04-21 08:17:22 -04:00
dohertj2 referenced this issue from a commit 2026-04-30 08:21:26 -04:00
Doc refresh (task #206) — Client.CLI + Client.UI brand flip + new top-level docs/README.md index. Client.CLI.md: replaced stale LmxOpcUa-OPC UA-server references with OtOpcUa throughout the overview + sample output + applicationUri examples (opc.tcp://localhost:4840/OtOpcUa, urn:localhost:OtOpcUa:instanceN); confirmed against src/ZB.MOM.WW.OtOpcUa.Server/Program.cs:69-71 which sets the live endpoint url + application uri to those exact values. Added a driver-agnostic note in the overview — the CLI is reachable against every shipped driver surface because the OPC UA endpoint abstracts them all. Kept the `lmxopcua-cli` executable name + the `{LocalAppData}/LmxOpcUaClient/pki/` PKI folder name AS-IS because those are real filesystem-level residuals the code still uses (Program.cs SetExecutableName + OpcUaClientService.cs:428) — flipping them requires migration shims so existing dev boxes don't lose their trusted-cert store; added explicit doc text explaining the residual + why it persists so future readers aren't confused. Fixed the sample connect-output "Server: LmxOpcUa" to "Server: OtOpcUa Server" matching the live ApplicationName in OpcUaServerOptions.cs:39. Client.UI.md: replaced the 4 LmxOpcUa references — overview one-liner, status-bar mock (now reads "OtOpcUa Server" matching the server's reported ApplicationName), endpoint-url example, settings persistence path. Same residual-explanation note added under the LmxOpcUaClient/settings.json path pointing at the Client.Shared session-factory literal at OpcUaClientService.cs:428. docs/README.md is new — a top-level index distinguishing the two documentation tiers (current reference at docs/*.md vs implementation history + design notes at docs/v2/*.md). Every current-reference doc gets a one-line role description in a section table (Architecture + data-path / Drivers / Operational / Client tooling / Requirements) so a new reader picking up the repo finds their way in without having to grep file names. Cross-link calls out that load-bearing references from top-level docs (plan.md decisions, admin-ui.md, acl-design.md, config-db-schema.md, driver-specs.md, dev-environment.md, test-data-sources.md) live under v2/. Notes up front that the project was renamed LmxOpcUa → OtOpcUa and that any remaining LmxOpcUa-string in paths is a deliberate residual with a migration follow-up, so readers don't chase phantom bugs. Four parallel doc-refresh agents currently working on the rest of docs/*.md (task #202 core architecture, #203 driver docs split, #204 operational, #205 requirements) — those commits will land on separate worktree branches + get folded in together once complete; this index already lists the docs they'll produce (drivers/README.md, drivers/Galaxy.md, drivers/Galaxy-Repository.md) so the final merge just has the content showing up where the index already points.
Sign in to join this conversation.