Modbus integration with AWS IoT


Industrial automation is not new. But it is time to create a better modbus iot integration for a deeper understanding of your data and also manage your devices in a efficient way.

In the Industry 3.0, devices are managed in an isolated fashion. From late 1960s to early 19790 PLCs , DCS and few more ways to automate the simple process came into existence. In addition, With the introduction of Modbus, programmers were able to mange them and automate a few of the process in a localized fashion.

But these machines are still managed in the same isolated way in many industrial sectors. However It is time to integrate them for a more productive outcome. Over the last few months, we tried writing some code to integrate data received from Modbus/RTU into MQTT Broker. The integration was very simple and straight. But One of the major challenge is the association of the data we read from the Modbus Server to the actual spec as provided by the Manufacturer.

About Modbus

Modbus Protocol, a messaging structure developed by Modicon in 1979, is used to establish master-slave/client-server communication between smart devices. It is a de facto standard, truly open and the most widely used network protocol in the field of industrial automation. It has been implemented by hundreds of vendors on thousands of different devices to transfer discrete/analogue I/O and route data between control devices.

Modbus is used in multiple master-slave applications to:

  • Monitor and program devices
  • Communicate between smart devices, sensors and instruments
  • Monitor field devices using PCs and HMIs

Modbus is used in a number of smart manufacturing solutions. But Modbus is not only an industrial protocol. Its benefits are also evident in the building, agriculture, transportation and energy applications.


We have used Raspberry Pi 3B+ for creating the gateway to gather the Modbus data and push data to AWS IoT Core (MQTT Broker).

Modbus Client

We used the pymodbus python implementation of the Modbus IoT gateway. This will query the data from the Modbus RTU PLC. Using the pymodbus implementation, you will be able to read and write data into the the memory registers & Coils of your equipment.

So let’s see how are we gonna implement the system.

Creating Thing on AWS IoT Core:

  • Create an object in the AWS IoT console via “Manage→Things” and then “Register a thing”.

  • Name your thing and Click “Next”

  • You will be given 4 options for creation of certificates. You can bring your own certificates or you can download certificates created by AWS IoT’s Certificate Authority.

  • For this tutorial, we are downloading certificate created by AWS IoT’s Certificate Authority. Download all certificates also private key and Amazon Root CA. This will be used to authenticate with AWS IoT MQTT Broker. Click on “Activate” to acitivate those certificates.

  • After that, click on attach policy. You will have to attach policy which is used to restrict the thing to perform task associated with that only. For this tutorial we are going to attach unrestricted policy, which states that the thing will be able to send data on any topic.
  • { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "iot:*", "Resource": "*" } ] }

Now we are done with IoT Core setup. We can now proceed to setup our gateway.

Setting up Raspberry Pi

We can follow this link for setting up raspberry pi.

Once raspberry pi is booted up, we can now start coding our gateway to make it communicate to PLC and send data to AWS IoT Core.

Hardware Components

  • Raspberry Pi 3 B+
  • 16GB SD Card
  • 2Amp Power Adapter
  • USB to RS232 converter
  • Delta PLC with RS232 COM Port

Hardware Setup

  • Power on Raspberry Pi with Power Adapter.
  • Connect PLC with Raspberry Pi through USB to RS232 Converter. This converter is used to interface raspberry pi with RS232 protocol.

Software Setup.

Lets implement ModbusRead class which will be used to read data from modbus registers:

from pymodbus.client.sync import ModbusSerialClient import time import logging logging.basicConfig(level=logging.ERROR, format='%(asctime)s %(name)s %(levelname)s: %(message)s') logger = logging.getLogger(__name__) METHOD = "ascii" PORT = “/dev/ttyUSB0” STOPBITS = 1 BYTESIZE = 7 PARITY = 'E' BAUDRATE = 9600 TIMEOUT = 1 COUNTER = 0 class ModbusRead(): def __init__(self): self.params = dict( method=METHOD, port=PORT, stopbits=STOPBITS, bytesize=BYTESIZE, parity=PARITY, baudrate=BAUDRATE, timeout=TIMEOUT ) self.client = ModbusSerialClient(**self.params) def connect(self): try: self.client.connect() return True except: logger.error("--------No PLC connected-------") return False def disconnect(self): try: self.client.close() except: logger.error("Exception in disconnect Block of Modbus Read code") def read_reg(self, address, count): try: val = "" val = self.client.read_holding_registers(address, count, unit=0x01) value = val.registers[0] return value except: return 9999 def get_Register_Values(self, address): try: value = self.read_reg(address, 1) return value except: logger.error("Exception Occured in get Registers Value Block") def put_Register_Value(self, address, value): try: self.client.write_register(address, value) return True except Exception as e: logger.error("Exception Occured in Put Registers Value Block") logger.error(e) return False

