OPC-UA Integration
OPC-UA Integration connects ThingsBoard to an OPC UA server as a client. It finds the device nodes that match your mapping, subscribes to their values, and passes every change to an uplink data converter, which turns it into telemetry and attributes. For downlink, ThingsBoard writes values to server nodes and calls server methods.
Use OPC-UA Integration when:
- Your data lives on an OPC UA server, such as a PLC, a SCADA system, or an OPC UA gateway like KEPServerEX, and the server is reachable from ThingsBoard.
- You want ThingsBoard to create a device for every node that matches a pattern, instead of registering devices one by one.
- You need to write node values or call methods on the server from the Rule Engine.
Architecture
Section titled “Architecture”- Connect and find devices. The integration connects to the server and browses its address space for nodes that match the Device Node Pattern. It repeats the scan every Scan period in seconds.
- Subscribe. For each device node, the integration subscribes to the child nodes listed in Subscription tags. The server reports value changes, sampled once per second.
- Decode the payload. On every change, the uplink converter gets the tag values and the device node details, and returns the device name, telemetry, and attributes. If Allow create devices or assets is on, ThingsBoard creates the device on its first message.
- Write or call (optional). The Rule Engine passes a message to the integration. The downlink converter returns the values to write and the methods to call, and the integration sends them to the server right away.
Prerequisites
Section titled “Prerequisites”- Access to ThingsBoard or ThingsBoard Cloud with integrations enabled for your tenant.
- Permission to create integrations and data converters, and to edit rule chains for downlink.
- An OPC UA server that ThingsBoard can reach over TCP.
- Optional: an OPC UA client to browse the server and look up node names and NodeIds, for example the free Prosys OPC UA Browser.
Prepare the OPC UA Server
Section titled “Prepare the OPC UA Server”Collect these details of your server. You enter them in the integration later.
- Endpoint URL —
opc.tcp://{host}:{port}/{path}. - Security policy and Identity that the server accepts.
- Device node — the node that represents a device, with its full browse path from
Objects, or its NodeId. - Tags — the browse names of the child nodes to read, and the NodeIds of the nodes to write or the methods to call.
This guide uses the public demo instance of the Prosys OPC UA Simulation Server as an example. It runs on the internet with values that change every second, so there is nothing to install. To follow the guide with your own server, replace the example values with yours. For a complete scenario with another server, a dashboard, and method calls, see the air conditioner monitoring recipe.
| Setting | Value |
|---|---|
| Endpoint URL | opc.tcp://uademo.prosysopc.com:53530/OPCUA/SimulationServer |
| Host | uademo.prosysopc.com |
| Port | 53530 |
| Endpoint | /OPCUA/SimulationServer |
| Security | None |
| Identity | Anonymous |
On the demo server, the guide reads the sample device MyDevice. Its fully qualified name is Objects.MyObjects.MyDevice, and its NodeId is ns=6;s=MyDevice. Among its child nodes are:
- MyLevel — a
Doublevariable, NodeIdns=6;s=MyLevel, with a simulated level that changes every second. The guide reads it as telemetry. - MySwitch — a
Booleanvariable, NodeIdns=6;s=MySwitch, that clients can write. The guide reads it and writes it. - MyLevelAlarm — an alarm object, NodeId
ns=6;s=MyLevel.Alarm, not a variable. - MyMethod — a sample method.
To check the address space, open an OPC UA client such as the Prosys OPC UA Browser, connect to the endpoint URL, and expand Objects ⇾ MyObjects ⇾ MyDevice. Select a node to see its NodeId.
Set Up OPC-UA Integration
Section titled “Set Up OPC-UA Integration”Create the uplink converter, then the integration with the mapping of your device nodes.
Create the Uplink Data Converter
Section titled “Create the Uplink Data Converter”The uplink converter receives the tag values as a JSON byte array and returns the device data. OPC-UA Integration uses the Generic converter: you write the decoder in TBEL or JavaScript. For converter types and the full decoder reference, see Uplink data converter.
-
Go to Integrations ⇾ Data converters and click + Add data converter ⇾ Create new converter.
-
Converter type — keep Uplink.
-
Integration type — select OPC-UA.
-
Name — enter a name, for example
OPC-UA Uplink Converter. -
Main decoding configuration — the editor opens with the default OPC-UA decoder below. Keep it: it takes the device name from the node name in the metadata, stores the node details as attributes, and stores every tag value as telemetry. Use the TBEL / JS toggle to switch to JavaScript.
/** Decoder **/// One string value per subscription tag key, for example {"level": "42.17", "switchState": "true"}.var data = decodeToJson(payload);var telemetry = {};foreach (element : data.entrySet()) {var value = element.value;// A tag without a value yet arrives as null.if (value != null) {// Boolean values arrive as "true" or "false".if (value == "true" || value == "false") {value = value == "true";}telemetry.put(element.key, value);}}return {// Device node name, for example MyDevice.deviceName: metadata['opcUaNode_name'],deviceType: "OPC-UA Device",attributes: {opcUaNodeFqn: metadata['opcUaNode_fqn'],opcUaNamespaceIndex: metadata['opcUaNode_namespaceIndex'],opcUaIdentifier: metadata['opcUaNode_identifier']},telemetry: telemetry};/** Decoder **/// One string value per subscription tag key, for example {"level": "42.17", "switchState": "true"}.var data = JSON.parse(String.fromCharCode.apply(String, payload));var telemetry = {};Object.keys(data).forEach(function (key) {var value = data[key];// A tag without a value yet arrives as null.if (value !== null) {// Boolean values arrive as "true" or "false".if (value === 'true' || value === 'false') {value = value === 'true';}telemetry[key] = value;}});return {// Device node name, for example MyDevice.deviceName: metadata['opcUaNode_name'],deviceType: 'OPC-UA Device',attributes: {opcUaNodeFqn: metadata['opcUaNode_fqn'],opcUaNamespaceIndex: metadata['opcUaNode_namespaceIndex'],opcUaIdentifier: metadata['opcUaNode_identifier']},telemetry: telemetry};To adapt:
- Device name —
opcUaNode_nameis the browse name of the device node. If nodes in different folders share a name, usemetadata['opcUaNode_fqn']instead. - Device profile — set
deviceTypeto the name of the device profile you want. - Attributes instead of telemetry — move a key from
telemetrytoattributes, for exampleif (element.key == "switchState") { ... }. - Update-only keys — the node attributes are sent with every message. To store them only when they change, add them to the Update only keys list in Advanced decoding parameters.
- Group or customer — add
groupNameorcustomerNameto the result.
- Device name —
-
Click Test decoder function and check the result (see Test the Decoder).
-
Click Add.
Decoder Inputs
| Variable | Type | Content |
|---|---|---|
payload |
byte array | A JSON object with one entry per subscription tag: the tag Key and the node value as a string, for example "42.17" or "true". A tag whose node has no value yet is null. |
metadata |
{[key: string]: string} |
integrationName, the key–value pairs from the integration’s Metadata field, and the device node details: opcUaNode_name (browse name), opcUaNode_fqn (fully qualified name), opcUaNode_namespaceIndex, and opcUaNode_identifier (the identifier part of the NodeId). |
For the example device, the first message after the device is found holds every tag. A tag whose value has not arrived yet is null:
{ "level": "17.0", "switchState": null}with this metadata:
{ "integrationName": "OPC-UA integration", "opcUaNode_name": "MyDevice", "opcUaNode_fqn": "Objects.MyObjects.MyDevice", "opcUaNode_namespaceIndex": "6", "opcUaNode_identifier": "MyDevice"}After that, each message holds only the tag that changed, plus every tag marked Required. For example, a level change sends {"level": "18.0"}. Write the decoder so that every key is optional.
Test the Decoder
Click Test decoder function below the editor. Replace the payload with {"level": "42.17", "switchState": "true"}, and in Metadata add opcUaNode_name = MyDevice, opcUaNode_fqn = Objects.MyObjects.MyDevice, opcUaNode_namespaceIndex = 6, and opcUaNode_identifier = MyDevice. Click Test. The Output panel shows:
{ "deviceName": "MyDevice", "deviceType": "OPC-UA Device", "attributes": { "opcUaNodeFqn": "Objects.MyObjects.MyDevice", "opcUaNamespaceIndex": 6, "opcUaIdentifier": "MyDevice" }, "telemetry": { "level": "42.17", "switchState": true }}level stays a string in the test output. When ThingsBoard saves the data, it stores numeric strings as numbers. If the output is empty or shows an error, fix the decoder and test again.
Create the Integration
Section titled “Create the Integration”- Go to Integrations ⇾ Integrations and click + Add integration.
- Basic settings:
- Integration type — select OPC-UA.
- Name — keep the default
OPC-UA integrationor enter your own. - Enable integration and Allow create devices or assets — keep both on, so the device is created on its first message.
- Click Next.
- Uplink data converter:
- Click Select existing and choose
OPC-UA Uplink Converter. - Alternatively, click Create new to write a decoder here.
- Click Next.
- Click Select existing and choose
- Downlink data converter:
- Click Skip. Add a downlink converter later if you need to write to the server.
- Connection:
- Host — the host of your server, for example
uademo.prosysopc.com. - Port — the port of your server. Replace the default
49320, for example with53530. - Endpoint — the endpoint path, for example
/OPCUA/SimulationServer. - Security — a policy that the server offers. The example keeps
None. - Identity — Anonymous, or Username with the credentials of your server. The example keeps Anonymous.
- Mapping, in the same step:
-
Mapping type — keep Fully Qualified Name.
-
Device Node Pattern — a regular expression for the full path of your device nodes. Replace the default
Channel1\.Device\d+$, for example withObjects\.MyObjects\.MyDevice. Escape each dot as\.. -
Subscription tags — one tag per node to read: a Key for the value and the Path of the node. Fill in the first tag, then click Add subscription tag for the next one. Leave Required off. The example uses:
Key Path levelMyLevelswitchStateMySwitch
-
- Host — the host of your server, for example
- Click Add.
The integration connects to the server right away and starts the first scan. See Connection Settings for the other parameters.
Connection Settings
Section titled “Connection Settings”| Parameter | Default | Description |
|---|---|---|
| Host | — | Host name or IP address of the OPC UA server. Required. On ThingsBoard Cloud, it must be a public address. |
| Port | 49320 |
Port of the server, from 1 to 65535. The default is the port of KEPServerEX. |
| Endpoint | — | Path of the endpoint. The integration connects to opc.tcp://{Host}:{Port}/{Endpoint}. The leading slash is optional. Leave it empty if the server endpoint has no path. |
| Security | None |
Security policy: None, Basic128Rsa15, Basic256, or Basic256Sha256. The integration uses the first endpoint of the server with this policy. Any policy other than None shows the Keystore fields. |
| Type | JKS |
In Keystore. JKS or PKCS12. |
| Location | — | In Keystore. The keystore file with the client certificate and private key. Upload it with Browse file, or click Use Secret storage to take it from Secrets storage. The server must trust this certificate. |
| Alias | opc-ua-extension |
In Keystore. Alias of the key entry. |
| Password and Key password | secret |
In Keystore. Passwords of the keystore and of the key entry. |
| Identity | Anonymous | Anonymous, or Username with the Username and Password fields. |
| Mapping type | Fully Qualified Name | In Mapping. Fully Qualified Name matches the Device Node Pattern against the full browse path of a node, for example Objects.MyObjects.MyDevice. ID matches it against the identifier part of the NodeId, for example Channel1.Device1 in ns=2;s=Channel1.Device1. |
| Device Node Pattern | Channel1\.Device\d+$ |
In Mapping. Required. Regular expression that must match the whole name or identifier. For Fully Qualified Name, the path starts at Objects, and each dot must be escaped as \.: the integration splits the pattern at \. to decide which folders to browse. |
| Namespace | — | In Mapping, for ID only. Namespace index of the device nodes. If empty, nodes in every namespace can match. |
| Subscription tags | — | In Mapping. At least one is required. Key is the name of the value in the payload. Path is the browse name of a node anywhere under the device node, for example MyLevel. If the NodeId identifier of a child contains the device node name, Path is the rest of the identifier instead, for example Tag1 for Channel1.Device1.Tag1. Required adds the tag to every message, not only when it changes. |
| Add mapping element | — | Adds another mapping with its own pattern and tags, for a second kind of device. |
| Execute remotely | Off | Runs the integration as a separate process outside the ThingsBoard cluster, for a server in a private network. ThingsBoard generates an Integration key and Integration secret for it. See Remote Integration. |
| Application name | — | In Advanced settings. Client application name sent to the server. |
| Application uri | — | In Advanced settings. Client application URI sent to the server. |
| Scan period in seconds | 10 |
In Advanced settings. How often the integration browses the server again to find new device nodes and tags. Devices not found in a scan are removed from the integration. It does not change how often values arrive. |
| Timeout in milliseconds | 5000 |
In Advanced settings. Request timeout of the OPC UA client. |
| Description | — | In Advanced settings. Free-text description. |
| Metadata | — | In Advanced settings. Key–value pairs added to the metadata of every message from this integration. |
The subscription settings are fixed: the integration asks the server to sample each tag every 1,000 ms and to report changes once per second. If the connection fails, the integration tries again after 10 seconds, adding 10 seconds to each next attempt, up to 10 minutes.
Test Uplink
Section titled “Test Uplink”Data arrives as soon as the integration connects and whenever a tag value changes. On the demo server, MyLevel changes every second.
Verify the Result
Section titled “Verify the Result”- Integration events — go to Integrations ⇾ Integrations, open the integration, and click the Events tab. A CONNECT event with status SUCCESS shows that the integration connected. Then Uplink events with status OK follow, about once per second. Click
⋅⋅⋅in the Message column to see the tag values, for example{"level":"18.0"}. - Converter events — open
OPC-UA Uplink Converterin Integrations ⇾ Data converters and click the Events tab. In shows the tag values, Out shows the decoded result, and Metadata showsintegrationNameand theopcUaNode_*keys. - Device — go to Devices & assets ⇾ Devices. The integration has created the device
MyDevicewith the OPC-UA Device profile. Open it and check:- Latest telemetry —
level, which updates as the server value changes, andswitchState. - Attributes —
opcUaNodeFqn,opcUaNamespaceIndex, andopcUaIdentifierin Client attributes.
- Latest telemetry —
Configure Downlink
Section titled “Configure Downlink”The integration sends each downlink right away as OPC UA Write and Call requests. Nothing is queued: if the integration is not connected, it records a Downlink event with status FAILURE and drops the message.
The downlink converter turns a Rule Engine message into a JSON object with two arrays: writeValues and callMethods. In this guide, a change of the shared attribute switchState writes MySwitch on the server. For the full encoder reference, see Downlink data converter.
Create and Assign the Downlink Converter
Section titled “Create and Assign the Downlink Converter”- Open the integration in Integrations ⇾ Integrations and click Toggle edit mode (pencil icon).
- In the Downlink data converter field, click Create new.
- Enter a name, for example
OPC-UA Downlink Converter. - Main encoding configuration opens in TBEL with the default OPC-UA encoder below. Keep it: on a
switchStateshared attribute update, it writes the value to theMySwitchnode of the device. Use the TBEL / JS toggle to switch to JavaScript. - To record downlink events, click the debug button next to the name, select All messages, and click Apply.
- Click Add.
- Click Apply changes.
The default encoder writes the switchState value to the MySwitch node of the device. The rule chain adds the namespace index of the device to the metadata as cs_opcUaNamespaceIndex.
/** Encoder **/
var data = { writeValues: [], callMethods: []};
// A shared attribute update, for example {"switchState": true}.if (msgType == 'ATTRIBUTES_UPDATED' && msg.switchState != null) { data.writeValues.push({ // For the example device: ns=6;s=MySwitch. nodeId: 'ns=' + metadata['cs_opcUaNamespaceIndex'] + ';s=MySwitch', value: msg.switchState, dataType: 'Boolean' });}
return { contentType: 'JSON', data: JSON.stringify(data), metadata: {}};/** Encoder **/
var data = { writeValues: [], callMethods: []};
// A shared attribute update, for example {"switchState": true}.if (msgType === 'ATTRIBUTES_UPDATED' && msg.switchState !== undefined && msg.switchState !== null) { data.writeValues.push({ // For the example device: ns=6;s=MySwitch. nodeId: 'ns=' + metadata['cs_opcUaNamespaceIndex'] + ';s=MySwitch', value: msg.switchState, dataType: 'Boolean' });}
return { contentType: 'JSON', data: JSON.stringify(data), metadata: {}};To check the encoder, click Test encoder function. Set Message type to ATTRIBUTES_UPDATED, replace the Message with {"switchState": true}, add cs_opcUaNamespaceIndex = 6 to Metadata, and click Test. The Output panel shows:
{ "contentType": "JSON", "data": "{\"writeValues\":[{\"nodeId\":\"ns=6;s=MySwitch\",\"value\":true,\"dataType\":\"Boolean\"}],\"callMethods\":[]}", "metadata": {}}The integration reads these fields from the encoder result. It ignores metadata.
| Field | Description |
|---|---|
contentType |
Must be JSON. Results with other content types are skipped. |
data |
JSON string with the writeValues and callMethods arrays. Both are optional. If both are empty, nothing is sent. |
writeValues[].nodeId |
NodeId of the variable to write, for example ns=6;s=MySwitch or ns=3;i=1009. Entries with an invalid NodeId are skipped. |
writeValues[].value |
Value to write: a number, string, or boolean. |
writeValues[].dataType |
Optional OPC UA type of the value: SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, Float, Double, Boolean, or String. UInt64 is not supported: the write fails with failed to convert value to OPC UA type UInt64. An unknown name is treated as String. Without it, whole numbers are sent as Int32 (or Int64 if too large), decimals as Double. The server rejects a value whose type does not match the node, so set it for numeric nodes. |
callMethods[].objectId |
NodeId of the object that owns the method, for example ns=6;s=MyDevice. |
callMethods[].methodId |
NodeId of the method. |
callMethods[].args |
Optional array of input arguments, in order. Each one is a value, or an object with value and dataType, for example {"value": 2.5, "dataType": "Double"}. |
To call a method, push an entry to callMethods. Look up the NodeIds and the input arguments of the method in an OPC UA client: select the method and check its InputArguments property.
Configure the Root Rule Chain
Section titled “Configure the Root Rule Chain”The encoder needs the namespace index of the device. Add it to the metadata with an originator attributes node, then pass the message to the integration.
- Go to Data processing ⇾ Rule chains and open the Root Rule Chain.
- From the Enrichment section, drag an originator attributes node onto the canvas:
- Name — for example
Add Namespace Index. - Client attributes —
opcUaNamespaceIndex. The node adds it to the metadata ascs_opcUaNamespaceIndex. - Add originator attributes to — keep Metadata.
- Click Add.
- Name — for example
- From the Action section, drag an integration downlink node onto the canvas:
- Name — for example
Downlink to OPC-UA. - Integration — select
OPC-UA integration. - Click Add.
- Name — for example
- Connect the message type switch node to
Add Namespace Indexwith the Attributes Updated relation. - Connect
Add Namespace IndextoDownlink to OPC-UAwith the Success relation. - Click Apply changes.
Test Downlink
Section titled “Test Downlink”- Go to Devices & assets ⇾ Devices and open
MyDevice. - On the Attributes tab, select Shared attributes and click +.
- Enter Key
switchState, select the Boolean type, set the value to the opposite of the currentswitchStatetelemetry, and click Add.
Verify the Downlink
Section titled “Verify the Downlink”- Converter events — open
OPC-UA Downlink Converterin Integrations ⇾ Data converters and click the Events tab. In shows{"switchState": true}withcs_opcUaNamespaceIndexin its metadata. Out shows thewriteValuesentry withns=6;s=MySwitch. - Integration events — open the integration’s Events tab. Two events appear: Downlink: ATTRIBUTES_UPDATED for the message from the Rule Engine, and Downlink with status OK for the write, with the written values in its message. A rejected write appears as an error with the OPC UA status, for example
Write NodeId{ns=6, id=MySwitch}, status = Bad_TypeMismatch. - Device — the server reports the new
MySwitchvalue back, soswitchStateon the Latest telemetry tab changes to the value you set. - Server — in an OPC UA client, such as the Prosys OPC UA Browser, select MySwitch. Its Value shows the value you set.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Cause | Fix |
|---|---|---|
| No events on the integration Events tab | Debug mode is off, or the integration is disabled. Debug mode records all events only for a limited time after you turn it on. | Turn on Enable integration and debug mode. Click Toggle edit mode and Apply changes to reconnect. |
Host must be in the public network., or Usage of local network host for OPC-UA server connection is not allowed! |
The host is a private or local address, and the platform allows only public hosts. | Use a public address, or run the integration as a Remote Integration in the server’s network. |
CONNECT with status FAILURE: Failed to connect to provided endpoint: opc.tcp://... |
The host, port, or endpoint is wrong, or a firewall blocks the connection. | Check the URL in the error against the endpoint URL of your server. Allow outbound TCP to the port. |
CONNECT with status FAILURE: Failed to connect to OPC-UA server. Reason: UaServiceFaultException: status=Bad_TooManySessions |
The server has reached its maximum number of sessions. The public demo server often does. Every client connected to it, such as an OPC UA browser, holds a session. | Disconnect other clients you do not need. The integration reconnects on its own, with a delay that grows by 10 seconds after each failure, up to 10 minutes. To retry right away, turn Enable integration off and on. |
CONNECT with status FAILURE: no desired endpoints returned |
The server has no endpoint with the selected Security policy. | Select a policy that the server offers. Check the endpoints in an OPC UA client. |
CONNECT with status FAILURE: Failed to load certificate using provided configuration! |
The keystore file, type, alias, or a password is wrong. | Check the Keystore fields. The alias must point to an entry with a private key. |
| CONNECT with SUCCESS, but no Uplink events | The Device Node Pattern matches no node. | Check the pattern against the full path from Objects, for example Objects\.MyObjects\.MyDevice. Escape every dot as \.: with plain dots, the integration does not browse into the folders. For ID, check Namespace. |
A key is always null in the payload |
The tag Path matches no node under the device node, for example because of a typo or an extra character such as a trailing dot or space. | Use the exact browse name of the node, for example MySwitch. Check it in an OPC UA client. |
| Each Uplink event holds only one key | Expected: a message holds only the changed tag and the tags marked Required. | Mark the tags you need in every message as Required. |
Device named Unknown Device |
The converter has a decoder that reads deviceName from the payload, for example a decoder copied from another integration. OPC UA payloads have no deviceName. |
Use the default OPC-UA decoder: it reads the device name from opcUaNode_name in the metadata. |
switchState is stored as the string "true" |
The decoder does not convert boolean strings. | Use the default OPC-UA decoder, or convert "true" and "false" to booleans in your decoder. |
Downlink FAILURE: Cannot process downlink message because of connection was lost. |
The integration was not connected. Downlinks are not queued. | Check the CONNECT events, fix the connection, and send the downlink again. |
No downlink event, and the converter Out has ns=null (TBEL) or ns=undefined (JavaScript) in nodeId |
The rule chain did not add cs_opcUaNamespaceIndex, so the NodeId is invalid and the write is skipped. |
Connect Add Namespace Index between the message type switch and the integration downlink node, and check that the device has the opcUaNamespaceIndex client attribute. |
| No downlink and no error | No downlink converter is assigned, the rule chain does not route attribute updates, or the encoder returned empty arrays. | Assign the converter, check the Attributes Updated relation, and check Out in the downlink converter events. |
Downlink error Bad_TypeMismatch |
The value type does not match the node type, for example a string for a Boolean node. |
Set dataType in the encoder. Add the shared attribute with the matching type. |
Downlink error Bad_NodeIdUnknown, Bad_NotWritable, or Bad_UserAccessDenied |
The NodeId is wrong, or the server does not allow the write. | Check the NodeId and the AccessLevel of the node in an OPC UA client. |
To read debug events, open the integration or converter, click Events, and select an event: In is the received data, Out is the converter result, and Error holds the error text.
See Also
Section titled “See Also”- Integrations overview — how integrations, converters, uplinks, and downlinks fit together.
- Uplink data converter — decoder inputs, output format, and scripting patterns.
- Downlink data converter — encoder reference.
- integration downlink node — route Rule Engine messages to an integration.
- originator attributes node — add attributes of the message originator to the metadata.
- message type switch node — route messages by type, for example attribute updates.
- Remote Integration — run the integration outside the ThingsBoard cluster, next to a server in a private network.
- Secrets storage — store the keystore for secure connections.
- TBEL — built-in functions and syntax for converter scripts.
- Monitor and control air conditioners over OPC UA — an end-to-end example with a dashboard and RPC downlink.
- Prosys OPC UA Simulation Server — the server used as the example in this guide; run your own copy for private tests.
Was this helpful?