ModbusTCPServer

ModbusTCPServer implements the Modbus TCP server. ModbusTCPServer support function codes 1 (Read Coils), 2 (Read Discrete Inputs), 3 (Read Holding Registers), 4 (Read Input Registers), 5 (Write Single Coil), 6 (Write Single Holding Register), 15 (Write Multiple Coils), and 16 (Write Multiple Holding Registers).

UiFlow2 Example

CoreS3 TCP Server

Open the cores3_tcp_server_example.m5f2 project in UiFlow2.

This example demonstrates how to use ModbusTCPServer to implement a Modbus TCP server.

UiFlow2 Code Block:

cores3_tcp_server_example.png

Example output:

None

MicroPython Example

CoreS3 TCP Server

This example demonstrates how to use ModbusTCPServer to implement a Modbus TCP server.

MicroPython Code Block:

  1# SPDX-FileCopyrightText: 2024 M5Stack Technology CO LTD
  2#
  3# SPDX-License-Identifier: MIT
  4import os, sys, io
  5import M5
  6from M5 import *
  7import modbus
  8import network
  9
 10
 11label0 = None
 12label1 = None
 13label3 = None
 14label2 = None
 15wlan_sta = None
 16modbustcpserver_0 = None
 17
 18
 19starting_register4 = None
 20slave_list4 = None
 21starting_register1 = None
 22slave_list1 = None
 23starting_register2 = None
 24slave_list2 = None
 25register2 = None
 26slave_value2 = None
 27starting_register3 = None
 28slave_list3 = None
 29starting_register6 = None
 30slave_list6 = None
 31register1 = None
 32slave_value1 = None
 33starting_register5 = None
 34slave_list5 = None
 35
 36
 37def modbus_read_input_registers_cb(args):
 38    global \
 39        label0, \
 40        label1, \
 41        label3, \
 42        label2, \
 43        wlan_sta, \
 44        modbustcpserver_0, \
 45        starting_register4, \
 46        slave_list4, \
 47        starting_register1, \
 48        slave_list1, \
 49        starting_register2, \
 50        slave_list2, \
 51        register2, \
 52        slave_value2, \
 53        starting_register3, \
 54        slave_list3, \
 55        starting_register6, \
 56        slave_list6, \
 57        register1, \
 58        slave_value1, \
 59        starting_register5, \
 60        slave_list5
 61    _, starting_register4, slave_list4 = args
 62    label0.setText(str("read input register"))
 63    label1.setText(str(starting_register4))
 64    label2.setText(str(slave_list4))
 65
 66
 67def modbus_read_coils_cb(args):
 68    global \
 69        label0, \
 70        label1, \
 71        label3, \
 72        label2, \
 73        wlan_sta, \
 74        modbustcpserver_0, \
 75        starting_register4, \
 76        slave_list4, \
 77        starting_register1, \
 78        slave_list1, \
 79        starting_register2, \
 80        slave_list2, \
 81        register2, \
 82        slave_value2, \
 83        starting_register3, \
 84        slave_list3, \
 85        starting_register6, \
 86        slave_list6, \
 87        register1, \
 88        slave_value1, \
 89        starting_register5, \
 90        slave_list5
 91    _, starting_register1, slave_list1 = args
 92    label0.setText(str("read coils"))
 93    label1.setText(str(starting_register1))
 94    label2.setText(str(slave_list1))
 95
 96
 97def modbus_read_discrete_inputs_cb(args):
 98    global \
 99        label0, \
