Files
wwtools/mxaccesscli/docs/usage.md
T
Joseph Doherty cc1ce05f96 mxaccesscli: document type/array support matrix from live verification
Adds a 'Type support matrix' table to docs/usage.md capturing what was
verified against the live ZB galaxy on System Platform 2017 Express
with MxAccess 3.2.0.0:

Verified read + write (round-tripped):
- MxBoolean   — DelmiaReceiver_001.TestAttribute (false→true→false)
- MxInteger   — MESReceiver_001.MoveInBatchID    (999→12345→0→999)
- MxString    — MESReceiver_001.MoveOutErrorText (round-trip + restore)
- String array element via 1-based [N] indexing
                — MESReceiver_001.MoveInPartNumbers[2] (11111→ARR-WRITE-OK→11111)

Verified read only (no writeable instance in this galaxy):
- MxFloat       — DevPlatform.CPULoad{,Avg,Max,Min}, PageFaultsAvg
- MxTime        — DevPlatform.SystemStartupTime → ISO-8601 string
- MxReferenceType — Container/Host/Area → target object's Tagname

Wired but no live instance found (matrix marked ''):
- MxDouble, MxElapsedTime, MxQualifiedEnum, MxInternationalizedString,
  MxBigString. Adding a writeable UDA of any of these types should
  exercise the existing code path without further changes.

Hard limitation surfaced and documented:
- MxAccess.AddItem('<obj>.<arrayAttr>') for bulk array read returns
  MxCategoryCommunicationError, Detail=1003. Read array elements
  individually via the 1-based '[N]' suffix; '[0]' is invalid.

Adds a 'Reading arrays' section pointing at grdb's attributes.sql
('array_dimension' column) for discovering element count.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 20:33:07 -04:00

