Files
wwtools/mxaccesscli/docs/usage.md
T
Joseph Doherty ab202a1fa1 mxaccesscli: read/write/subscribe System Platform tags via MxAccess
New tool wrapping ArchestrA.MxAccess.LMXProxyServerClass (the same COM
proxy aaObjectViewer / WindowViewer use) as a CliFx CLI for LLM-driven
debugging.

Commands:
- mxa info      — loaded MxAccess assembly identity, supported value
                   types, MxStatusCategory enum.
- mxa read      — fetch one or more tag values; subscribes briefly,
                   captures first OnDataChange per tag, tears down.
- mxa write     — write a value with optional --type coercion; advises
                   first to resolve the attribute type, then waits for
                   OnWriteComplete with a per-call timeout.
- mxa subscribe — stream OnDataChange events for --seconds; JSON Lines
                   under --llm-json for piped agent consumption.
- mxa diag      — minimal smoke test on a private STA thread; bypasses
                   the CliFx pipeline for diagnosing apartment / pump
                   issues.

Implementation notes documented in docs/api-notes.md (reverse-engineered
because AVEVA does not publish a single canonical MxAccess reference):

- Net48 / x86 / [STAThread] are non-negotiable. The CLI runs the entire
  CliFx pipeline on a dedicated STA thread.
- COM events are dispatched as Win32 messages; AutoResetEvent.WaitOne
  alone does not pump them on this configuration. MxSession.WaitForUpdate
  loops Application.DoEvents() + drain + Sleep(20ms) instead.
- Write requires the target attribute's type to be resolved first.
  WriteCommand advises and waits for the initial OnDataChange before
  calling LMXProxyServerClass.Write to avoid ArgumentException
  "Value does not fall within the expected range".
- Errors carry the full MXSTATUS_PROXY[] from MxAccess (Success,
  Category, DetectedBy, Detail) so an agent can tell exactly which
  layer rejected a request.

Verified against the live ZB galaxy with a writeable tag identified
via grdb (TestChildObject.TestInt, mx_attribute_category=10):
  read:      99 (q=192, MxCategoryOk)
  write 7:   round-tripped — read returned 7 — written back to 99
  write str: TestChildObject.TestString round-tripped a timestamp
  subscribe: captured initial value plus subsequent change from a
             separate process

The vendored ArchestrA.MxAccess.dll is gitignored — it is copied from
C:\Program Files (x86)\ArchestrA\Framework\Bin\ on any System Platform
install per the README.

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

7.3 KiB

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.

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.

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>.