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.