Lets understand above code.

  • From pymodbus.client.sync import ModbusSerialClient this imports pymodbus library in our code. Since we are going to use ModbusRTU, we are importing ModbusSerialClient.
  • While creating object for the class ModbusRead, the __init__ block will be executed which will set the connection to PLC.
  • Connect() function establishes connection with Modbus Master.
  • To Write Register to modbus register, we have to call function put_Register_value(address,value).
    For e.g., put_Register_value(2025,10) This will write register 2025 with 10 value.
  • To Read register value from Modbus Registers, we need to call function read_reg(address,count).
    For e.g., read_reg(2024,5) 2024 is register address. 5 means read 5 registers starting from register 2025

Implementing MQTT Client

  • Installing the dependencies on raspberry pi: sudo apt-get install paho-mqtt
  • Copy above created certificates on Raspberry Pi in this project directory.
  • Creating python script to read data from PLC and sending it to AWS IoT Core.
  • from __future__ import print_function import sys import ssl import time import datetime import logging, traceback import paho.mqtt.client as mqtt from ModbusRead import * IoT_protocol_name = "x-amzn-mqtt-ca" aws_iot_endpoint = "AWS_IoT_ENDPOINT_HERE" # <random>.iot.<region> url = "https://{}".format(aws_iot_endpoint) ca = "YOUR/ROOT/CA/PATH" cert = "YOUR/DEVICE/CERT/PATH" private = "YOUR/DEVICE/KEY/PATH" topic = "test/PLCData" logger = logging.getLogger() logger.setLevel(logging.DEBUG) handler = logging.StreamHandler(sys.stdout) log_format = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(log_format) logger.addHandler(handler) mbRead = ModbusRead() mbRead.connect() def ssl_alpn(): try: #debug print opnessl version"open ssl version:{}".format(ssl.OPENSSL_VERSION)) ssl_context = ssl.create_default_context() ssl_context.set_alpn_protocols([IoT_protocol_name]) ssl_context.load_verify_locations(cafile=ca) ssl_context.load_cert_chain(certfile=cert, keyfile=private) return ssl_context except Exception as e: print("exception ssl_alpn()") raise e if __name__ == '__main__': try: mqttc = mqtt.Client() ssl_context= ssl_alpn() mqttc.tls_set_context(context=ssl_context)"start connect") mqttc.connect(aws_iot_endpoint, port=443)"connect success") mqttc.loop_start() while True: now ='%Y-%m-%dT%H:%M:%S')"try to publish:{}".format(now)) reg = mbRead.read_reg(2024,1) mqttc.publish(topic, reg) time.sleep(1) except Exception as e: logger.error("exception main()") logger.error("e obj:{}".format(vars(e))) logger.error("message:{}".format(e.message)) traceback.print_exc(file=sys.stdout)
  • Run the code : python
  • The code will start connect to PLC and then start sending data to IoT Core.

  • Now you can write a rule which will forward the data to any storage service i.e., S3, DynamoDB, Kinesis, one can write query which can directly trigger SNS Notification, et


In this post, I’ve shown you how to connect your IoT devices to AWS IoT Core over MQTT on port 443 and sniffing data from PLC. If you have had a constraint in the past to open port 8883 in your corporate firewalls, you can now use a standard port for HTTPS traffic (443) to send your messages over MQTT to AWS IoT Core endpoint

We can help transform your business and make it future-ready

Get expert assistance with our wide range of Cloud and IoT offerings.