Auto: abcip-4.3 — diagnostic / system tags as browseable variables
Closes #240
This commit is contained in:
@@ -297,3 +297,68 @@ the equality threshold too loose; revisit the per-tag config.
|
||||
- Modbus driver — read-side deadband in `ModbusDriver` predates this
|
||||
write-side equivalent; the config shape is intentionally similar.
|
||||
- Kepware "Deadband (write)" knob — this is the AB CIP equivalent.
|
||||
|
||||
## System tags / `_System` folder
|
||||
|
||||
PR abcip-4.3 surfaces five read-only diagnostic variables under
|
||||
`AbCip/<device>/_System/` so SCADA / Admin clients can pivot from "is the
|
||||
wire up?" to "what's our scan rate / tag count?" without leaving the OPC UA
|
||||
address space. The values come straight from the live
|
||||
`IHostConnectivityProbe` + `DriverHealth` surfaces — reads bypass libplctag
|
||||
and are served from the in-memory snapshot the probe loop / read loop
|
||||
updates.
|
||||
|
||||
### What it ships
|
||||
|
||||
| Variable | Type | Source | Notes |
|
||||
|---|---|---|---|
|
||||
| `_ConnectionStatus` | String | `HostState` | `Running` / `Stopped` / `Unknown` / `Faulted`. Mirrors what the connectivity probe sees. |
|
||||
| `_ScanRate` | Float64 | `AbCipProbeOptions.Interval` | Configured probe interval in milliseconds — compare against `_LastScanTimeMs` to spot wire stretch. |
|
||||
| `_TagCount` | Int32 | `_tagsByName` | Discovered tag count for this device, excluding `_System/*`. |
|
||||
| `_DeviceError` | String | `DriverHealth.LastError` | Most recent error message; empty when the device is healthy. |
|
||||
| `_LastScanTimeMs` | Float64 | `ReadAsync` wall-clock | Duration of the most-recent `ReadAsync` iteration on this device. |
|
||||
|
||||
### When the snapshot updates
|
||||
|
||||
- **Probe transitions** — every `Running ↔ Stopped` flip refreshes the
|
||||
device's snapshot inline, so a client subscribed to
|
||||
`_System/_ConnectionStatus` sees the new state on the next OPC UA
|
||||
publish tick.
|
||||
- **Read iterations** — `ReadAsync` recomputes `_LastScanTimeMs` per
|
||||
device that owned at least one reference in the batch + writes a fresh
|
||||
snapshot before returning.
|
||||
- **Driver init** — every device gets a seeded snapshot
|
||||
(`Unknown` / `0` / `""`) before the probe loop spins up so a read that
|
||||
arrives before the first probe iteration returns a stable shape rather
|
||||
than null.
|
||||
|
||||
### Browse + read example
|
||||
|
||||
```powershell
|
||||
# Browse the synthetic folder
|
||||
otopcua-client-cli browse -u opc.tcp://localhost:4840 \
|
||||
-n "ns=2;s=AbCip/ab://10.0.0.5/1,0/_System"
|
||||
|
||||
# Read the connection status
|
||||
otopcua-client-cli read -u opc.tcp://localhost:4840 \
|
||||
-n "ns=2;s=AbCip/ab://10.0.0.5/1,0/_System/_ConnectionStatus"
|
||||
```
|
||||
|
||||
The driver-side reference embeds the device host address (the
|
||||
`_System/<device>/<name>` form) so the dispatcher can route by device
|
||||
without an additional registry. PR abcip-4.4 will turn `_RefreshTagDb` into
|
||||
a writeable refresh trigger; everything 4.3 ships is `ViewOnly`.
|
||||
|
||||
### Verification
|
||||
|
||||
- **Unit**: `AbCipSystemTagSourceTests`
|
||||
(`tests/.../AbCip.Tests`) — covers snapshot round-trip, two-device
|
||||
isolation, recognised-name lookup, default-shape on unseeded devices,
|
||||
discovery emits the five canonical nodes, and `ReadAsync` dispatches
|
||||
through the source instead of libplctag.
|
||||
- **Integration**: `AbCipSystemTagDiscoveryTests`
|
||||
(`tests/.../AbCip.IntegrationTests`) — `[AbServerFact]` connects to a
|
||||
real `ab_server`, browses `_System/`, reads each variable, asserts
|
||||
every one returns Good with a non-null value.
|
||||
- **E2E**: `scripts/e2e/test-abcip.ps1` — see the *SystemTagBrowse*
|
||||
assertion.
|
||||
|
||||
@@ -146,7 +146,14 @@ No smoke test for:
|
||||
atomic-write coverage end-to-end is still unit-only.
|
||||
- `ITagDiscovery.DiscoverAsync` (`@tags` walker)
|
||||
- `ISubscribable.SubscribeAsync` (poll-group engine)
|
||||
- `IHostConnectivityProbe` state transitions under wire failure
|
||||
- ~~`IHostConnectivityProbe` state transitions under wire failure~~ —
|
||||
covered as of PR abcip-4.3. `AbCipSystemTagDiscoveryTests` connects to
|
||||
`ab_server`, drives the discovery + read path against the synthetic
|
||||
`_System/_ConnectionStatus` variable, and asserts the live snapshot
|
||||
reflects the probe-driven `HostState`. Wire-failure transitions still
|
||||
rely on unit-level `ThrowOnRead` injection rather than a real wire pull,
|
||||
but the end-to-end probe → snapshot → OPC UA address-space link is
|
||||
exercised against `ab_server`.
|
||||
- `IPerCallHostResolver` multi-device routing
|
||||
|
||||
The driver implements all of these + they have unit coverage, but the only
|
||||
|
||||
Reference in New Issue
Block a user