IOhub Development - Introduction


We will develop an application from scratch, deploy it on Docker Hub, and use it inside IOhubTM.

In the following walkthrough, we will use Javascript as a programming language and Node.js as a runtime. However, any programming stack you select will work.

Use case definition

We are going to create a storage component, saving the data to an on-premise CSV file.

This new component will be used inside an application in IOhubTM, just like any other existing component.

The application will:

  • read data from a Modbus plc
  • save the data to a CSV file

For simplicity, we will use a Modbus slave simulator in place of a real PLC. And we will also use a random number generator to fill the Modbus PLC with fake data.

Once you have completed the walkthrough, feel free to remove both the Modbus slave simulator and the random data generator, and use your real PLC IP address and port.

IDE Setup

You can use any IDE or editor you like. We suggest installing and using Visual Studio Code because of its many features (available on Linux, macOS, Windows), and integration with the most common languages and file formats.

Please refer to the Development setup section if you need to configure your programming environment.

As we will be using Javascript and Node.js, we suggest that you install the following additional extensions in VSCode:

  • Prettier
  • ES Lint
  • Docker
  • Remote - WSL (if running on Windows 10 with WSL2)

Prepare Docker Environment

The images in use by IOhubTM are containers hosted on public registries are used as any other images present on Docker Hub or other registries.

Using the existing IOhubTM images, we can set up a locally running copy of IOhubTM, acting as your local IOhubTM hardware.

Initial application

Our initial local setup will reproduce the following environment:

Modbus Generator

  • Modbus PLC is a Modbus PLC simulator. If you want to use a real PLC, just remove the modbus-slave service from the docker-compose.yml below.
  • Random Generator is a random value generator, filling holding register from 1 to 20. If you want to use real PLC data, just remove the rnd-generator service from the docker-compose.yml below.
  • Modbus Driver is the ezvpn-fld-modbus container, exchanging data between the PLC and the MQTT broker.
  • MQTT Broker is the ezvpn-mqtt IOhubTM internal broker.

Final result

We are going to have, at the end of this walkthrough, the following environment:

Modbus Generator

CSV File Writer is an application we will develop together, producing a CSV file for all the values changing on the plc. The resulting image demo-csv-writer will be usable directly in IOhubTM.

If you need a CSV storage/logger, the image is a production-grade application with the same functionalities as the image we are going to build, including log rotation.

Start docker-compose

We are now ready to work on a new application.

  • Create a new folder for your project: mkdir demo-csv-writer
  • Open VSCode on the new folder (cd demo-csv-writer && code .)

If you are working on Windows 10 with WSL2, do not create the working folder in the Windows share (/mnt/c).

  • Create a docker-compose.yml file with the following content
version: "3.8"

        image: oitc/modbus-server
            - "5020"
            - iohub-mqtt

        image: ""
            MODBUS_HOST: "modbus-slave"
            MODBUS_PORT: 5020
            MODBUS_SLEEP: 2000
            - modbus-slave

        image: ""
            - "1883:1883"
            - "1883"

        image: ""
            MQTT_HOST: "iohub-mqtt"
            MQTT_PORT: 1883
            FLD_CFG: |-
                    "plcs": [
                            "name": "devplc",
                            "ip": "modbus-slave",
                            "port": 5020
                    "addresses": [
                            "name": "rnd1",
                            "target": "devplc",
                            "type": "16unsignedintLE",
                            "address": 5
                            "name": "rnd2",
                            "target": "devplc",
                            "type": "16unsignedintLE",
                            "address": 13
                            "name": "rnd3",
                            "target": "devplc",
                            "type": "16unsignedintLE",
                            "address": 20
                            "name": "nornd",
                            "target": "devplc",
                            "type": "16unsignedintLE",
                            "address": 21
                    "pollings": [
                            "every": "1s 500ms",
                            "addresses": ["rnd1", "rnd2", "rnd3", "nornd"]
                    "writables": ["nornd"]
            - modbus-slave
            - iohub-mqtt
  • Open a new terminal in VSCode (or open a new WSL2 console and cd to your project folder)
  • In the terminal, start your environment
docker-compose -p iohubdev up

You now have an IOhubTM development environment up & running. Refer to the ezvpn-fld-modbus documentation if you need to understand the value of the FLD_CFG environment variable.

If you get an error regarding docker-credential-desktop.exe failing, you can manually link the executable to the WSL2 file system.

sudo ln -s /mnt/c/Program Files/Docker/Docker/resources/bin/docker-credential-desktop.exe /usr/local/bin/.

Watch MQTT messages

While your application is running, you can start a subscription in another terminal for the MQTT Broker to monitor all the changing values, by launching

docker exec -it iohubdev_iohub-mqtt_1 mosquitto_sub \
    -v -t 'fld/+/r/#'

If you are already running a Docker command inside a terminal, click the + button in the terminal window to open a new one

You should see something like this in your console

fld/modbus/r/rnd1 {"value":6315,"ts":1604097306515}
fld/modbus/r/rnd2 {"value":505,"ts":1604097306519}
fld/modbus/r/rnd3 {"value":15,"ts":1604097306522}
fld/modbus/r/rnd1 {"value":6320,"ts":1604097309548}
fld/modbus/r/rnd2 {"value":506,"ts":1604097309552}
fld/modbus/r/rnd1 {"value":6325,"ts":1604097311059}

You can also send the a value (23 in the example below) to the plc, to the writable address nornd, through the MQTT Broker, in the following way:

docker exec -it iohubdev_iohub-mqtt_1 mosquitto_pub \
    -t 'fld/modbus/w/nornd' -m '23'

You will see the new value showing up in the terminal running the mosquitto_sub command.

Take note the w in place of the r in the topic name.