umodbus
– MODBUS protocol implementation¶
Currently implemented are:
MODBUS RTU master
MODBUS TCP slave
Example:
import umodbus
# Talk to the MODBUS RTU slave with address 42
# connected to UART bus 1 at 115200 baud
mdev = umodbus.ModbusRtuSlave(1, 115200, 42)
# Read the first holding register
mdev.read_register(0)
# Read the first input register
mdev.read_register(0, fun=4)
class ModbusException¶
Parent class for MODBUS-related errors
class ModbusSlaveException¶
MODBUS slave device exception. Details are in class memebers code and message.
class ModbusSlave¶
Parent class for remote MODBUS slave device implementations. Use an instance of one of derivative classes (or implement your own) in order to talk to a MODBUS slave device (with MicroPython board being the master).
Constructors¶
- class umodbus.ModbusSlave(address, debug=False)¶
Construct a remote MODBUS slave device instance with the given address. If debug is
True
, print extended debug information to the REPL
Methods¶
Each method may raise a ValueError, TypeError, or ModbusSlaveException in case of invalid input parameters or an error thrown by the slave device
- ModbusSlave.read_bit(registeraddress, fun=2)¶
Read one discrete input (if
fun == 2
), or coil (iffun == 1
) in a remote device.registeraddress - starting address.
fun - MODBUS function code
This function code is used to read from 1 to 2000 contiguous status of coils in a remote device. Returns an integer value of the coil read (0 or 1)
- ModbusSlave.write_bit(registeraddress, value, fun=5)¶
Write a single output (coil) in a remote device.
registeraddress - starting address
value - output value (will be converted to 0 or 1 via
bool(...)
)fun - MODBUS function code
This function code is used to write a single output to either ON or OFF in a remote device. Returns the value written (as reported by the slave device).
- ModbusSlave.read_bits(registeraddress, count, fun=2)¶
Read count discrete inputs (if
fun == 2
), or coils (iffun == 1
) in a remote deviceregisteraddress - starting address
count - quantity of coils / inputs
fun - MODBUS function code
This function code is used to read from 1 to 2000 contiguous status of coils in a remote device. Returns an array of integer values of the coils (inputs) read. Each value is 0 or 1.
- ModbusSlave.write_bits(registeraddress, values)¶
Write a sequence of coils in a remote device (function code 15).
registeraddress - starting address
values - an array of coil states.
This function code is used to force each coil in a sequence of coils to either ON or OFF in a remote device. Each value in the array will be converted to 0 or 1 via
bool(...)
. ReturnsTrue
if the operation has succeeded.
- ModbusSlave.read_register(registeraddress, fun=3)¶
Read a single holding (function code 3), or input (function code 4) register in a remote device.
registeraddress - starting address
fun - MODBUS function code
This function code is used to read the contents of a contiguous block of holding (input) registers in a remote device. Returns the received value (integer).
- ModbusSlave.write_register(registeraddress, value)¶
Write a single holding register in a remote device (function code 6)
registeraddress - stating address
value - register value (will be converted to int)
This function code is used to write a single holding register in a remote device. Returns the value written (as reported by the slave device).
- ModbusSlave.read_registers(regiteraddress, count, fun=3)¶
Read count holding (or input) registers in a remote device.
registeraddress - starting address
count - quantity of registers
fun - MODBUS function code
This function code is used to read the contents of a contiguous block of holding (input) registers in a remote device. Returns a list of the received values (integers).
- ModbusSlave.write_registers(registeraddress, values)¶
Write a block of contiguous registers in a remote device (function code 16)
registeraddress - starting address
values - an array of register values (each one will be converted to int)
This function code is used to write a block of contiguous registers (1 to 123 registers) in a remote device. Returns
True
if the operation has succeeded.
- ModbusSlave.read_string(registeraddress, size, fun=3, pad=None)¶
Read an ASCII string from a remote device. Each 16bit register (holding or input if
fun == 3
orfun == 4
respectively) in the remote device is interpreted as two ASCII characters. If pad is notNone
, the returned string is assumed to be padded with this character, and at most 1 pad byte may be removed from the received data.registeraddress - starting address
size - number of ASCII characters to read (
(size + 1) // 2
registers will be read).fun - MODBUS function code
pad - data padding character
The corresponding fmt value in the
ModbusSlave.request
call is “string”.
- ModbusSlave.write_string(registeraddress, data, pad=' ')¶
Write an ASCII string to a remote device. Each 16bit holding register in the remote device is interpreted as two ASCII characters. The data transmitted will be padded to an even number of characters using pad character.
registeraddress - starting address
data - string to be written
pad - padding character
The corresponding fmt value in the
ModbusSlave.request
call is “string”.
- ModbusSlave.request(fun, registeraddress, tx=None, count=None, fmt=None, pad=' ')¶
Generic method used to communicate with the device. All the above methods call this one with the appropriate arguments
fun - function code (ref. to the MODBUS application protocol)
registeraddress - starting address
tx - data to be transmitted accoring to the fmt parameter
count - number of entities (coils, registers) to be received from the remote device
fmt - data format string (ref.
ModbusSlave.SUPPORTED_FUNCTIONS
)pad - string padding character
Refer to the MODBUS application protocol for the list of function codes and their meaning, and
ModbusSlave.SUPPORTED_FUNCTIONS
for a list of supported function codes and accepted data types.The value returned depends on the function code and the fmt paraterer. May be a value, a list of values, a string, or
True
.
- ModbusSlave._compose(fun, registeraddress, tx, count, fmt, pad=' ')¶
Implement this method in a derivative class. Must return an APDU to be sent to a remote device
fun - function code
registeraddress - starting address
tx - data to be transmitted (may be None)
count - number of entities to be received (may be 0 or None)
fmt - data format string
pad - string padding character.
Most of the work is done by the
umodbus.modbus_pdu_compose
function. One just has to call it with the appropriate arguments.The default implementation raises a
RuntimeError
.
- ModbusSlave._rxtx(adpu, fun, count, fmt)¶
Implement this method in a derivative class. This function must do the low-level work of sending the APDU to the remote device via the communication channel and reading the remote device response. Raise an error is the data could not be written of the remote device did not repond. Return the data received from the remote device (as a
bytes
object)apdu - the data to be sent (as returned by the
ModbusSlave._compose
method).fun - function code
count - number of entities to be received (may be 0 or None)
fmt - data format string
The default implementation raises a
RuntimeError
.
- ModbusSlave._process(apdu, fun, registeraddress, count, fmt, pad=None)¶
Implement this method in a derivative class. This function must process the APDU received from the remote device and return the recived reply according to the fmt parameter.
apdu - the data received from the remote device
fun - function code
registeraddress - starting address
fmt - data format string
pad - string padding character.
Most of the work is done by the
umodbus.modbus_pdu_parse
function. One just has to call it with the appropriate arguments.The default implementation raises a
RuntimeError
.
Constants¶
- ModbusSlave.SUPPORTED_FUNCTIONS¶
A dictionary mapping modbus function numbers (int) to payload types (string):
{ 1: 'bits' 2: 'bits', 3: 'registers', 4: 'registers', 5: 'bit', 6: 'register', 15: 'bits', 16: 'registers' }
class ModbusDevice¶
Parent class for MODBUS slave device implementations Use an instance of one of derivative classes (or implement your own) in order to become a MODBUS slave device.
Constructors¶
- class umodbus.ModbusDevice(address, debug=False)¶
Construct a MODBUS slave device instance with the given address. If debug is
True
, print extended debug information to the REPL
Methods¶
- ModbusDevice.set_callback(cls, cb):
The cb function will be called when a remote master requests a read or write operation.
Read operation:
data = cb(registeraddress)
Write opetation:
cb(registeraddress, value)
The callback must not be a coroutine and for the read operation must return the requested data or raise an exception (preferably a ModbusSlaveException with an appropriate code), for the write operation must accept a register address and a value and raise an exception if the operation cannot be completed. Values are passed as is (ex. coil values are 0x0000 and 0xFF00).
cls - function class (ref:
ModbusDevice.TYPES
)cb - the callback function
If
None
is passed, the corresponding operation will raise the ‘Illegal function’ MODBUS error.
- ModbusDevice.get_callback(cls)¶
Return the currently installed callback.
cls - function class (ref:
ModbusDevice.TYPES
)
- ModbusDevice.process(pdu)¶
Processes the request pdu (w/o the TCP header), calls the appropriate callback (if set), and returns the reply PDU.
pdu - the request PDU (bytes object)
- ModbusDevice.runner()¶
The default implementation of an asyncronous task. Polls for incoming PDU’s, processes the received data and sends the reply
This is a coroutine.
- ModbusDevice.poll()¶
Implement this method in a derivative class. This function must poll the underlying media for incoming data and return the received bytes. The output of this function will be fed to the
ModbusDevice._parse
method by the defaultModbusDevice.runner
function.This is a coroutine. The default implementation raises a
RuntimeError
.
- ModbusDevice._parse(apdu)¶
Implement this method in a derivative class. This method must process the incoming data (full APDU with all the headers and trailers), pass the stripped PDU to the
_process()
function and return the reply APDU (with all the headers and trailers attached).This is not a coroutine. The default implementation raises a
RuntimeError
.
- ModbusDevice._write(apdu)¶
Implement this method in a derivative class. This function must write the apdu to the underlying media
This is a coroutine. The default implementation does nothing.
Constants¶
- ModbusDevice.TYPES¶
A set of callback types:
“coil” (called for functions
0x01
,0x05
,0x0F
)“discrete” (called for function
0x02
)“input” (called for function
0x04
)“holding” (called for functions
0x03
,0x06
,0x10
)
class ModbusRtuSlave¶
Implements MODBUS RTU protocol as a master, inherits ModbusSlave
class.
Constructors¶
- class umodbus.ModbusRtuSlave(port, baud, address, debug=False)¶
Port may be an instance of
pyb.UART
or a number. In the letter case, the UART(port) instance will be created internally.port - UART handle or the UART port number.
baud - baudrate. If port is a handle, pass the correct baudrate anyway - it is used to calculate the line silence time.
class ModbusRtuDevice¶
Implements MODBUS RTU protocol as a slave, inherits ModbusDevice
.
Constructors¶
- class umodbus.ModbusRtuDevice(port, baud, address, debug=False)¶
Port may be an instance of
pyb.UART
or a number. In the letter case, the UART(port) instance will be created internally.port - UART handle or the UART port number.
baud - baudrate. If port is a handle, pass the correct baudrate anyway - it is used to calculate the line silence time.
class ModbusTcpSlave¶
Implements MODBUS TCP protocol as a master, inherits ModbusSlave
Constructors¶
- class umodbus.ModbusTcpSlave(ip, address, port=502, debug=False)¶
Create a MODBUS master that will talk to a slave device at ip:port with the MODBUS id address.
Note: the constructor will not initiate a connection.
ip - IP address of the slave device
address - address (1-247) of the slave device
port - TCP port the slave device is listening at (defaults to 502)
Methods¶
- ModbusTcpSlave.connect()¶
Connect to the remote device.
Returns
True
if the connection succeeds.
class ModbusTcpDevice¶
Implements MODBUS TCP protocol as a slave, inherits ModbusDevice
.
Constructors¶
- class umodbus.ModbusTcpDevice(address, ip='0.0.0.0', port=502, debug=False)¶
Create a MODBUS slave device that will listen at ip:port and have a MODBUS id address.
address - address (1-247) of the device
ip - IP address of the network interface
port - TCP port the device will be listening at (defaults to 502)
Functions¶
- umodbus.modbus_crc(bytestring)¶
Calculates the CRC value accoring to the MODBUS RTU protocol specification and returns it as a
bytes
value.bytestring - CRC source data (
bytes
)
- umodbus.modbus_pdu_compose(fun, registeraddress, data, count, fmt, pad=' ')¶
Compose the MODBUS PDU.
fun - function code
registeraddress - starting address
data - data to be send to the remote device
count - number of entities (coils or registers) to be read from the remote device
fmt - format of the data
pad - string padding character