183 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# mxa — usage
Read, write, and subscribe to AVEVA System Platform tags via MxAccess. The CLI runs in-process: each invocation registers an `LMXProxyServer`, executes, and unregisters cleanly. Errors carry the underlying `MxStatusCategory` so an agent can decide whether the failure is transient (Pending), configurational, or operational.
## Common notes
- **Tag references** are full attribute paths: `<ObjectName>.<AttributeName>` (e.g. `TestMachine_001.Speed`). For `Galaxy:` references, follow the convention used in InTouch / Object Viewer.
- **`--client <name>`** sets the client name passed to MxAccess `Register()`. Defaults to `mxa`. Most install logs key on this string.
- **Timeouts are per-call.** They control how long the CLI waits for a `OnDataChange` (read) or `OnWriteComplete` (write). The default is 5 seconds.
- **First-event latency.** LMX has to resolve the reference and bind to the hosting engine on each fresh client connection. Empirically the first `OnDataChange` arrives **3-8 seconds** after `Advise()`. Set timeouts and `subscribe --seconds` accordingly: a 3-second `read` may legitimately time out on first contact, then succeed on the next try because LMX has cached the binding.
- **Subsequent events are fast.** Once a tag is bound, value-change updates propagate within ~100 ms.
- **Exit codes:** `0` on success, `1` if any operation timed out or returned a non-Ok / non-Pending `MxStatusCategory`, `2` on argument-validation errors.
## `mxa info`
Print the loaded `ArchestrA.MxAccess` assembly identity, supported `--type` values, and the full `MxStatusCategory` enum. No tag access.
```powershell
mxa info
```
## `mxa read <tag> [<tag>...]`
Reads one or more tags by briefly subscribing and capturing the first `OnDataChange` per tag.
| Option | Default | Notes |
| --- | --- | --- |
| `-t`, `--timeout <seconds>` | `5` | Per-tag timeout. Tags that don't deliver a `DataChange` within the window are reported with `error: timeout`. |
| `--client <name>` | `mxa` | Passed to `Register()`. |
| `--llm-json` | off | Emit the JSON envelope. |
Examples:
```powershell
mxa read TestMachine_001.Speed
mxa read TestMachine_001.Speed Reactor1.Level -t 3
mxa read TestMachine_001.Speed Reactor1.Level --llm-json
```
LLM-JSON envelope:
```json
{
"query": { "command": "read", "tags": ["TestMachine_001.Speed"], "timeout_s": 5.0, "client": "mxa" },
"ok": true,
"results": [
{
"tag": "TestMachine_001.Speed",
"ok": true,
"value": 1234.5,
"quality": 192,
"timestamp": "2026-05-03T19:42:18.001",
"statuses": [
{ "Success": 0, "Category": "MxCategoryOk", "DetectedBy": "MxSourceRespondingAutomationObject", "Detail": 0 }
]
}
]
}
```
## `mxa write <tag> <value>`
Writes one value to one tag and waits for `OnWriteComplete`.
| Option | Default | Notes |
| --- | --- | --- |
| `--type <kind>` | inferred | Force the .NET type used for the boxed value. One of `bool`, `byte`, `short`, `int`, `long`, `float`, `double`, `string`, `datetime`. |
| `-t`, `--timeout <seconds>` | `5` | How long to wait for `OnWriteComplete`. |
| `--user-id <int>` | `0` | Authenticated user id. `0` is unauthenticated; secured attributes will reject. |
| `--client <name>` | `mxa` | Passed to `Register()`. |
| `--llm-json` | off | Emit the JSON envelope. |
Type inference rules (when `--type` is not set): `true`/`false`/`yes`/`no`/`on`/`off`/`1`/`0` → bool; pure integer → `int` (then `long`); decimals → `double`; everything else → `string`.
Examples:
```powershell
mxa write TestMachine_001.Setpoint 42.5 --type double
mxa write TestMachine_001.RunFlag true
mxa write TestMachine_001.Label "Hello world"
mxa write Reactor1.Setpoint 100 --type int -t 10 --llm-json
```
The same JSON envelope shape as `read`, with `results[0]` containing `{ tag, ok, error?, statuses }`. No `value`/`quality`/`timestamp` on the write result — consult a follow-up `mxa read` to confirm.
## `mxa subscribe <tag> [<tag>...]`
Streams `OnDataChange` events for a duration.
| Option | Default | Notes |
| --- | --- | --- |
| `-s`, `--seconds <seconds>` | `10` | Wall-clock duration of the subscription. |
| `--max <int>` | `1000` | Hard cap on emitted events. |
| `--client <name>` | `mxa` | Passed to `Register()`. |
| `--llm-json` | off | **JSON Lines** mode — one JSON object per line, no outer envelope. |
Human output:
```text
[INFO] Subscribed to 1 tag(s). Streaming for 30.0s. Ctrl-C to stop early.
[19:42:18.001] [OK ] TestMachine_001.Speed = 1234.5 (q=192)
[19:42:19.002] [OK ] TestMachine_001.Speed = 1245.7 (q=192)
...
[INFO] 30 event(s) emitted; subscription closed.
```
LLM-JSON output (one event per line, no surrounding `[ ... ]`):
```jsonl
{"tag":"TestMachine_001.Speed","ok":true,"value":1234.5,"quality":192,"timestamp":"2026-05-03T19:42:18.001","statuses":[{...}]}
{"tag":"TestMachine_001.Speed","ok":true,"value":1245.7,"quality":192,"timestamp":"2026-05-03T19:42:19.002","statuses":[{...}]}
```
JSON Lines lets a downstream consumer parse events incrementally rather than buffering the whole stream — the right shape for indefinite or long-running subscriptions.
## Type support matrix
Verified end-to-end against the live `ZB` galaxy (System Platform 2017 Express, MxAccess `3.2.0.0`). Each row records what the wire shape looks like in the JSON envelope.
| `MxDataType` | Read | Write | JSON shape | Notes |
| --- | :---: | :---: | --- | --- |
| `MxBoolean` | ✅ | ✅ | JSON `true` / `false` | `--type bool` accepts `true`/`false`/`1`/`0`/`yes`/`no`/`on`/`off`. |
| `MxInteger` (Int32) | ✅ | ✅ | JSON number | `--type int`. Up-cast to `long` if it overflows `int.MaxValue`. |
| `MxFloat` (single) | ✅ | ⚠️ | JSON number | Read verified on `DevPlatform.CPULoad` family. Write requires a writeable Float UDA — none in the test galaxy, but `--type float` is wired. |
| `MxDouble` | ❓ | ❓ | JSON number | No accessible Double instance in the test galaxy. Wiring is identical to Float; expected to work. |
| `MxString` | ✅ | ✅ | JSON string | Default inferred type for non-numeric values. |
| `MxTime` (DateTime) | ✅ | ⚠️ | JSON string `"YYYY-MM-DDTHH:mm:ss"` | Read verified on `DevPlatform.SystemStartupTime`. Write via `--type datetime` accepts ISO-8601. |
| `MxElapsedTime` | ❓ | ❓ | JSON number (seconds) | No accessible instance in the test galaxy. |
| `MxReferenceType` | ✅ | | JSON string (target object's `Tagname`) | E.g. `TestChildObject.Container``"DevTestObject"`. Writing references is not exposed by the CLI. |
| `MxQualifiedEnum` (13) | ❓ | | (likely string) | No accessible instance. |
| `MxQualifiedStruct` (14) | | | | Access via dotted member names: `<obj>.<struct>.<field>`. |
| `MxInternationalizedString` (15) | ❓ | ❓ | (likely string) | No accessible instance. |
| `MxBigString` (16) | ❓ | ❓ | JSON string | No accessible instance. |
| **Array (any type), bulk read** | ❌ | | — | `MxAccess.AddItem(<arrayRef>)``MxCategoryCommunicationError, Detail=1003`. Bulk array reads are not supported by this LMX client API. |
| **Array element by index** | ✅ | ✅ | scalar of element type | Reference syntax `<obj>.<arrayAttr>[<n>]`. **1-based** indexing. Verified on `MESReceiver_001.MoveInPartNumbers[2]` (String[]). `[0]` is invalid. |
Legend: ✅ verified live, ⚠️ wiring present but no live instance to write, ❓ wiring present but no live instance found, ❌ not supported by MxAccess at this layer, not applicable.
To test write support for a type, use [`../../grdb/`](../../grdb/) to find a deployed instance whose `dynamic_attribute.mx_data_type` matches and whose `mx_attribute_category` is in `(2-11, 24)` ([Writeable_*](../../aot/dev-guide/appendix-f-attribute-categories.md) family).
## Errors and statuses
Every `result` carries a `statuses` array — the elements of the COM `MXSTATUS_PROXY[]` MxAccess passes back. Field names match the C# struct exactly:
| Field | Type | Meaning |
| --- | --- | --- |
| `Success` | int16 | 0 = Ok, non-zero = error code |
| `Category` | enum | `MxCategoryOk`, `MxCategoryPending`, `MxCategoryWarning`, `MxCategoryCommunicationError`, `MxCategoryConfigurationError`, `MxCategoryOperationalError`, `MxCategorySecurityError`, `MxCategorySoftwareError`, `MxCategoryOtherError`, `MxStatusCategoryUnknown` |
| `DetectedBy` | enum | `MxSourceRequestingLmx`, `MxSourceRespondingLmx`, `MxSourceRequestingNmx`, `MxSourceRespondingNmx`, `MxSourceRequestingAutomationObject`, `MxSourceRespondingAutomationObject`, `MxSourceUnknown` |
| `Detail` | int16 | Additional error-code detail |
A result is considered `ok` only if every `statuses` element has `Category in (MxCategoryOk, MxCategoryPending)`.
Common failure shapes:
- **`Category: MxCategoryConfigurationError`** — usually a typo'd reference or the attribute doesn't exist on the deployed instance. Sanity-check via `graccesscli object snapshot`.
- **`Category: MxCategoryCommunicationError`** — engine isn't running, object is OffScan, or LMX can't reach the platform hosting the object.
- **`Category: MxCategorySecurityError`** — secured attribute, `--user-id 0`. Use `WriteSecured` semantics (not yet exposed by this CLI) or target a `Writeable_USC_*` attribute.
- **Timeout** — most likely the tag is genuinely silent (no value updates) or the reference is wrong. With `--llm-json` you'll see `"error": "timeout"` and an empty `statuses`.
## Reading arrays
MxAccess does not return array attributes as a single rowset. Bulk `AddItem("<obj>.<arrayAttr>")` returns `MxCategoryCommunicationError, Detail=1003`. Read elements individually:
```powershell
mxa read 'MESReceiver_001.MoveInPartNumbers[1]' \
'MESReceiver_001.MoveInPartNumbers[2]' \
'MESReceiver_001.MoveInPartNumbers[3]' \
--llm-json
```
- Array indices are **1-based** (`[1]`, `[2]`, …). `[0]` is invalid and returns a configuration error.
- The CLI does not (yet) auto-discover the array length; combine with [`../../grdb/queries/attributes.sql`](../../grdb/queries/attributes.sql) (`array_dimension` column) to know how many elements to fetch.
- Writing an element uses the same indexed reference: `mxa write '<obj>.<attr>[N]' <value>`.
## Picking a tag for a smoke test
If the live galaxy is not familiar:
1. Connect to the Galaxy Repository SQL — see [`../../grdb/connectioninfo.md`](../../grdb/connectioninfo.md).
2. Find a deployed instance with a writeable UDA — [`../../grdb/queries/attributes.sql`](../../grdb/queries/attributes.sql) lists user-defined attributes with their data type. Filter on a `Writeable_*` security classification (see [`../../aot/dev-guide/appendix-e-security-classifications.md`](../../aot/dev-guide/appendix-e-security-classifications.md)).
3. The reference for MxAccess is `<InstanceName>.<AttributeName>`.