Introduction: ESP32 Modbus Master TCP

About: Enthusiast of Industrial IoT applications

In this class, you will program ESP32 processor to be Modbus TCP Master.

We will use two devices, which contain this processor: Moduino ESP32 and Pycom. Both devices are running in MicroPytthon environment. Our Modbus Slave will be PC computer with Modbus simulator software running on it.

You will need:

  • Moduino ESP32 or Moduino Pycom device (check this website to find out more about Moduino ESP32 device and this to check Pycom device)
  • PC with Linux operating system
  • RS-232/RS-485 port in your computer or USB to RS-232/RS-485 converter

Step 1: Download and Start Modbus TCP Slave Simulator

Download Modbus Slave simulator from http://www.modbusdriver.com/diagslave.html.
Then open downloaded archive and unpack version for Linux operating system.

Run the program from console with -p <port> argument:

./diagslave -p <port>

<port> is a port where the Modbus Slave server will work. For Modbus protocol it is by default 502, but you can use another one.

In Linux ports below 1024 cannot be used by programs run from regular user (not root privileges).

Remember what port you are using. This value will be necessary later.

Step 2: Prepare Your Computer to Connect to the Device

You will need some programs to make connection to the device and send files to it.

Install Python environment and pip (if you don't have it):

apt-get install python3
apt-get install python3-dev 
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
python3 get-pip.py

Install picocom:

apt-get install picocom

This program is needed to connect to the device and execute commands on it.
Install mpfshell:

pip install mpfshell

This program allows you to send files to the device.

You can also install it form sources. Refer this page: https://github.com/wendlers/mpfshell

Step 3: Prepare Device and Connect to It

To connect Moduino or Pycom device to PC you need RS-232/RS-485 port or converter. Check version of your device (which port type it uses) and find appropriate port or converter.

  1. Connect device to PC
  2. Then connect power supply to it

Connect device to PC and then connect power supply to it. You can also connect ethernet cable to Moduino ESP32 (if it has that port).

Connection should be like in photos above.

Find path for port, which is used for device connection.It can be for example: /dev/ttyS1, /dev/ttyUSB0.

For usb converters, path will contain USB word.

You can connect to device with picocom program:

picocom /dev/ttyUSB0 -b 115200

Command prompt of device looks similar to one of these images below.

Moduino ESP32: See here

Moduino Pycom: See here

Step 4: Upload Modbus Master Library

https://github.com/pycom/pycom-modbus/To communicate with Modbus Slave you need appropriate library. Libraries for Pycom aren't compatible with Moduino. Check instructions which comply to your device.

Close picocom before sending files: press Ctrl+A and then Ctrl+X keys.

uModBus library for Moduino ESP32 bases on pycom-modbus library for Moduino Pycom. It is modified to work on regular ESP32 device. It also has additional close() methods for connector classes.

1) Moduino ESP32

Download library from https://github.com/techbase123/micropython-modbus. Unpack archive and send all 4 files to Moduino device.

Use mpfshell to upload them. Run this program in directory with that files.

Connect to device by executing: THIS

ttyUSB0 is a name of serial port where device is connected.

Change directory to /flash/lib with command:

cd /flash/lib

Put all files with commands:

put uModBusConst.py
put uModBusFunctions.py
put uModBusTCP.py
put uModBusSerial.py 

EXAMPLE

Then exit console with exit command and restart the device with Reset button.

2) Moduino Pycom

Download library from https://github.com/pycom/pycom-modbus/. Unpack archive and send content of uModbus directory to the device.Use mpfshell to upload them. Run this program in directory with that files.

Connect to device by executing:

open ttyUSB0

ttyUSB0 is a name of serial port where device is connected.

Change directory to /flash/lib, create uModbus directory and enter it with commands:

cd /flash/lib<br>md uModbus <br>cd uModbus

Put all files with commands:

put const.py
put functions.py
put tcp.py
put serial.py

Then exit console with exit command and restart the device with Reset button.

EXAMPLE

Step 5: Connect to the Network

Commands to establish connection differ between Moduino and Pycom.

Connect to device with picocom to execute appropriate commands. You can connect Moduino device to network by wire or wireless. Following examples assumes that your network has working DHCP server.

In other case, device won't get IP address.WiFi support is available in every Moduino. Ethernet port is an option and not all devices have it.

1) Moduino ESP32

Connecting to WiFi

Execute following commands on the device:

from netWiFi import netWiFi
wifi = netWiFi(netWiFi.WIFI_STA, 'ESSID', 'PASS')
wifi.start()

Replace ESSID with name of your WiFi network, and PASS with password of it.

After some time after executing start() you should get an IP address which was assigned to your device.

