ezvpn-fld-opcua is a service (provided as Docker container image) acting as a broker between multiple OPC-UA devices and one MQTT broker, which:

  • reads data from OPC-UA devices and publishes it to MQTT topics
  • subscribes to MQTT topics and writes incoming messages to OPC-UA devices

OPC-UA Schema

Using ezvpn-fld-opcua, allows you to:

  • write to your OPC-UA device by sending text messages to MQTT.
  • read from your devices by subscribing to MQTT topics.

We support communication with and without password authentication. Authentication using certificates is not supported.

NodeID Discovery

To use ezvpn-fld-opcua you will need to know the OPC-UA NodeID. If you don't know the Node ID, we suggest using the following software to discover it.

OPC-UA Commander

UA Expert

How to use it

ezvpn-fld-opcua is a Docker container image pre-configured to communicate with ezvpn-mqtt. In case you need to use it with your MQTT broker, see the section regarding customization below.

You can use it directly in IOhubTM for final production, or on your PC for testing purposes. The Docker image is provided in the following, with all the environment variables used by the container.

If used with ezvpn-mqtt, only one environment variable must be provided: FLD_CFG.

FLD_CFG is a string representing a JSON object, describing the OPC-UA devices' configuration, addresses, polling, subscription, and writable addresses.

Below is a working example representing an oversimplified case with:

  • two machines (extruder and pelletizer)
  • two thermocouples (one on the extruder tempextruder, one on the pelletizer tempdie), read-only
  • one pressure sensor (pressure), read-only
  • one temperature setpoint (tempSP), read-write (the writing permission depends on OPC-UA configuration on the device)
    "servers": [
            "name": "extruder",
            "protocol": "opc.tcp",
            "host": "",
            "port": 4840,
            "addresses": [
                    "name": "tempextruder",
                    "nodeId": "ns=6;s=::Main:tempextruder"
                    "name": "tempSP",
                    "nodeId": "ns=6;s=::Main:tempSP"
            "sampling": {
                "every": "500ms",
                "addresses": ["tempextruder", "tempSP"]
            "name": "pelletizer",
            "protocol": "opc.tcp",
            "host": "",
            "port": 4840,
            "addresses": [
                    "name": "tempdie",
                    "nodeId": "ns=6;s=::Main:tankDisplayLevel"
                    "name": "pressure",
                    "nodeId": "ns=6;s=::Main:pressure"
            "sampling": {
                "every": "50ms",
                "addresses": ["tempdie", "pressure"]

Mapping configuration (FLD_CFG)

The JSON object has 1 array field:

    "servers": []

servers (required): contains the list of the OPC-UA servers.


servers is an array of objects, representing the available OPC-UA server. The servers array cannot be empty.

Each server is represented by the following objects:

    "name": "<device name>",
    "protocol": "<protocol name>",
    "host": "<OPC-UA server address>",
    "port": <OPC-UA port>,
    "url": "<OPC-UA base url>",
    "authentication": { "username": "<username>", "password": "<password>"},
    "addresses": [],
    "sampling": {
        "every": "<frequency>",
        "cron": "<frequency time>",
        "timezone": "<timezone>",
        "addresses": [<addresses list>],
        "sendAlways": <polling or subscription>,
        "sendBatch": <batch or single>,
        "disableSingle": <send or not single measurements>}

name and host are required.

protocol valid values are opc.tcp or http

port OPC-UA server port, required

url base url, optional

authentication (optional) username and password for OPC-UA authentication


addresses is an array of objects, representing the available OPC-UA variables. The addresses array cannot be empty.

Each address is represented by the following object:

    "name": "<symbolic address name>",
    "nodeId": "<NodeID address>",
    "datatype": "<data type>"

name: measurement name

nodeId: OPC-UA NodeID address

datatype: (optional) accepted values are Boolean, Byte, Double, Float, Int16, Int32, Int64, SByte, UInt16, UInt32, UInt64, String. When accessing other datatypes the behavior is undefined.

We suggest skipping the datatype property because it is automatically inferred. It becomes only necessary if you need to write a value in a NodeID without read permission (therefore disabling automatic data type detection).

When writing to a boolean address, the MQTT payloads true and 1 are both considered as a true boolean value.


sampling represents a list of subscriptions on the OPC-UA devices. The sampling array cannot be empty.

Each sampling is related to each OPC-UA device.

This is the structure of a sampling object:

    "every": "<frequency>",
    "cron": "<frequency time>",
    "timezone": "<timezone>",
    "addresses": [<addresses list>],
    "sendAlways": <polling or subscription>,
    "sendBatch": <batch or single>,
    "disableSingle": <send or not single measurements>

The data reading frequency is specified using the alternative every or cron syntax.

every or cron cannot both be defined in the same polling definition, choose which type of polling frequency should be used.

  • every: can be supplied in : human readable time format

  • cron: can be supplied in : cron time format

  • timezone: an optional timezone, see the list, to use for the cron expression. If not defined UTC is used.

  • addresses: is an array of plcs names, in string format

  • sendAlways: is a boolean optional property. If absent or false, only changed values from previous polling cycles are sent to MQTT, otherwise all values are always sent.

At the first polling cycle, all values are sent, even if sendAlways is false.

sendBatch is a boolean optional property. Defaults to false. If true, all the measurements are sent in aggregated form to the MQTT topic specified on FROM_DEVICE_AGGREGATED_TOPIC_PREFIX environment variable.

The payload is a JSON with 2 properties on default topic aggregate/<protocol>:

    "ts": 1612043704952,
    "data": [
        { "address": "tempextruder", "value": 115, "ts": 1612043702457 },
        { "address": "tempdie", "value": 120, "ts": 1612043702457 }
  • ts value is the time at which the payload has been sent.
  • data is an array of all the measures to be sent on each polling cycle. Each array of data is a measurement as sent in single form.

The sendAlways setting affects both the single data and the aggregated data.

disableSingle is a boolean optional property. Defaults to false. If true the measurements are not sent to the MQTT topic specified on TO_DEVICE_TOPIC_PREFIX environment variable.

Environment variables

When you start the ezvpn-fld-opcua image, you can adjust the instance's configuration by passing one or more environment variables to the docker run command.

  • FLD_CFG: OPC-UA mapping description, as documented above. Required.
  • MQTT_HOST: IP address / host name of the MQTT broker. Defaults to (In IOhubTM the variable is set to ezpn-mqtt value)
  • MQTT_PORT: MQTT broker port. Defaults to 1883.
  • FROM_DEVICE_TOPIC_PREFIX: MQTT topic used to publish values read from devices, defaults to fld/opcua/r/.
  • TO_DEVICE_TOPIC_PREFIX: MQTT topic subscribed to get values to write on devices, defaults to fld/opcua/w/.
  • FROM_DEVICE_AGGREGATED_TOPIC_PREFIX: MQTT topic use to publish values read from devices, defaults to aggregate/opcua. Used if sendBatch is set to true.
  • NO_RETAIN: if true values are sent to MQTT_HOST without the retain flag; defaults to false.

With NO_RETAIN set to false, each client that subscribes to a topic pattern receives the retained message immediately after they subscribe.

The broker stores only one retained message per topic.

Examples in EXCH

Read a PLC address

Read an address from the PLC as a 16-bit value and write its value to the key-value DB as Celsius temperature

writeField "db-key-value" "temp" call(f_to_c, ${_v})

Write a value to the PLC

Write a 0-1000 Celsius temperature from the key-value DB to a PLC address, as a 16bit value.

writeField "opcua" "plc.setpoint" call(scale, 0, 1000, 0, 65535, db-key-value/temp)

Docker Container details

Image: us-central1-docker.pkg.dev/ez-shared/iohub/iohub-fld-opcua

Supported architecture: amd64



*Value 1 with Boolean variables is considered as true

  • Parallel writes fix
  • Timezone in cron
  • String datatype support added
  • OPC-UA library upgraded
  • Better management when writing a high number of values
  • Smaller image
  • Cron expression added
  • Fixed sendAlways, was sending all fields even if in not included in sampling list
  • FROM_DEVICE_AGGREGATED_TOPIC_PREFIX Environment variable added
  • NO_RETAIN Environment variable added
  • First release