Modbus to MQTT
Note: This tutorial uses the iQunet Industrial Edge Server
[link].
A demo gateway endpoint is provided for the purpose of this guide.
Mission: Publish Modbus over MQTT, plot in Python
In this tutorial, you will learn how to:
- Connect a Modbus-RTU motor drive to the iQunet Industrial Edge Server.
- Understand the steps how sensor data is stored in the local OPC-UA database.
- Next, publish this sensor data in realtime to an MQTT broker.
- Subscribe to the MQTT broker using Python for post-processing and visualization.
Terminology
Modbus is a wired communication protocol for industrial automation and data exchange between devices like sensors and PLC controllers. Visit modbus.org.
- Modbus-RTU: Uses serial wired communication (RS-232/RS-485) for short-distance, point-to-point, or multi-drop connections.
- Modbus-TCP: Runs over Ethernet, using TCP/IP for integration with modern IT systems. A gateway is used to convert between Modbus-RTU and -TCP.
MQTT (Message Queuing Telemetry Transport) is a lightweight, publish-subscribe network protocol designed for resource-constrained devices and low-bandwidth, high-latency networks. It is widely used in internet-oriented services, particularly for IoT applications. In contrast to OPC-UA, the payload format is not part of the specification. Visit mqtt.org.
Typical Modbus-to-MQTT Information Flow
In a typical Modbus/MQTT monitoring setup, an industrial device, — such as a motor drive — is connected to a Modbus-TCP gateway via an RS-485 serial interface. The gateway converts between the synchronous Modbus-RTU protocol and the asynchronous Modbus-TCP Ethernet network protocol. This allows the use of standard networking equipment. Some devices natively support Modbus-TCP, which eliminates the need for a gateway.
A Modbus-TCP master actively polls connected devices to extract data, which is subsequently decoded from binary to a user-friendly format, typically JSON. This JSON data is then published to an MQTT platform, either on-premises or cloud-based, such as the HiveMQ MQTT broker.
An MQTT subscriber retrieves the data from the broker and stores it in a database. This database then serves as a data source for real-time or historical operational dashboards, providing the user with insight into emerging faults, predictive maintenance or energy efficiency.
Configuring the Modbus-TCP master and decoding data demand deep understanding of
each device’s register map, requiring significant expertise and effort with every
new device integration.
An example of such a manual setup procedure can be found here
hivemq.com .
The required expertise and effort may lead to a higher TCO and project delays
than initially projected, making a ready-to-use solution an attractive and efficient
alternative.
A Single-Board Modbus-to-MQTT Setup
The Modbus-TCP gateway, Modbus master and MQTT publisher can all be integrated in
a single board computer (SBC), such as is the case for the iQunet Edge Server
[link].
Data collected via Modbus is first decoded and stored in the on-board OPC-UA historian
database.
This data can be routed (LAN/VPN) and accessed with the embedded dashboard
webserver or via various protocols, including OPC-UA, GraphQL or CSV. In a
second step, realtime updates in the OPC-UA server can be linked to the
onboard MQTT publisher for integration with third-party IoT platforms.
In this tutorial, the red route indicated in figure 2 will be used. The motor drive is connected via an FTDI-232R galvanically isolated interface to the iQunet Server, which polls the drive at a configurable interval. The payload is then decoded, unpacked and written to the built-in database.
Publishing to MQTT
When a new measurement is written into the database, the OPC-UA server triggers
a callback that activates the MQTT publisher. The new measurement is first
converted into JSON format and published to the MQTT broker.
The topic of the MQTT message is derived from the path of the corresponding
data point in the OPC-UA tree (figure 3).
In this tutorial, a Python program will then subscribe to the specified topic on the MQTT broker and display the incoming data on a real-time updated graph.
Motor Drive + Modbus Hardware Setup
Figure 4 shows the minimal setup required to publish real-time motor drive data via MQTT. This configuration includes the inverter drive itself, an (optional) Ethernet network switch, the iQunet server, and a mobile access point, which serves as a temporary placeholder for, for example, a company VLAN. The Modbus-RTU to TCP gateway is omitted because the drive depicted in Figure 4 is equipped with a Modbus-TCP communication module.
With this setup, MQTT data can be transmitted to either a private or a public internet-based MQTT broker.
For the remainder of this tutorial, the Invertek Optidrive E3 will be used.
The Optidrive inverter supports both Modbus-RTU and Modbus-TCP via an additional
module. However, because the Profinet IO module occupies the sole available slot
for PLC drive control, the on-board Modbus-RTU is used. A separate RS-485 to USB
converter is used for monitoring the drive parameters in read-only mode.
Scanning for Modbus Devices
After the hardware is connected and powered up as shown in figure 4, the Optidrive E3 must be added to the list of monitored devices in the iQunet server software.
The first step involves activating both the Modbus-TCP and the Modbus-RTU modules in the dashboard of the iQunet server. For this, click the Config button in the menu bar, as shown in Figure 6.
- The Modbus-TCP software module provides Modbus master functionality, which includes probing the connected devices at regular intervals and forwarding data to the OPC-UA historian database.
- The Modbus-RTU module enables the drivers for the FTDI FT232R USB-to-serial interface and serves as a gateway for the Modbus master to communicate with RTU devices.
After both Modbus modules are enabled, the Home menu will display a new Modbus Master and Gateway node in the OPC-UA device list.
The Modbus Master allows scanning a single IP or subnet for known devices (figure 7):
The scanner is also capable of scanning not only for Modbus slave devices on the local network (Ethernet or WiFi) but also for remote devices via any configured Wireguard VPN endpoint on the iQunet server.
The Modbus-RTU gateway operates similarly, scanning all slave Unit IDs within the configured range, as illustrated in Figure 8. Because Modbus-RTU is a synchronous serial protocol, parallel scanning is not feasible. Therefore, probing the full range of all slave IDs from 1 to 247 may take a minute or two.
Auto-Detection of Modbus Devices
When the iQunet server detects a Modbus slave device on the network, it attempts to identify the specifics of the slave for auto-configuration purposes. This process serves two main objectives:
- Device Identification: A unique device MAC address is derived from the device serial number. This allows for flexible remapping of IP addresses or Unit (Slave) IDs, with monitoring data tied to the device serial rather than the location in the network or the MAC address of the Modbus network card.
- Device Type Detection: This is crucial for automatic payload decoding. iQunet provides customized payload decoders upon request. The configuration for the end-user is reduced to setting some basic parameters such as the polling interval and the selection of data to be published to MQTT. This simplifies the commissioning of new devices in the field, reducing the setup time to a matter of minutes.
In Figure 8 below, the Optidrive E3 inverter is detected on the local Modbus-RTU gateway at Unit ID 1. The dashboard automatically adapts to the device specifics and displays the most important configuration highlights of the device, such as the serial number, hardware model, and current configuration (e.g., closed-loop vector control mode):
In addition to the static configuration, real-time drive and historical parameters are also available in the dashboard. The generic motor drive section (Figure 9) displays the most common parameters.
While the dashboard provides a graphical summary of the drive status, much more detailed information about drive parameters and historical logs can be accessed by directly browsing the OPC-UA node tree of the internal OPC-UA server. To do this, click the OPC-UA icon in the left menu:
The built-in OPC-UA browser allows immediate export to Google Sheets or a plain CSV file. Additionally, as shown in Figure 10, any variable node of the OPC-UA tree can be enabled for publication via MQTT to an external broker.
Direct Access of Modbus Data via OPC-UA
All historical Modbus data is stored in the OPC-UA database of the iQunet server. It can either be browsed via the dashboard of the web interface, or through third-party OPC-UA clients such as UaExpert, a popular OPC-UA client developed by Unified Automation [unified-automation.com].
Figure 11 shows the configuration of UaExpert to connect to the iQunet OPC-UA server at address 192.168.10.101, port 4840. Both encrypted and non-encrypted connections are supported.
When the UaExpert client is successfully connected to the iQunet OPC-UA server, direct access is provided to all real-time motor drive parameters, metadata and historical values as stored in the local database.
OPC-UA vs MQTT: Payload Format and Data Types
MQTT is a widely used protocol for large-scale, multi-site IoT deployments. However, it does not define a specific data format. JSON is commonly used as the payload encoding, but it lacks data type definitions for the payload, and thus needs careful manual coordination between data publishers and subscribers to ensure mutual compatibility.
On the other hand, OPC-UA is highly suitable for low latency networks, real-time data exchange, and has well-defined object type formatting. It allows OPC-UA clients to autonomously resolve data type definitions without user intervention. However, the protocol is currently not widely used in internet-oriented big data platforms.
For maximum flexibility, the iQunet server supports both protocols and employs the following strategy to link the OPC-UA core system to the MQTT subsystem:
- The OPC-UA node tree path is used as the topic for publishing data via MQTT. A user-definable “Root/” can be prepended to the path (default: server name).
- The JSON payload consists of a dictionary dump, which includes the numerical, string, or array data, and the source- and serverTimestamp in ISO-8601 format.
Enabling the MQTT Subsystem for the iQunet Server
Enabling the MQTT subsystem for the iQunet server is straightforward.
- Click on the MQTT icon in the left-hand menu.
- Fill in the MQTT broker host details and credentials.
Optionally, set a custom Client ID (also serves as the root of the topics). - If supported by the broker, select the TLS encryption option.
Finally, toggle the button “MQTT OFF” to “MQTT ON”. - If the ONLINE icon is highlighted, the setup is complete and operational.
The MQTT setup menu also displays a list of all published nodes and their respective topics. To add a node to this list, browse to the desired node in the OPC-UA tree and click the MQTT “publish” button.
Testing the MQTT Setup
To verify the MQTT setup, a web-based MQTT client will be connected to the broker to subscribe to the published data. Since browsers do not support raw TCP sockets, the WebSocket port of the broker will be used.
First, open the HiveMQ MQTT Client [hivemq.com], and setup the broker host and TLS WebSocket port as below. Then click connect.
- host: broker.hivemq.com
- port: 8884 (wss://)
Next, click “Add New Topic Subscription” and choose the topic to subscribe to. Use a multilevel wildcard (#) to subscribe to all topics at once. More information here [hivemq.com]
For example, if the topic published to by the iQunet Server is
SERN-dca632xxxxxx/Objects/b1:dd:1f:e9/inverterTemperature
,
then subscribe to
SERN-dca632xxxxxx/#
to capture all messages from this server.
If the configuration is correct, JSON packets will start arriving as soon as they are published by the iQunet Server!
Subscribing to MQTT and Plotting with Python
This section provides Python boilerplate code to demonstrate how to subscribe to the MQTT broker, receive data from the iQunet server, and visualize this data in real-time.
The Paho MQTT client is used for handling MQTT communication, and Matplotlib is used for plotting the data.
-
MQTT Client Configuration: The Paho MQTT client connects to the HiveMQ broker at
broker.hivemq.com
on TCP/TLS port8883
and subscribes to the specified topic where the iQunet server publishes data. -
Message Handling: When a message is received, the
on_message
callback parses the JSON payload and appends the data to an in-memorycache
. Thedata_event
signals to the plotting thread that new data is available. -
Plotting: The
update_plot
function retrieves data from the cache, extracts timestamps and values, and updates the plot. TheFuncAnimation
class from Matplotlib refreshes the plot every second.
from collections import deque
from datetime import datetime
from functools import partial
import json
import threading
import time
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import paho.mqtt.client as mqtt
# MQTT setup
BROKER = 'broker.hivemq.com'
PORT = 8883
TOPIC = 'SERN-dca632c03aee/Objects/b1:dd:1f:e9/inverterTemperature'
# In-memory storage
cache = deque(maxlen=1024)
# Event to trigger plot updates
data_event = threading.Event()
def on_connect(client, userdata, flags, rc, properties):
print(f'Connected with result code {rc}')
assert rc == 0
client.subscribe(TOPIC)
def on_message(client, userdata, message):
payload = json.loads(message.payload)
cache.append(payload)
data_event.set()
def start_mqtt_loop():
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.tls_set()
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, PORT, keepalive=60)
client.loop_start()
return client
def update_plot(frame, ax):
if not data_event.is_set():
time.sleep(1)
return
c = list(cache)
x = [datetime.fromisoformat(pl['SourceTimestamp']) for pl in c]
y = [pl['Value'] for pl in c]
ax.clear()
ax.plot(x, y, marker='o')
ax.set_ylim(20, 70)
plt.xticks(rotation=45, ha='right')
plt.subplots_adjust(bottom=0.30)
plt.title('Inverter Temperature')
plt.xlabel('Timestamp')
plt.ylabel('degC')
data_event.clear()
if __name__ == '__main__':
client = start_mqtt_loop()
try:
fig, ax = plt.subplots()
func = partial(update_plot, ax=ax)
ani = FuncAnimation(fig, func, interval=1000, cache_frame_data=False)
plt.show()
finally:
client.disconnect()
Conclusion
In this tutorial, we’ve demonstrated how to integrate a Modbus-RTU motor drive with the iQunet Industrial Edge Server, store sensor data in a local OPC-UA database, publish this sensor data to an MQTT broker, and finally visualize the data using Python for a real-time monitoring setup.
Beyond the basics covered in this guide, iQunet offers extensive capabilities for more advanced data processing tasks. These include handling complex datasets like vibration data, implementing machine learning techniques for predictive maintenance, and enabling custom software adaptations for specific industrial needs.
For further exploration and support, check out our documentation, get new ideas from some case studies or reach out to our support team. Happy data monitoring!