Connecting to Ethernet network

Connect device to wired network with ethernet cable.

Then execute following commands:

from netETH import netETH
eth = netETH()
eth.start()

After some time after executing start() you should get IP address which was assigned to your device.

2) Moduino Pycom

Connect to WiFi

Execute following commands on the device:

from network import WLAN
wlan = WLAN(mode=WLAN.STA) nets = wlan.scan()
for net in nets:
if net.ssid == 'ESSID':
print('Network found!')
wlan.connect(net.ssid, auth=(net.sec, 'PASS'), timeout=5000)
while not wlan.isconnected():
machine.idle()
print('WLAN connection succeeded!')
break

Replace ESSID with name of your WiFi network, and PASS with password of it.

Step 6: Initialize Communication With Modbus Slave

Modbus Master libraries are similar for both devices

They vary in initialization.

1) Initialize uModBus on Moduino ESP32

Execute:

from uModBusTCP import uModBusTCP as TCP

2) Initialize uModBus on Pycom

Execute:

from uModbus.tcp import TCP

Open connection

Then open connection with:

modbus=TCP('IP', PORT, 60)

where:

  • IP - ip address of your PC with Modbus Slave simulator
  • PORT - port of Modbus Slave
  • 60 is a timeout

If following error occurs during executing reading/writing commands: EXAMPLE

execute:

  • for Moduino ESP32:
modbus.close()
  • for Moduino Pycom:
modbus._sock.close()

and then recreate connection:

modbus=TCP('IP', PORT, 60)

This is important to close socket before recreating connection.
Device has constrainted amount of available socket connection.

Step 7: Read and Write Registers

Modbus support several functions to read and write registers.

uModBus library has method for each function:

  1. read_coils
  2. read_discrete_inputs
  3. read_holding_registers
  4. read_input_registers
  5. write_single_coil
  6. write_single_register

Firstly, lets write some values.

1) Write coils (func: 5)

Write 1 value to 200 register from slave 1:

modbus.write_single_coil(1, 200, 0xFF00)

First argument is for slave id, in our case 1.

Second is register number and thirs is a value. For 1 you have to put 0xFF00 here. Write 0 to 201 register from slave 1:

modbus.write_single_coil(1, 201, 0)

This method allows writting only boolean values: 0 or 1.

2) Write registers (func: 6)

Now write some integer values to several registers.

Write signed 111 value to register 100 from slave 1:

modbus.write_single_register(1, 100, 111, True)

First argument is slave id, second register number and third is new value.
Last argument defines if value should be set as signed number. Default value for it is True. You don't need to set it.

Write signed -457 value to 101 register from slave 1:

modbus.write_single_register(1, 101, -457)

Write not signed 50 value to 100 register from slave 3:

modbus.write_single_register(3, 100, 50, False)

This method allows writting integer values to single register.

Single register can contain 16 bit values.

Method returns True is input value is valid and False if not. Value is written even if is invalid (too big for register)

3) Read coils/discrete inputs

Now lets read written boolean values. To read register with function 1 read coil, execute:

modbus.read_coils(slaveId, register, count)[0:count]

To read register with function 2 read discrete input, execute:

modbus.read_discrete_inputs(slaveId, register, count)[0:count]

where:

  • slave-id - id of virtual slave (Slave simulator accepts all valid ids)
  • register - register number for reading
  • count - amount of registers to be read (put desired amount in both places)

These methods return array with boolean values. Each value correspond to each register.

The fragment: [0:count] is needed, because this method returns more values, than count. It returns always amount of values which is divisible by 8. Additional values are False and don't corresponds to any register.

Read our boolean values with both methods:

modbus.read_coils(1,200,2)[0:2]
modbus.read_discrete_inputs(1,200,2)[0:2]

Result will be like these: EXAMPLE

True refers to 1 value, False to 0.

4) Read registers

Now read values from registers written with 6 function.

To read registers with function 3 read holding registers, execute:

modbus.read_holding_registers(slaveId, register, count, signed=True)

To read registers with function 4 read input registers, execute:

modbus.read_input_registers(slaveId, register, count, signed=True)

where:

  • slave-id - id of virtual slave
  • register - register number for reading
  • count - amount of registers to be read
  • signed - indicates if read values should be treated as signed numbers or not. Default state: True

Return value is a tuple with desired amount of registers.

Read registers set in previous point:

modbus.read_holding_registers(1,100,2,True)
modbus.read_input_registers(1,100,2,True)
modbus.read_holding_registers(3,100,1,False)
modbus.read_input_registers(3,100,1,False)

Results should look like in this screenshot: EXAMPLE

In the next lesson you will learn how to create Modbus RTU Master on ESP32-enabled device.