--- alias: user-guide-driver-opcua tags: - connect iot description: "This documentation details the OPC UA Driver for connecting to industrial automation equipment, supporting data types, protocol parameters, and driver" --- # 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](#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. `""` for a 1D array of length ``. `","` 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*** ```ts PropertyValue[] connect.iot.driver.opcua.getPropertiesValues(request Property[]) ``` ***Example*** Request `connect.iot.driver.opcua.getPropertiesValues` ```json [ { "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: ```json [ { "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*** ```ts boolean connect.iot.driver.opcua.setPropertiesValues(request PropertyValuePair[]) ``` ***Example*** Request `connect.iot.driver.opcua.setPropertiesValues` ```json [ { "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: ```json true ``` #### Register Event Notifies the protocol driver to raise the occurrences of a specific event when it occurs. ***Signature*** ```ts 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*** ``` json { "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*** ```ts void connect.iot.driver.opcua.unregisterEvent(data: UnregisterHandler) ``` ***Example*** ```json { "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*** ```ts { 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`: ```json [ { "name": "TemperatureReading", "description": "Temperature value with unit", "fields": [ { "name": "value", "dataType": { "Name": "Double" }, "isOptional": false }, { "name": "unit", "dataType": { "Name": "String" }, "isOptional": false } ] } ] ``` Reply: ```json { "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. ```json [ { "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, `""` for a fixed-length 1D array, and `","` 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*** ```ts NodeInfo[] connect.iot.driver.opcua.browse(request: { startNodeId?: string }) ``` ***Example*** Request `connect.iot.driver.opcua.browse`, starting from the server's root: ```json {} ``` Or from a specific node: ```json { "startNodeId": "ns=2;s=Demo.Static.Scalar" } ``` Reply: ```json [ { "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 `:` (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](#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](diagrams/opcua_transparency.drawio.svg) 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.