Files
wwtools/mxaccesscli/docs/usage.md
T
Joseph Doherty e9e37385aa mxaccesscli: document <arrayAttr>[] as the bulk-array read syntax
Empty square brackets — `<obj>.<arrayAttr>[]` — are the supported
MxAccess reference form for fetching a whole array as a single value.
Verified live:

  mxa read 'MESReceiver_001.MoveInPartNumbers[]' --llm-json
  -> ok=true, value=["", "11111", "", ..., "15", ...] (50 elements,
     quality=192, MxCategoryOk)

The bare reference without brackets continues to return
MxCategoryCommunicationError, Detail=1003 — that's a real proxy-side
rejection, not a CLI bug. Documented separately so the matrix shows
both the working syntax and the failing one.

docs/usage.md:
- Type matrix gains a "bulk array read via []" row () and a
  "bare reference" row (, kept for reference).
- "Reading arrays" section rewritten around the two reference
  shapes — `[]` for whole arrays, `[N]` for elements (1-based,
  N <= NumElements).
- Adds a "Discovering array length" note pointing at grdb's
  attributes.sql array_dimension column.

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

12 KiB
Raw Blame History

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.

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:

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:

{
  "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:

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:

[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 [ ... ]):

{"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 JSON array of element type Reference syntax <obj>.<arrayAttr>[]empty square brackets. Verified on MESReceiver_001.MoveInPartNumbers[] (String[50]) and MoveOutWorkOrderNumbers[]. Returns the entire array as a single value with MxCategoryOk.
Array (bare reference) The plain <obj>.<arrayAttr> (no brackets) returns MxCategoryCommunicationError, Detail=1003. Use [] instead.
Array element by index scalar of element type Reference syntax <obj>.<arrayAttr>[<n>]. 1-based, runs from [1] to [NumElements]. [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/ to find a deployed instance whose dynamic_attribute.mx_data_type matches and whose mx_attribute_category is in (2-11, 24) (Writeable_* 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 accepts two reference forms for arrays — pick by what you need:

Whole array — <obj>.<arrayAttr>[] (empty brackets)

mxa read 'MESReceiver_001.MoveInPartNumbers[]' --llm-json

Returns the full array as a single JSON value:

{
  "tag":   "MESReceiver_001.MoveInPartNumbers[]",
  "ok":    true,
  "value": ["", "11111", "", "", /* ... 50 elements total ... */],
  "quality": 192,
  "statuses": [{"Success":-1,"Category":"MxCategoryOk", ...}]
}

The array is fixed-length (sized at deploy time per the template's array_dimension). Empty string elements are unset slots, not gaps.

Single element — <obj>.<arrayAttr>[N]

mxa read 'MESReceiver_001.MoveInPartNumbers[2]' --llm-json

Indices are 1-based: [1] is the first element, [NumElements] is the last. [0] is invalid. Single-element reads are also writeable: mxa write '<obj>.<attr>[N]' <value>.

What does not work

mxa read 'MESReceiver_001.MoveInPartNumbers'   # bare ref, no brackets
# → MxCategoryCommunicationError, Detail=1003

The plain reference (no [], no [N]) is rejected by the proxy. Always include the brackets — empty for whole-array, indexed for element.

Discovering array length

The CLI doesn't (yet) auto-discover element count. Two ways to find it:

  1. Read with [] and count the returned values.
  2. Query the Galaxy Repository's ../../grdb/queries/attributes.sql — the array_dimension column reports the configured size from the template.

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.
  2. Find a deployed instance with a writeable UDA — ../../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).
  3. The reference for MxAccess is <InstanceName>.<AttributeName>.