Learn · Protocols · 03 of 03

OPC UA: one address space for everything

Matter bulbs, Modbus meters and microcontroller sensor nodes have nothing in common on the wire. In the controller they share one address space, one set of status codes and one way of being read. That is what OPC UA is for.

OPC UA is the industrial standard for describing and reading equipment. Unlike Modbus it carries meaning as well as bits: a server publishes a browsable tree of objects and variables, each with a name, a data type, a value, a timestamp and a status code. A client, whether a SCADA system, an HMI panel or a browser tab, can walk the tree without a manual, read what it finds and subscribe to changes.

Capabilities become variables

The controller runs an OPC UA server and publishes into it everything the capability layer knows. Each device is an object; each of its capabilities is a variable under it. A Matter plug contributes a boolean Switch. A Modbus meter contributes PowerMetering as a double. A sensor node contributes temperature, humidity and air quality. The controller itself appears too, with CPU temperature, load, memory and uptime, because a controller that cannot report on itself is not much of a controller.

Objects/
  Opichy/
    Controller/         CPUTemperature  CPUUsage  MemoryUsage  Uptime
    Kitchen/
      matter-7-1/       Switch                      (measured)
      sensor-node-2/    Temperature  Humidity  AQI  (measured)
    Plant room/
      meter-1/          PowerMetering               (measured)
      pump-1/           Switch                      (commanded)

Status codes that mean something

OPC UA's status codes are the reason it fits the capability model so well. The model already decides how much to trust a value from how it was obtained and how old it is. Those decisions map directly onto standard codes every industrial client understands:

Situation OPC UA status
Measured value, fresher than its capability's max_age_s Good
Measured value, but older than max_age_s UncertainLastUsableValue
Commanded state with no independent read‑back UncertainSubstituteValue
No value ever received from the device UncertainNoCommunicationLastUsableValue

An HMI that colours uncertain values grey does the right thing with no configuration. The same rules live in the Rust core, so the browser demo on the capability model section of the homepage and the controller's server cannot disagree about what "good" means.

The codec is Rust, and it runs in the browser

The OPC UA client the ecosystem uses is written in Rust and compiled to WebAssembly. The same module that parses a Hello / Acknowledge exchange, opens a secure channel, creates a session and browses a tree runs unchanged in a Cloudflare Worker, where the Worker owns the socket and the module owns the bytes, and in a web page. One implementation, tested once, wherever a client is needed.

HEL → ACK                  hello, buffer sizes negotiated
OPN → OPN                  secure channel opened
CreateSession / Activate   session bound to the channel
Browse / Read              walk the tree, read values + status + timestamp
CreateSubscription         server pushes changes; nothing polls the device

Where the endpoint lives

An OPC UA endpoint is a control surface as well as a read surface, so it stays on the controller's private network. Reaching it from outside means joining that network over Tailscale, as described on the Security page, not exposing port 4840 to the internet. The live prototype panel on this site does not touch the endpoint at all: it reads a filtered, read‑only summary that the controller publishes on purpose. Everything a SCADA system needs is available inside the boundary; nothing that can move a machine is available outside it.