OPC UA connects an instance to PLCs, gateways and SCADA products in both directions. The client module reads and writes nodes on an OPC UA server. The server module publishes the instance's own variables to OPC UA clients. Both modules use the same certificate, kept in the same folders.
| Module | What it does | Typical use |
|---|---|---|
OPCUA-Client (OPC UA Client) |
Reads nodes into variables, by subscription or on a schedule, and writes variables to nodes when they change | Tags on a PLC with a built-in OPC UA server, or on an OPC UA gateway |
OPCUA-Server (OPC UA Server) |
Publishes chosen variables as nodes, and accepts the writes its configuration permits | Giving a SCADA, HMI or reporting tool the instance's variables |
Enable, Name and the Status and messages tab work the same way in every module. They are described in Settings every module shares.
Certificates
With any security policy other than None, both ends of an OPC UA connection prove who they are with a certificate.
The instance creates its own the first time either module opens, and keeps it with the certificates it has been
shown:
instance/pki/opcua/own/certificate.p12 this instance's key pair and certificate
instance/pki/opcua/trusted/ certificates this instance accepts
instance/pki/opcua/issuers/ certificate authorities, for certificates signed by one
instance/pki/opcua/rejected/ certificates that were refused
- One identity per instance. The client and the server module present the same certificate: self-signed,
RSA 2048, valid for 20 years, with the application URI
urn:amtiri:dataorchester:<install id>. - No trust on first use. A certificate that is neither in
trusted/nor signed by an authority inissuers/is refused, and filed inrejected/. The client's error message shows its thumbprint (SHA-1, as OPC UA tools show it). - Trusting is moving a file. Move the certificate from
rejected/totrusted/. Nothing needs restarting: the folders are watched, and a client that failed to open tries again on its own (see Settings every module shares). - What is checked. The certificate's validity dates and its key usage. The host name and the application URI inside it are not checked, because an industrial device's certificate rarely names the address it is reached at.
Important
The first connection to a secured server is expected to fail once, and so is the first secured connection of a new
client to the server module. Trusting a certificate is a deliberate act on each side: move the far end's certificate
into trusted/ here, and trust this instance's certificate on the far end, the way that product's documentation
says.
OPC UA Client
The OPCUA-Client module opens one session to one OPC UA server and keeps it. It has two lists, as every client
module does: collectors bring a node's value into a variable, and forwarders write a variable's value to a
node whenever the variable changes.
Settings
| Key | Setting | Type | Default | Meaning |
|---|---|---|---|---|
endpointUrl |
Endpoint URL | string | opc.tcp://localhost:4840 |
The server's address, with scheme and port, such as opc.tcp://10.20.1.15:4840. Required: without it the module does not open |
securityPolicy |
Security policy | string | None |
None, Basic256Sha256, Aes128_Sha256_RsaOaep or Aes256_Sha256_RsaPss. The policy's full URI is accepted too. A name the engine does not know is read as None |
securityMode |
Security mode | string | None |
None, Sign or SignAndEncrypt. A value the engine does not know is read as None |
userName |
User | string | (empty) | The user the session opens with. Empty opens it anonymously |
password |
Password | string | (empty) | The user's password, or env:NAME to read it from the environment variable NAME each time the module opens |
publishingIntervalMs |
Publishing (ms) | int, ms | 1000 | How often the server may send the changes of the subscribed nodes |
collectors |
Collector | list of rows | empty | The nodes read into variables |
forewarders |
Forwarder | list of rows | empty | The variables written to nodes. The key is spelled forewarders |
Collectors and forwarders
A collector row uses every key below. A forwarder row uses field, nodeId and dataType.
| Key | Column | Type | Default | Meaning |
|---|---|---|---|---|
field |
Variable | variable code | (none) | Collector: the variable the node's value is written to. Forwarder: the variable whose changes are written to the node |
nodeId |
NodeId | string | (empty) | The node, in OPC UA notation: ns=3;s="DB_Tank"."Level", ns=2;i=1001 |
dataType |
Type | string | (empty) | The node's OPC UA type, from the table below. Optional, but see what it decides |
mode |
Mode | string | poll |
subscription: the server sends the value whenever it changes. Any other value, poll in the editor: the module reads the node on cron |
cron |
Schedule / sampling | Quartz cron | 0 * * * * ? |
A polled collector's schedule. Required for a polled collector |
samplingIntervalMs |
Schedule / sampling | int, ms | 1000 | How often the server samples a subscribed node |
The Schedule / sampling column follows the mode: a cron for a polled collector, a sampling interval for a subscribed one.
Types
dataType decides two things. It tells the editor the variable type of the row, so the diagram shows the module's
ports and the pencil beside Variable can create a variable of that type before the server has ever been reached.
And it decides the OPC UA type a forwarder sends: OPC UA writes are typed, so a node declared Int16 refuses a
write carrying an Int64, however small the number in it.
dataType |
Variable type | Notes |
|---|---|---|
Boolean |
boolean | |
SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64 |
int | Unsigned values arrive as whole numbers. A UInt64 above 9223372036854775807 arrives as a negative number, the value less 18446744073709551616: 18446744073709551615 arrives as -1 |
Float, Double |
float | |
String |
string | |
LocalizedText |
string | The text, without its locale |
DateTime |
string | ISO 8601 in UTC, to the second: 2026-09-29T14:05:00Z |
Boolean[], Int32[], Double[], String[] |
list | An array arrives as a list |
- Reading, the server has already said what the value is: it is converted as the table says, and stored with the variable's own type, as every value a module writes is.
- Writing, the value is converted to
dataTypebefore it is sent. Without adataType, and forDateTimeand the array types, it is sent as the variable holds it. - Ranges are not checked. Keep a forwarded variable within the node's range: 70000 sent as
Int16arrives as 4464.
Behaviour
- Opening. Every polled collector's schedule is checked first, then the endpoint URL. A problem stops the module opening, with a message naming it.
- The endpoint. The module connects only to an endpoint the server offers with exactly the configured policy and
mode. It never falls back to another one, so a server that offers
Nonefirst cannot quietly downgrade a module configured forSignAndEncrypt. It keeps the host and port written in Endpoint URL, even when the server's endpoints name another address, as a server behind NAT or in a container often does. - Subscribed collectors share one subscription, with the publishing interval of the module and the sampling interval of each row. The subscription is created again every time the session is re-activated.
- Polled collectors are read once when the module opens, then on their own schedules. Each node is read on its own, never from a cache on the server.
- Forwarders write their variable's current value once when the module opens, then every change.
- A bad status is not a lost link. A node that answers with a bad status leaves its variable as it was, and the module warns. A variable is never cleared to say that its reading failed.
- Reconnection is the OPC UA library's own: a dropped session is re-activated, and the module reports what happened. A module that could not open at all is tried again by the engine.
Messages
A problem is written into the module's message variables, and cleared once the module succeeds again. "then ERROR"
follows the thresholds in Settings every module shares: a lost connection becomes
an error after errorAfterSeconds, and a failure repeated errorAfterFailures times in a row becomes one. All texts
are in English; the full list is in Module messages.
{server} is the Endpoint URL. In {node} refused the write: {reason}, {reason} is the status code the
server answered the write with, written out with its name, such as Bad_NotWritable, and its value.
| When | Level | Text |
|---|---|---|
| Opening: a polled collector has no schedule | ERROR |
No schedule given |
| Opening: a schedule does not parse | ERROR |
Invalid schedule '{cron}': {reason} |
| Opening: no endpoint URL | ERROR |
No endpoint URL |
| Opening: the server's certificate is not trusted | ERROR |
Server certificate not trusted: {thumbprint} |
| Opening: the server cannot be reached, or offers no endpoint with this policy and mode | ERROR |
Server {server} unreachable: {reason} |
| The session is active | INFO |
Connected to {server} |
| Every subscribed node was accepted | INFO |
Subscribed to {n} node(s) |
| The server refused some subscribed nodes | WARNING |
{n} of {total} node(s) refused by the server |
| The subscription could not be created | WARNING |
Subscription refused: {reason} |
| The session dropped | WARNING, then ERROR |
Disconnected from {server}, then Server {server} unreachable |
| A polled read failed | WARNING, then ERROR |
Reading {node} failed: {reason} |
| A node answered with a bad status | WARNING |
{node} returned {status} |
| The variable could not take the value | WARNING |
Variable {variable} refused the value: {reason} |
| The server refused a write | WARNING |
{node} refused the write: {reason} |
| A write could not be sent | WARNING |
Writing {node} failed: {reason} |
Example
A tank level taken as the PLC changes it, a pump's running hours checked every five minutes, and a level setpoint written back when an operator moves it, over an encrypted session:
Endpoint URL opc.tcp://10.20.1.15:4840
Security policy Basic256Sha256
Security mode SignAndEncrypt
User orchester
Password env:OPCUA_PLC1_PASSWORD
Collector LIT_101 ns=3;s="DB_Tank"."Level" Double Subscription 500
Collector P_101_HOURS ns=3;s="DB_Pump"."Hours" UInt32 Poll 0 */5 * * * ?
Forwarder LIT_101_SP ns=3;s="DB_Tank"."Setpoint" Double
The first connection fails with Server certificate not trusted: {thumbprint}. Once the PLC's certificate is moved
into trusted/, and the PLC trusts this instance's certificate, the next attempt connects. LIT_101 then follows
the PLC without being asked, P_101_HOURS costs one read every five minutes, and writing LIT_101_SP from a
dashboard or a formula sends it to the PLC as a Double.
OPC UA Server
The OPCUA-Server module makes the instance an OPC UA server. A SCADA, an HMI or a reporting tool connects to it,
browses the published variables, reads or subscribes to them, and writes the ones it is allowed to.
The endpoint URL is:
opc.tcp://<host>:<port>/orchester
<host> is the address the client reaches the machine at, and <port> is the module's port. In the endpoint
descriptions it publishes, the server names itself by the machine's host name; a client that cannot resolve that name
should keep the address it dialled.
Settings
| Key | Setting | Type | Default | Meaning |
|---|---|---|---|---|
port |
Port | int | 4840 | The TCP port. The server listens on every network interface |
securityPolicies |
Security policy | list of strings | Basic256Sha256 |
The policies offered, one endpoint each, chosen with four checkboxes: None, Basic256Sha256, Aes128_Sha256_RsaOaep, Aes256_Sha256_RsaPss. At least one must be usable |
allowAnonymous |
Allow anonymous access | boolean | false | Whether a session may open without a user. An anonymous session may read, and may never write |
users |
Users | list of rows | empty | Who may open a session |
variables |
Published variables | list of rows | empty | The variables the server publishes |
- Every policy except
Noneis offered with the modeSignAndEncryptonly.Noneis offered with the modeNone, and only when it is ticked. - With anonymous access off and no users, no client can open a session.
Users
| Key | Column | Type | Default | Meaning |
|---|---|---|---|---|
userName |
User | string | (empty) | The name a client signs in with. Compared exactly, upper and lower case included |
password |
Password | string | (empty) | The password, or env:NAME to read it from the environment variable NAME when the module opens. A user without a password, or whose variable is not set, can never sign in |
writable |
Writable | boolean | false | Whether this user may write the variables that permit it |
Published variables
| Key | Column | Type | Default | Meaning |
|---|---|---|---|---|
field |
Variable | variable code | (none) | The variable published |
browseName |
Browse name | string | (empty) | The name the node is shown under. Empty uses the variable's code |
dataType |
Type | string | (empty) | The node's OPC UA type: Boolean, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float, Double, String or DateTime. Empty publishes the node as BaseDataType, which takes any value |
writable |
Writable | boolean | false | Whether the variable may be written from outside |
The address space
- One folder per module, under the Objects folder, named after the module's Name.
- One node per published variable, addressed as
ns=<index>;s=<code>, with the code as written in the row. The browse name and the display name are the row's Browse name. - The namespace index is assigned by the server, not chosen. On an instance with one server module it is usually
2. The engine log gives it when the module opens, in a line such as
[SCADA_LINK][OPEN] 2 variable(s) published as ns=2;s=<code> on port 4840, whereSCADA_LINKis the module's name: read it there rather than assuming it. - Values follow the variables. A node holds its variable's value when the module opens, and every change of the variable is written to the node, so a client that subscribes hears about it.
Who may write
A write is accepted only when the variable is marked Writable and the session's user is marked Writable. Neither implies the other: a variable that must never be driven from outside stays read-only whoever asks, and a read-only user cannot write even the variables that permit it.
| The variable | The session | The client gets |
|---|---|---|
| Not writable | Any | Bad_NotWritable |
| Writable | A user marked Writable | The write is accepted, and the value is written to the variable |
| Writable | A user not marked Writable | Bad_UserAccessDenied |
| Writable | Anonymous | Bad_UserAccessDenied |
An accepted value is stored with the variable's type, as every value a module writes is.
Messages
| When | Level | Text |
|---|---|---|
| Opening: no ticked policy is usable | ERROR |
No usable security policy: {policies} |
| Opening: the port cannot be bound, or the server cannot start | ERROR |
Cannot listen on port {port}: {reason} |
| The server is listening | INFO |
Listening on port {port} |
| A variable's new value could not be written to its node | WARNING |
Variable {variable} could not be published: {reason} |
The server module opens before the other modules, and a server that could not open, because another program still holds its port for example, is tried again by the engine.
Example
A tank level a plant SCADA may read, and a setpoint it may write:
Port 4840
Security policy Basic256Sha256, Aes256_Sha256_RsaPss
Allow anonymous off
Published variables
LIT_101 Tank101Level Double writable: no
LIT_101_SP Tank101Setpoint Double writable: yes
Users
scada env:OPCUA_SCADA_PASSWORD writable: yes
reports env:OPCUA_REPORTS_PASSWORD writable: no
The SCADA connects to opc.tcp://<host>:4840/orchester with SignAndEncrypt, finds both nodes under the module's
folder as ns=2;s=LIT_101 and ns=2;s=LIT_101_SP, and signs in as scada. It can write LIT_101_SP; writing
LIT_101 answers Bad_NotWritable. reports can read both and write neither: writing LIT_101_SP answers
Bad_UserAccessDenied, and writing LIT_101 answers Bad_NotWritable.
Warning
Ticking None publishes an endpoint that neither signs nor encrypts. Leave it off unless the network between the
two ends is closed to everything else.
Next steps
- Module catalogue
- Settings every module shares
- Module messages
- Siemens S7 and EtherNet/IP, for controllers without OPC UA
- Connectivity
This page describes Data Orchester engine 6.12.0.