OPC UA in five minutes
Enough OPC UA to read the rest of these docs. If you already model OPC UA, skip to the mapping table — it is the part you actually want.
The address space
An OPC UA server exposes an address space: a graph of nodes connected by references. A client browses that graph the way you browse a filesystem, except the edges are typed and carry meaning.
Each node has a NodeId (unique, machine-facing) and a BrowseName (stable, human-facing). Clients are written against BrowseNames, not NodeIds — that is what lets one client work against two vendors' servers.
Types and instances
This is the part that matters most, and the part people coming from tag-based systems find unfamiliar.
Every Object and Variable in the address space points at a TypeDefinition
that describes its shape. A TemperatureSensorType declares that instances have
a Temperature variable; every instance then has one, with the same BrowseName.
So a client that understands the type understands every instance of it, from any vendor. That is the whole value proposition of OPC UA information modelling, and it is why companion specifications exist: agree the types once, and tooling written against them works everywhere.
Types can be subtyped. A subtype may add members; a client expecting the
parent type can still consume the child. This is why our diagnostics push you
toward subtyping a companion-spec type rather than declaring a fresh one —
di:ComponentType carries meaning that BaseObjectType does not.
Members
A type's children come in a few flavours, distinguished by the reference that attaches them:
- Components (
HasComponent) — the substance of the thing: measured values, sub-objects, methods. - Properties (
HasProperty) — metadata about the node, not data from the process. Serial number, engineering range. - Methods — callable operations, with input and output arguments.
Each member carries a modelling rule: Mandatory members appear on every
instance, Optional ones only when asked for.
Companion specifications
A companion specification is a published set of types for a domain — Devices
(DI), Machinery, Robotics, Machine Tools. They are ordinary OPC UA models that
happen to be standardised, and they are the reason your model should rarely
start from BaseObjectType.
The modeller ships 28 of them, queryable offline through the MCP tools and declarable with a single alias:
namespaces:
- di
- machinery
The mapping
Every OPC UA concept above has one place it lives in the DSL:
| OPC UA | DSL | Reference |
|---|---|---|
| Namespace this model defines | namespaceUri | Header |
| Companion specs used | namespaces: | Namespaces |
| A nodeset we do not ship | imports: | Custom nodesets |
| ObjectType | objectTypes: | Object types |
| VariableType | variableTypes: | Variable types |
| DataType | dataTypes: | Data types |
| ReferenceType | referenceTypes: | Reference types |
| Interface | interfaceTypes: | Interfaces |
| EventType | eventTypes: | Event types |
| FiniteStateMachine | stateMachines: | State machines |
| Object / Variable instance | instances: | Instances |
HasComponent child | components: | Object types |
HasProperty child | properties: | Object types |
| Method | methods: | Methods |
| Subtyping | subtypeOf: | Object types |
| Optional member, made mandatory | promotedToMandatory: | Initializers |
| Initial values | initializers: | Initializers |
| Non-hierarchical references | references: | References |
NodeIds are not in that table on purpose. You do not write them; the
generator assigns them and the symbols.csv file keeps them stable across
regenerations. That is the point of the DSL: BrowseNames are the contract,
NodeIds are an implementation detail.
Next
- Why a modelling language? — the argument for not hand-editing XML
- From YAML to a nodeset — what the compiler produces
- Glossary
- The DSL reference