Connect IoT - OPC UA Driver#
OPC Unified Architecture (OPC UA) is a machine to machine communication protocol for industrial automation developed by the OPC Foundation. Distinguishing characteristics are:
- Focus on communicating with industrial equipment and systems for data collection and control
- Open - freely available and implementable without restrictions or fees
- Cross-platform - not tied to one operating system or programming language
- Service-oriented architecture (SOA)
- Robust security
Data Types#
These are the supported specific data types:
| Name | Description |
|---|---|
| UInt8 | Unsigned Integer 8 bits |
| UInt16 | Unsigned Integer 16 bits |
| UInt32 | Unsigned Integer 32 bits |
| UInt64 | Unsigned Integer 64 bits |
| Int8 | Signed Integer 8 bits |
| Int16 | Signed Integer 16 bits |
| Int32 | Signed Integer 32 bits |
| Int64 | Signed Integer 64 bits |
| Boolean | Boolean value |
| Float | Floating number |
| Double | Floating double-precision number |
| String | ASCII value (text string) |
| LocalizedText | Text string localized |
| DateTime | Date and Time value |
| Custom | Custom Data Type |
Table: OPC UA specific data types
Protocol Parameters#
The protocol supports the following parameters:
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| address | String | "" | Address of OPC UA server | |
| discoveryUrl | String | "" | Url to use if the server uses Discovery. Leave empty for none | |
| user | String | "" | Login username | |
| password | Password | "" | Login password | |
| securityMode | Enum | NoneSignSignAndEncrypt | None | Message Security Mode for communication between client and server. |
| securityPolicy | Enum | NoneBasic128Basic192Basic256Basic256Sha256 | None | Security Policies for communication between client and server. The *Rsa15 policies were removed because they are no longer supported on Node.js >18.19.1 / >20.11.1. |
| certificatesRootFolder | String | "${temp}/ConnectIoT/OPC-UA/Certificates/${id}" | Absolute path of the root folder for the Public Key Infrastructure. Allows the use of tokens ${temp} or ${tmp} for the OS temporary folder and token ${id} for replacing with the respective driver instance id | |
| certificate | Text | "" | Own certificate - can be either a path to a file or the contents of the file in plain text. Format should be 'pem' | |
| privateKey | Text | "" | Own private key - can be either a path to a file or the contents of the file in plain text. Format should be 'pem' | |
| floatDecimalPlaces | Integer | 0 | Decimal places to use with float types to help fix IEEE 754 precision errors. Leave 0 for no rounding. | |
| defaultTransactionTimeout | Integer | 15000 | Client Secure Channel default transaction timeout (ms) |
Table: OPC UA specific parameters
Extended Parameters#
As with other protocol drivers, some extra parameters are necessary to provide more context to the behavior expected.
Property#
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| customDataType | String | "" | The name of the data type when selecting data type 'Custom'. Opcua requires data type names to end with 'DataType'. This isn't required here because this suffix will be automatically appended internally | |
| arrayType | Enum | ScalarArrayMatrix | Scalar | Whether the property is a scalar, an array or a matrix |
| dimensions | String | "" | Empty for scalars or arrays. For matrices this should be a comma separated list of unsigned integer values representing the length of each dimension. E.g., a 3x2 matrix: \"3,2\" or \"[3,2]\". Note: brackets are optional |
Event#
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| eventType | Enum | SubscriptionEventAlarm | Subscription | Type of alarm to registerSubscription- Notification when at least one node changes valueEvent - Notification when event occursAlarm - Notification when alarm occurs |
| publishingInterval | Integer | 1000 | The rate (in milliseconds) at which the subscription executes and reports any items that have changed | |
| lifeTimeCount | Integer | 2400 | if the client can't communicate with the server for a period of time shorter than (lifetimeCount * publishingInterval), then the subscription is still available in the server. After that, the server will delete the subscription. (In milliseconds) | |
| maxKeepAliveCount | Integer | 10 | If the server has no notifications pending for the period of time defined by (MaxKeepAliveCount * PublishingInterval), the server will send a keep alive message to the client | |
| maxNotificationsPerPublish | Integer | 0 | The maximum number of notifications that the client wishes to receive in a single publish response | |
| priority | Integer | 10 | If multiple subscriptions need to send notifications to the client, the server will send notifications to the subscription with the highest priority first | |
| serverNodeId | String | "" | When event type is either Event or Alarm, the node representing the entire server must be provided for registration. Example: "i=2253 [Server]" |
EventProperty#
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| isTrigger | Boolean | true | Trigger the event when the value changes | |
| samplingInterval | Integer | 1000 | Sampling interval (in milliseconds) for the monitored item to create | |
| discardOldest | Boolean | true | Discard the oldest item when the queue is full | |
| queueSize | Integer | 1 | Size of sampling queue |
Command#
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| objectDeviceId | String | "" | Identifier of the Object (parent) where the method is located (ex: ns=3;s=AirConditioner1) |
Command Parameter#
| Name | Type | Possible Values | Default Value | Description |
|---|---|---|---|---|
| customDataType | String | "" | The name of the data type when selecting data type 'Custom'. Opcua requires data type names to end with 'DataType'. This isn't required here because this suffix will be automatically appended internally. | |
| arrayDimensions | String | "" | Empty for scalars. For arrays, this should be a comma separated list of unsigned integer values representing the maximum length of each array dimension, where 0 represents a dimension with no maximum (or unknown) length. E.g., a 3x2 matrix: \"3,2\" or \"[3,2]\"; an array with unlimited size: \"0\" or \"[0]\". Note: brackets are optional |
Driver Extensions#
This protocol driver provides a set of extension that allow the customization to perform actions that are independent of the Driver Definitions associated. This means you can, using customization, get/set node values without needing to describe them.
- This is particularly useful when accessing equipment data that is shared/too complex to access using the regular mechanisms. Also useful when needing to access data whose naming convention may vary from device to device.
- To use these extensions you can either implement your own task or use the supplied Tasks
Send Notification to DriverandSubscribe in Driver.
Objects#
The objects are structures that are either passed as parameters or returned as result values.
Event#
| Name | Type | Description |
|---|---|---|
| name | String | Name of the event. Will be used as identifiers in the result calls. |
| isEnabled | Boolean | Is the event enabled and ready to be used? Default false |
| properties | Property[] | List of properties to link with the event |
Property#
| Name | Type | Description |
|---|---|---|
| name | String | Name of the property. Will be used as identifiers in the result calls. |
| deviceId | String | Unique identifier in the OPC UA server (this is the NodeId/Tag Name). |
| deviceType | String | Data Type as the Server known the Property. Must use one from the supported Data Types of this protocol driver. |
| dataType | String | Data Type of the value as known/used by the MES/System. |
PropertyValue#
| Name | Type | Description |
|---|---|---|
| propertyName | String | Name of the property. Will match the name of the property object provided |
| value | any | Value received from the Server, converted to the dataType of the Property |
| originalValue | any | Value received from the Server without any conversion applied. See OriginalValue below for its structure. |
OriginalValue#
| Name | Type | Description |
|---|---|---|
| dataType | String | OPC UA data type of the value, as reported by the server (for example, String, Int16). |
| arrayType | String | Scalar, Array, or Matrix, as reported by the server. |
| dimensions | Integer[] | null | Array/matrix dimensions, when arrayType is not Scalar. |
| value | any | The raw value, without any conversion applied. |
| quality | String | Good, Uncertain, or Bad, derived from the OPC UA status code's severity bits. |
| statusCode | Integer | null | The raw OPC UA status code value. |
| timestamps | Object | serverTimestamp and sourceTimestamp, each a DateTime or null. |
PropertyValuePair#
| Name | Type | Description |
|---|---|---|
| property | property | Full description of the property |
| value | any | Value to associate with the property |
RegisterHandler#
| Name | Type | Description |
|---|---|---|
| event | Event | Event to register (full information) |
UnregisterHandler#
| Name | Type | Description |
|---|---|---|
| event | Event | Event to unregister (at least the property name must be supplied) |
CustomDataType#
| Name | Type | Description |
|---|---|---|
| name | String | Name of the custom data type as known by the OPC UA server. The DataType suffix is appended automatically — register Job, not JobDataType. |
| description | String | Description of the custom data type. |
| fields | CustomDataTypeField[] | Ordered list of fields that compose the structure. Order must match the field order defined in the server. |
CustomDataTypeField#
| Name | Type | Description |
|---|---|---|
| name | String | Name of the field within the structure. |
| description | String | (Optional) Description of the field. |
| dataType | Object | Object with a Name property identifying the field's data type. Use one of the OPC UA built-in types supported by this driver (Boolean, Int8/Int16/Int32/Int64, UInt8/UInt16/UInt32/UInt64, Float, Double, String, LocalizedText, DateTime), or the literal "Custom" for a nested structure. |
| customDataTypeName | String | Required when dataType.Name is "Custom". Name of another registered custom data type that defines this field's structure. Enables nesting custom types within custom types. |
| arrayDimensions | String | (Optional) Array dimensions; empty (or omitted) for scalars. "<n>" for a 1D array of length <n>. "<n>,<m>" for a 2D matrix. "0" means unbounded length. Brackets are optional, so "[3,2]" and "3,2" are both accepted. |
| isOptional | Boolean | Whether the field is optional in the structure. Optional fields may be absent from values written to / read from the server. |
NodeInfo#
Describes a single node found while browsing the server's address space, together with its children.
| Name | Type | Description |
|---|---|---|
| nodeId | String | Identifier of the node in the server (this is the NodeId/Tag Name, usable as deviceId). |
| nodeClass | String | OPC UA node class, for example Variable, Method, or Object. |
| browseName | String | Non-localized name of the node, as defined by the server. |
| displayName | String | Localized name of the node, as returned by the server for the session's locale. |
| description | String | Description of the node, as defined by the server. |
| dataType | String | Data type of the value, only present for Variable nodes. |
| value | any | Current value of the node, only present for Variable nodes. |
| valueRank | Integer | null | OPC UA value rank, only present for Variable nodes. |
| arrayDimensions | Integer[] | null | Array/matrix dimensions, only present for Variable nodes when applicable. |
| accessLevel | Integer | null | Raw OPC UA access level mask, only present for Variable nodes. |
| userAccessLevel | Integer | null | Raw OPC UA user access level mask, only present for Variable nodes. |
| minimumSamplingInterval | Integer | null | Minimum sampling interval (in milliseconds) supported by the node, only present for Variable nodes. |
| children | NodeInfo[] | Nodes found one level below this node in the address space, following the same shape. |
Methods#
Get Properties Values#
Requests the server for the values of one or more properties (Nodes/Tags)
Signature
Example
Request connect.iot.driver.opcua.getPropertiesValues
[
{
"name": "stringValue",
"deviceId": "ns=2;s=Demo.Static.Scalar.String",
"dataType": "String"
},
{
"name": "integerValue",
"deviceId": "ns=2;s=Demo.Static.Scalar.Int16",
"dataType": "Integer"
}
]
Reply:
[
{
"propertyName": "stringValue",
"originalValue": {
"dataType": "String",
"arrayType": "Scalar",
"dimensions": null,
"value": "Hello World",
"quality": "Good",
"statusCode": 0,
"timestamps": {
"serverTimestamp": "2026-01-01T12:00:00.000Z",
"sourceTimestamp": "2026-01-01T12:00:00.000Z"
}
},
"value": "Hello World",
},
{
"propertyName": "integerValue",
"originalValue": {
"dataType": "Int16",
"arrayType": "Scalar",
"dimensions": null,
"value": 123,
"quality": "Good",
"statusCode": 0,
"timestamps": {
"serverTimestamp": "2026-01-01T12:00:00.000Z",
"sourceTimestamp": "2026-01-01T12:00:00.000Z"
}
},
"value": 123,
}
]
Set Property Values#
Requests the server to define the values of one or more properties (Nodes/Tags).
Signature
Example
Request connect.iot.driver.opcua.setPropertiesValues
[
{
"property": {
"name": "stringValue",
"deviceId": "ns=2;s=Demo.Static.Scalar.String",
"deviceType": "String"
},
"value": "Hello World"
},
{
"property": {
"name": "integerValue",
"deviceId": "ns=2;s=Demo.Static.Scalar.Int16",
"deviceType": "Int16"
},
"value": 123
}
]
Reply:
Register Event#
Notifies the protocol driver to raise the occurrences of a specific event when it occurs.
Signature
Note
The events are published to the listeners connect.iot.driver.opcua.event appended with the name of the event registered. Example: connect.iot.driver.opcua.event.TemperatureChanged
Example
{
"event":{
"name":"CustomEvent",
"isEnabled":true,
"properties":[
{
"name":"humidity",
"deviceId":"ns=2;s=Demo.Static.Scalar.Double",
"dataType":"Decimal",
"deviceType":"Double",
"extendedData":{
"isTrigger":true
}
}
]
}
}
Unregister Event#
Notifies the protocol driver to stop raising the occurrences of a specific event when they occur.
Signature
Example
Add Custom Data Types#
Registers one or more structured (complex) data types with the driver, so the driver knows how to encode and decode values for OPC UA nodes whose data type is not one of the built-in scalars.
When to use
Use this method whenever the OPC UA server exposes nodes or method parameters whose value is a structure — for example, an equipment-defined Job object, a Recipe definition, or a MaintenanceWindow record. Without registration, the driver has no schema for these types and cannot serialise values for write operations or deserialise the fields after a read.
End-to-end setup
- Declare the structure on the driver by calling
addCustomDataTypesonce at start-up, after the driver is connected and before any node with a custom data type is read or written. The recommended way to issue this call from a workflow is the Add Custom Data Types OPC UA task; the transport topic below documents the underlying contract for custom code. - Point properties or command parameters at the type. On every Property or Command Parameter that should carry a custom value, configure the Driver Definition with:
AutomationProtocolDataType/deviceTypeset toCustom.- Extended parameter
customDataTypeset to the samenameyou registered (without theDataTypesuffix — the driver appends it automatically when querying the server).
- Run the workflow. When a read or write happens, the driver looks up the type on the server using the registered name, encodes the JSON value into an OPC UA
ExtensionObjectmatching the field order, and exchanges it with the server.
Signature
Example — simple structure
A TemperatureReading with a numeric value and a string unit. Both fields are mandatory.
Request connect.iot.driver.opcua.addCustomDataTypes:
[
{
"name": "TemperatureReading",
"description": "Temperature value with unit",
"fields": [
{ "name": "value", "dataType": { "Name": "Double" }, "isOptional": false },
{ "name": "unit", "dataType": { "Name": "String" }, "isOptional": false }
]
}
]
Reply:
A Property on the Driver Definition that reads/writes this type would then be configured as deviceType: "Custom" with customDataType: "TemperatureReading".
Example — nested structure with an array of structures
A Job with an id, an optional name, and an array of Step objects (itself a custom type). Nested types must be registered too; either include them in the same call or split into multiple calls — order does not matter.
[
{
"name": "Step",
"description": "One step in a job",
"fields": [
{ "name": "index", "dataType": { "Name": "UInt16" }, "isOptional": false },
{ "name": "description", "dataType": { "Name": "String" }, "isOptional": true }
]
},
{
"name": "Job",
"description": "Job with an ordered list of steps",
"fields": [
{ "name": "id", "dataType": { "Name": "String" }, "isOptional": false },
{ "name": "name", "dataType": { "Name": "String" }, "isOptional": true },
{
"name": "steps",
"dataType": { "Name": "Custom" },
"customDataTypeName": "Step",
"arrayDimensions": "0",
"isOptional": false
}
]
}
]
Notes
- The field order in
fieldsmust match the field order declared on the server; field-by-name encoding is not used. customDataTypeNameis required wheneverdataType.Nameis"Custom"and ignored otherwise.arrayDimensionsapplies to any field, scalar or structured. Use"0"when the length is variable,"<n>"for a fixed-length 1D array, and"<n>,<m>"for a matrix.- The driver caches the resolved node id of each custom type after the first successful read. Re-registering a type with the same name is safe but does not invalidate the cache during the same session — restart the driver if the server-side definition changes.
Browse#
Walks the server's address space starting from a given node and returns the resulting tree of variables, methods, and object containers, including each variable's current value and metadata. Use this to discover which nodes a server exposes, instead of requiring the node IDs to already be known.
Standard-namespace nodes (namespace 0 and 1), such as the built-in Server object, are traversed but not included in the result, so the returned tree only surfaces the parts of the address space that a custom server actually defines.
Signature
Example
Request connect.iot.driver.opcua.browse, starting from the server's root:
Or from a specific node:
Reply:
[
{
"nodeId": "ns=2;s=Demo.Static.Scalar.String",
"nodeClass": "Variable",
"browseName": "String",
"displayName": "String",
"description": "",
"dataType": "String",
"value": "Hello World",
"valueRank": -1,
"arrayDimensions": null,
"accessLevel": 3,
"userAccessLevel": 3,
"minimumSamplingInterval": 100,
"children": []
}
]
Notes
- Leave
startNodeIdempty to browse from the server's root folder. - The node IDs returned in
nodeIdcan be used directly asdeviceIdwhen configuring Properties, Events, and Commands. - Browsing a large address space reads the metadata of every discovered variable, so it can take longer to complete than a regular read; prefer starting from a specific
startNodeIdwhen only part of the tree is relevant.
Send Command#
The driver extensions have no method to send a command. OPC UA Method calls are supported through the regular Command flow defined in the Driver Definition (configure the parent object with the objectDeviceId extended parameter described above).
Remarks/Behavior#
- When an event has more than one property with the
isTriggerflag: - It will be triggered every time any of the properties value changes.
- The value of the other properties will be requested at that time.
-
It is possible to have multiple triggers with the same set values (because they have not changed). If this behavior is not intended, separate into multiple events each one with it's own trigger set.
-
When an event has no property with the
isTriggerflag, it will never be triggered. - In an event of type
Subscription, the first value that the server reports for a property after the event is subscribed does not trigger the event. - A read of a node that does not exist does not fail: the property has no value, and its
originalValue.qualityisBad. - An event registered with
connect.iot.driver.opcua.registerEventis not subscribed again after a reconnect. To restore it, unregister it and register it again. - A command passes its parameters to the method as input arguments by position, not by name, so the command parameters must follow the order of the method's input arguments.
- When using events of type
Eventthe property device id must follow the format<Namespace>:<name>(ex:2:Temperature) - When it´s necessary to convert a value from
Int64/UInt64toLong,IntegerorDecimal, a warning is displayed stating that a conversion was made on the value, that could cause a loss in the accuracy. When the accurate value is needed, the RawValue should be used to be processed. - Starting with version 12.0.0,
originalValuealso reports the tag'squality(Good/Uncertain/Bad, derived from the OPC UA status code) andstatusCode/timestamps, for both property reads and event occurrences — see OriginalValue. Custom scripts that destructureoriginalValueexpecting onlydataType/arrayType/valuecontinue to work, since the existing fields are unchanged, but should be updated to make use of the newqualityfield where relevant. - After nodejs@>20.11.1 and nodejs@>18.19.1 the Rsa15 Security Policy has been deprecated.
- To store OPC UA certificates (trusted, rejected, and own) in a custom location, set the NODEOPCUA_PKI environment variable. This overrides the default directory and ensures the driver uses a consistent PKI path across all environments.
- Example:
export NODEOPCUA_PKI=/opt/iot/opcua-pki
- Example:
Transparent Redundancy#
This driver only supports transparent redundancy.
In transparent redundancy, failover between servers is invisible to the client. If a server becomes unavailable, the client is not notified and does not need to take any action.
Servers in a transparent redundancy group appear as a single OPC UA server. They typically share the same Server URI and Endpoint URL, often exposed through a virtual IP address or a network load balancer. From the client’s perspective, there is only one server connection, and no special failover logic is required.
Failover is handled by the underlying infrastructure or cluster. When the primary server fails, the system automatically directs client communications to a standby server, allowing data exchange to continue without interruption.
Because this approach shifts complexity to the server and network layers, it requires a robust clustering setup. This usually includes a virtual IP address or network load balancer in front of multiple servers, as well as mechanisms to keep servers’ state in sync.
File Transfer#
The driver supports OPC UA file transfer operations through dedicated workflow tasks. Each task wraps the corresponding connect.iot.driver.opcua.{createDirectory,createFile,writeFile,readFile} transport topic so workflows do not need to call them directly.
- Create Directory task — creates a new directory on the OPC UA server.
- Create File task — creates a new file node.
- Write File task — uploads file content to the server.
- Read File task — downloads file content from the server (supports both streaming to a local directory and inline raw output).
Refer to the OPC UA task documentation for setting and parameter details.