100        label1, \
101        label3, \
102        label2, \
103        wlan_sta, \
104        modbustcpserver_0, \
105        starting_register4, \
106        slave_list4, \
107        starting_register1, \
108        slave_list1, \
109        starting_register2, \
110        slave_list2, \
111        register2, \
112        slave_value2, \
113        starting_register3, \
114        slave_list3, \
115        starting_register6, \
116        slave_list6, \
117        register1, \
118        slave_value1, \
119        starting_register5, \
120        slave_list5
121    _, starting_register2, slave_list2 = args
122    label0.setText(str("read  discrete input"))
123    label1.setText(str(starting_register2))
124    label2.setText(str(slave_list2))
125
126
127def modbus_write_single_registers_cb(args):
128    global \
129        label0, \
130        label1, \
131        label3, \
132        label2, \
133        wlan_sta, \
134        modbustcpserver_0, \
135        starting_register4, \
136        slave_list4, \
137        starting_register1, \
138        slave_list1, \
139        starting_register2, \
140        slave_list2, \
141        register2, \
142        slave_value2, \
143        starting_register3, \
144        slave_list3, \
145        starting_register6, \
146        slave_list6, \
147        register1, \
148        slave_value1, \
149        starting_register5, \
150        slave_list5
151    _, register2, slave_value2 = args
152    label0.setText(str("write single registers"))
153    label1.setText(str(register2))
154    label2.setText(str(slave_value2))
155
156
157def modbus_read_holding_registers_cb(args):
158    global \
159        label0, \
160        label1, \
161        label3, \
162        label2, \
163        wlan_sta, \
164        modbustcpserver_0, \
165        starting_register4, \
166        slave_list4, \
167        starting_register1, \
168        slave_list1, \
169        starting_register2, \
170        slave_list2, \
171        register2, \
172        slave_value2, \
173        starting_register3, \
174        slave_list3, \
175        starting_register6, \
176        slave_list6, \
177        register1, \
178        slave_value1, \
179        starting_register5, \
180        slave_list5
181    _, starting_register3, slave_list3 = args
182    label0.setText(str("read holding register"))
183    label1.setText(str(starting_register3))
184    label2.setText(str(slave_list3))
185
186
187def modbus_write_multiple_registers_cb(args):
188    global \
189        label0, \
190        label1, \
191        label3, \
192        label2, \
193        wlan_sta, \
194        modbustcpserver_0, \
195        starting_register4, \
196        slave_list4, \
197        starting_register1, \
198        slave_list1, \
199        starting_register2, \
200        slave_list2, \
201        register2, \
202        slave_value2, \
203        starting_register3, \
204        slave_list3, \
205        starting_register6, \
206        slave_list6, \
207        register1, \
208        slave_value1, \
209        starting_register5, \
210        slave_list5
211    _, starting_register6, slave_list6 = args
212    label0.setText(str("write multiple registers"))
213    label1.setText(str(slave_list6))
214    label2.setText(str(slave_list6))
215
216
217def modbus_write_single_coil_cb(args):
218    global \
219        label0, \
220        label1, \
221        label3, \
222        label2, \
223        wlan_sta, \
224        modbustcpserver_0, \
225        starting_register4, \
226        slave_list4, \
227        starting_register1, \
228        slave_list1, \
229        starting_register2, \
230        slave_list2, \
231        register2, \
232        slave_value2, \
233        starting_register3, \
234        slave_list3, \
235        starting_register6, \
236        slave_list6, \
237        register1, \
238        slave_value1, \
239        starting_register5, \
240        slave_list5
241    _, register1, slave_value1 = args
242    label0.setText(str("write single coil"))
243    label1.setText(str(register1))
244    label2.setText(str(slave_value1))
245
246
247def modbus_write_multiple_coils_cb(args):
248    global \
249        label0, \
250        label1, \
251        label3, \
252        label2, \
253        wlan_sta, \
254        modbustcpserver_0, \
255        starting_register4, \
256        slave_list4, \
257        starting_register1, \
258        slave_list1, \
259        starting_register2, \
260        slave_list2, \
261        register2, \
262        slave_value2, \
263        starting_register3, \
264        slave_list3, \
265        starting_register6, \
266        slave_list6, \
267        register1, \
268        slave_value1, \
269        starting_register5, \
270        slave_list5
271    _, starting_register5, slave_list5 = args
272    label0.setText(str("write multiple coils"))
273    label0.setText(str(slave_list5))
274    label0.setText(str(slave_list5))
275
276
277def setup():
278    global \
279        label0, \
280        label1, \
281        label3, \
282        label2, \
283        wlan_sta, \
284        modbustcpserver_0, \
285        starting_register4, \
286        slave_list4, \
287        starting_register1, \
288        slave_list1, \
289        starting_register2, \
290        slave_list2, \
291        register2, \
292        slave_value2, \
293        starting_register3, \
294        slave_list3, \
295        starting_register6, \
296        slave_list6, \
297        register1, \
298        slave_value1, \
299        starting_register5, \
300        slave_list5
301
302    M5.begin()
303    Widgets.setRotation(1)
304    Widgets.fillScreen(0x222222)
305    label0 = Widgets.Label("label0", 61, 54, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
306    label1 = Widgets.Label("label1", 58, 94, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
307    label3 = Widgets.Label("label3", 53, 11, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
308    label2 = Widgets.Label("label2", 58, 133, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
309
310    wlan_sta = network.WLAN(network.STA_IF)
311    while not (wlan_sta.isconnected()):
312        pass
313    label3.setText(str(wlan_sta.ifconfig()[0]))
314    modbustcpserver_0 = modbus.ModbusTCPServer("0.0.0.0", 5000, device_address=1, verbose=False)
315    modbustcpserver_0.set_callback(
316        modbustcpserver_0.READ_INPUT_REGISTERS_EVENT, modbus_read_input_registers_cb
317    )
318    modbustcpserver_0.set_callback(modbustcpserver_0.READ_COILS_EVENT, modbus_read_coils_cb)
319    modbustcpserver_0.set_callback(
320        modbustcpserver_0.READ_DISCRETE_INPUTS_EVENT, modbus_read_discrete_inputs_cb
321    )
322    modbustcpserver_0.set_callback(
323        modbustcpserver_0.WRITE_SINGLE_REGISTER_EVENT, modbus_write_single_registers_cb
324    )
325    modbustcpserver_0.set_callback(
326        modbustcpserver_0.READ_HOLDING_REGISTERS_EVENT, modbus_read_holding_registers_cb
327    )
328    modbustcpserver_0.set_callback(
329        modbustcpserver_0.WRITE_MULTIPLE_REGISTERS_EVENT, modbus_write_multiple_registers_cb
330    )
331    modbustcpserver_0.set_callback(
332        modbustcpserver_0.WRITE_SINGLE_COIL_EVENT, modbus_write_single_coil_cb
333    )
334    modbustcpserver_0.set_callback(
335        modbustcpserver_0.WRITE_MULTIPLE_COILS_EVENT, modbus_write_multiple_coils_cb
336    )
337    modbustcpserver_0.add_coil(1000, True)
338    modbustcpserver_0.add_coil(1001, False)
339    modbustcpserver_0.add_coil(1002, True)
340    modbustcpserver_0.add_coil(1003, False)
341    modbustcpserver_0.add_coil(1004, True)
342    modbustcpserver_0.add_discrete_input(1000, True)
343    modbustcpserver_0.add_discrete_input(1001, False)
344    modbustcpserver_0.add_discrete_input(1002, True)
345    modbustcpserver_0.add_discrete_input(1003, False)
346    modbustcpserver_0.add_discrete_input(1004, True)
347    modbustcpserver_0.add_holding_register(1000, 0x0102)
348    modbustcpserver_0.add_holding_register(1001, 0x0304)
349    modbustcpserver_0.add_holding_register(1002, 0x0506)
350    modbustcpserver_0.add_holding_register(1003, 0x0708)
351    modbustcpserver_0.add_holding_register(1004, 0x090A)
352    modbustcpserver_0.add_input_register(1000, 0x0102)
353    modbustcpserver_0.add_input_register(1001, 0x0304)
354    modbustcpserver_0.add_input_register(1002, 0x0506)
355    modbustcpserver_0.add_input_register(1003, 0x0708)
356    modbustcpserver_0.add_input_register(1004, 0x090A)
357    modbustcpserver_0.start()
358
359
360def loop():
361    global \
362        label0, \
363        label1, \
364        label3, \
365        label2, \
366        wlan_sta, \
367        modbustcpserver_0, \
368        starting_register4, \
369        slave_list4, \
370        starting_register1, \
371        slave_list1, \
372        starting_register2, \
373        slave_list2, \
374        register2, \
375        slave_value2, \
376        starting_register3, \
377        slave_list3, \
378        starting_register6, \
379        slave_list6, \
380        register1, \
381        slave_value1, \
382        starting_register5, \
383        slave_list5
384    M5.update()
385    modbustcpserver_0.tick()
386
387
388if __name__ == "__main__":
389    try:
390        setup()
391        while True:
392            loop()
393    except (Exception, KeyboardInterrupt) as e:
394        try:
395            from utility import print_error_msg
396
397            print_error_msg(e)
398        except ImportError:
399            print("please update to latest firmware")

Example output:

None

API

ModbusTCPServer

class modbus.ModbusTCPServer(host: str, port: int = 502, verbose: bool = False)

Create a ModbusTCPServer object.

Parameters:
  • host (str) – Hostname or IP address.

  • port (int) – Port number.

  • verbose (bool) – Verbose mode.

UiFlow2 Code Block:

init.png

MicroPython Code Block:

from modbus import ModbusTCPServer
server = ModbusTCPServer('0.0.0.0', 502)
start() None

Start the Modbus RTU slave.

UiFlow2 Code Block:

start.png

MicroPython Code Block:

server.start()
stop() None

Stop the Modbus RTU slave.

UiFlow2 Code Block:

stop.png

MicroPython Code Block:

server.stop()
add_coil(register: int, value: bool) None

Add a coil to the modbus register dictionary.

Parameters:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is True or False.

UiFlow2 Code Block:

add_coil.png

MicroPython Code Block:

server.add_coil(0, False)
add_discrete_input(register: int, value: bool) None

Add a discrete input to the modbus register dictionary.

Parameters:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is True or False.

UiFlow2 Code Block:

add_discrete_input.png

MicroPython Code Block:

server.add_discrete_input(0, False)
add_holding_register(register: int, value: int) None

Add a holding register to the modbus register dictionary.

Parameters:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

add_holding_register.png

MicroPython Code Block:

server.add_holding_register(0, 0)
add_input_register(register: int, value: int) None

Add an input register to the modbus register dictionary.

Parameters:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to add. The value is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

add_input_register.png

MicroPython Code Block:

server.add_input_register(0, 0)
remove_coil(register: int) None

Remove a coil from the modbus register dictionary.

Parameters:

register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

remove_coil.png

MicroPython Code Block:

server.remove_coil(0)
remove_discrete_input(register: int) None

Remove a discrete input from the modbus register dictionary.

Parameters:

register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

remove_discrete_input.png

MicroPython Code Block:

server.remove_discrete_input(0)
remove_holding_register(register: int) None

Remove a holding register from the modbus register dictionary.

Parameters:

register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

remove_holding_register.png

MicroPython Code Block:

server.remove_holding_register(0)
remove_input_register(register: int) None

Remove an input register from the modbus register dictionary.

Parameters:

register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

remove_input_register.png

MicroPython Code Block:

server.remove_input_register(0)
get_coil(register: int) bool

Get the coil value.

Parameters:

register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

Returns:

The value of the coil.

UiFlow2 Code Block:

get_coil.png

MicroPython Code Block:

server.get_coil(0)
get_discrete_input(register: int) bool

Get the discrete input value.

Parameters:

register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

Returns:

The value of the discrete input.

UiFlow2 Code Block:

get_discrete_input.png

MicroPython Code Block:

server.get_discrete_input(0)
get_holding_register(register: int) int

Get the holding register value.

Parameters:

register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

Returns:

The value of the holding register.

UiFlow2 Code Block:

get_holding_register.png

MicroPython Code Block:

server.get_holding_register(0)
get_input_register(register: int) int

Get the input register value.

Parameters:

register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

Returns:

The value of the input register.

UiFlow2 Code Block:

get_input_register.png

MicroPython Code Block:

server.get_input_register(0)
set_coil(register: int, value: bool) None

Set the coil value.

Parameters:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is True or False.

UiFlow2 Code Block:

set_coil.png

MicroPython Code Block:

server.set_coil(0, False)
set_multi_coils(register: int, value: list) None

Set the multi coils value.

Parameters:
  • register (int) – address of the coils. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of True or False.

UiFlow2 Code Block:

set_multi_coils.png

MicroPython Code Block:

server.set_multi_coils(0, [False, True])
set_discrete_input(register: int, value: bool) None

Set the discrete input value.

Parameters:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is True or False.

UiFlow2 Code Block:

set_discrete_input.png

MicroPython Code Block:

server.set_discrete_input(0, False)
set_multi_discrete_input(register: int, value: list) None

Set the multi discrete inputs value.

Parameters:
  • register (int) – address of the discrete inputs. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of True or False.

UiFlow2 Code Block:

set_multi_discrete_input.png

MicroPython Code Block:

server.set_multi_discrete_input(0, [False, True])
set_holding_register(register: int, value: int) None

Set the holding register value.

Parameters:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

set_holding_register.png

MicroPython Code Block:

server.set_holding_register(0, 0)
set_multi_holding_register(register: int, value: list) None

Set the multi holding registers value.

Parameters:
  • register (int) – address of the holding registers. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of 0x0000 to 0xFFFF.

UiFlow2 Code Block:

set_multi_holding_register.png

MicroPython Code Block:

server.set_multi_holding_register(0, [0, 1])
set_input_register(register: int, value: int) None

Set the input register value.

Parameters:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (int) – Value to set. The value is 0x0000 to 0xFFFF.

UiFlow2 Code Block:

set_input_register.png

MicroPython Code Block:

server.set_input_register(0, 0)
set_multi_input_register(register: int, value: list) None

Set the multi input registers value.

Parameters:
  • register (int) – address of the input registers. The address is 0x0000 to 0xFFFF.

  • value (list) – Values to set. The value is a list of 0x0000 to 0xFFFF.

UiFlow2 Code Block:

set_multi_input_register.png

MicroPython Code Block:

server.set_multi_input_register(0, [0, 1])
tick() None

Modbus RTU slave tick function. This function should be called in the main loop.

UiFlow2 Code Block:

tick.png

MicroPython Code Block:

server.tick()
set_callback(func_code: int, handler) None

Set the callback function for the function code.

Parameters:
  • func_code (int) – Function code. The function code is 1 to 6, 15, 16. the symbol is defined in the modbus.ModbusTCPServer (*_EVENT etc.).

  • handler – Callback function.

UiFlow2 Code Block:

read_coils_callback.png

read_discrete_inputs_callback.png

read_holding_registers_callback.png

read_input_registers_callback.png

write_multiple_coils_callback.png

write_multiple_registers_callback.png

write_single_coil_callback.png

write_single_register_callback.png

MicroPython Code Block:

def cb(arg):
    pass
server.set_callback(1, cb)
READ_COILS_EVENT

Function code 1 (Read Coils).

READ_DISCRETE_INPUTS_EVENT

Function code 2 (Read Discrete Inputs).

READ_HOLDING_REGISTERS_EVENT

Function code 3 (Read Holding Registers).

READ_INPUT_REGISTERS_EVENT

Function code 4 (Read Input Registers).

WRITE_SINGLE_COIL_EVENT

Function code 5 (Write Single Coil).

WRITE_SINGLE_HOLDING_REGISTER_EVENT

Function code 6 (Write Single Holding Register).

WRITE_MULTIPLE_COILS_EVENT

Function code 15 (Write Multiple Coils).

WRITE_MULTIPLE_HOLDING_REGISTERS_EVENT

Function code 16 (Write Multiple Holding Registers).