Tutorials¶
The tutorials walk through the client-side features of o6 against a single, fixed example server that runs against a background simulation. Every snippet on every page assumes you can reach that server at opc.tcp://localhost:4840 and that its address space looks like the layout described in the following section.
The tutorials build on each other — each page introduces one concept at a time and reuses the same server, so by the end you have walked through the full lifecycle: connecting, reading values, calling methods, subscribing to live data, reacting to state changes, and so on.
The example server¶
Every tutorial on this site talks to the same example server: a small automated still.
Driven by a simulation in the background¶
The server runs a simulation in the background: Wash goes in, gets heated to a setpoint, vapour turns into spirit on the way through the condenser, the spent wash drains out, and the still goes back to idle and waits for the next batch. Rinse, repeat.
Running the example server¶
The fastest way to get going is the standalone distilling binary, which
bundles the server and simulation into one executable. Public o6\Python wheels
are distributed through the o6 project on PyPI.
Once the binary is on your machine, start it with the simulation enabled:
That's the default case: the server listens on opc.tcp://localhost:4840. You can adjust the simulation speed with another parameter:
Info
--port lets you pick a different port for the server, however the tutorials all assume 4840, so make sure to update the endpointUrl if you pick a different port.
Address space layout¶
The server exposes the following nodes under Objects/ (alongside the standard Server object that open62541 adds automatically).
Objects/
└── DistillingSystem (Object, ns=1;i=1000)
├── Identification (Object, ns=1;i=1100)
│ ├── Name (String, read-only) (ns=1;i=1101)
│ ├── Manufacturer (String, read-only) (ns=1;i=1102)
│ └── ModelNumber (String, read-only) (ns=1;i=1103)
├── Status (Object, ns=1;i=1200)
│ ├── State (String, read-only) (ns=1;i=1201)
│ ├── Cycle (Int32, read-only) (ns=1;i=1202)
│ ├── Operating (Boolean, writable) (ns=1;i=1203)
│ └── Setpoint (Double °C, writable) (ns=1;i=1204)
├── Kettle (Object, ns=1;i=1300)
│ ├── Level (Double %, read-only) (ns=1;i=1301)
│ ├── Temperature (Double °C, read-only) (ns=1;i=1302)
│ └── WashStart (Double %, read-only) (ns=1;i=1303)
├── Distillate (Object, ns=1;i=1400)
│ └── Level (Double %, read-only) (ns=1;i=1401)
├── Actuators (Object, ns=1;i=1500)
│ ├── FillValve (Boolean, read-only) (ns=1;i=1501)
│ ├── DrainValve (Boolean, read-only) (ns=1;i=1502)
│ └── Heater (Boolean, read-only) (ns=1;i=1503)
├── Events (Object, ns=1;i=1600)
│ ├── EventCount (Int32, read-only) (ns=1;i=1601)
│ ├── LastEventTime (DateTime, read-only) (ns=1;i=1602)
│ ├── LastEventMessage(String, read-only) (ns=1;i=1603)
│ └── LastEventState (String, read-only) (ns=1;i=1604)
├── Start (Method) (ns=1;i=2001)
└── Shutdown (Method) (ns=1;i=2002)
A few things worth knowing before you start poking:
- Mostly read-only. Almost everything in the address space is read-only from a client's perspective. The only two variables you can write are
Status/OperatingandStatus/Setpoint, and as described above those feed back into the sim rather than directly controlling hardware. The actuators (FillValve,DrainValve,Heater) look tempting — they sound like switches — but they are not writable: the sim drives them itself as part of the batch state machine. If a tutorial tells you to writeSetpoint, it means it; if it tells you to writeHeater, it's lying and you should open an issue. - Methods.
Startkicks off a new batch (no-op if one is already running) andShutdownaborts the current batch and puts the still back to idle. Use them as the on/off buttons. - Events. The
o6high-level Server API does not currently exposeUA_Server_createEventat the Python level, so the server fakes events with a small "writable event log" pattern: every state transition appends an entry to theEventssub-object, and clients subscribe toEventCount/LastEventMessageto react to the change. From a client point of view you treat these exactly like any other monitored variables — the subscriptions and event-listening tutorials show how. Wheno6grows a real event API, the server will swap to properBaseEventTypenotifications behind the scenes and existing client code will keep working.
Topics¶
The tutorials are organized around what you typically do with a client: