Skip to content

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 None
Sign
SignAndEncrypt
None Message Security Mode for communication between client and server.
securityPolicy Enum None
Basic128
Basic192
Basic256
Basic256Sha256
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 Scalar
Array
Matrix
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 Subscription
Event
Alarm
Subscription Type of alarm to register
Subscription- Notification when at least one node changes value
Event - Notification when event occurs
Alarm - 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 Driver and Subscribe 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

PropertyValue[] connect.iot.driver.opcua.getPropertiesValues(request Property[])

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

boolean connect.iot.driver.opcua.setPropertiesValues(request PropertyValuePair[])

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:

true

Register Event#

Notifies the protocol driver to raise the occurrences of a specific event when it occurs.

Signature

void connect.iot.driver.opcua.registerEvent(data: RegisterHandler)

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

void connect.iot.driver.opcua.unregisterEvent(data: UnregisterHandler)

Example

{
   "event":{
      "name":"CustomEvent"
   }
}

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

  1. Declare the structure on the driver by calling addCustomDataTypes once 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.
  2. 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 / deviceType set to Custom.
    • Extended parameter customDataType set to the same name you registered (without the DataType suffix — the driver appends it automatically when querying the server).
  3. 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 ExtensionObject matching the field order, and exchanges it with the server.

Signature

{ success: boolean } connect.iot.driver.opcua.addCustomDataTypes(data: CustomDataType[])

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:

{ "success": true }

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 fields must match the field order declared on the server; field-by-name encoding is not used.
  • customDataTypeName is required whenever dataType.Name is "Custom" and ignored otherwise.
  • arrayDimensions applies 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

NodeInfo[] connect.iot.driver.opcua.browse(request: { startNodeId?: string })

Example

Request connect.iot.driver.opcua.browse, starting from the server's root:

{}

Or from a specific node:

{
  "startNodeId": "ns=2;s=Demo.Static.Scalar"
}

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 startNodeId empty to browse from the server's root folder.
  • The node IDs returned in nodeId can be used directly as deviceId when 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 startNodeId when 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 isTrigger flag:
  • 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 isTrigger flag, 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.quality is Bad.
  • An event registered with connect.iot.driver.opcua.registerEvent is 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 Event the property device id must follow the format <Namespace>:<name> (ex: 2:Temperature)
  • When it´s necessary to convert a value from Int64/UInt64 to Long, Integer or Decimal, 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, originalValue also reports the tag's quality (Good/Uncertain/Bad, derived from the OPC UA status code) and statusCode/timestamps, for both property reads and event occurrences — see OriginalValue. Custom scripts that destructure originalValue expecting only dataType/arrayType/value continue to work, since the existing fields are unchanged, but should be updated to make use of the new quality field 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

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.

Diagram about OPC-UA transparency

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.