Modbus transport
ModbusTCPTransport and ModbusRTUTransport are the Modbus transports that register-mapped instrument drivers sit on top of. They are a public part of the library so customers can build their own drivers for Modbus-attached instruments (temperature and process controllers, meters, PLCs) without wrapping pymodbus themselves.
They are intentionally narrow: a transport opens, closes, and locks a Modbus TCP or RTU connection and exposes raw function-code I/O plus typed register encode and decode. The caller owns the register map (which address holds what).
Modbus is a register-and-coil protocol. A driver reads and writes numbered 16-bit registers and single-bit coils by address; there is no self-describing command set. The Modbus transports use pymodbus under the hood and support both Modbus TCP and Modbus RTU (serial).
When to reach for it
The Modbus transports address Modbus TCP and RTU (serial) devices, exposing raw function-code ops plus a typed codec. Reach for one when the register map is fixed in code, or when you want a standalone client addressing registers by number. For a comparison against the other transports, see Transports. For a config-driven device where the register map lives in a JSON file rather than driver code, useModbusDevice instead. ModbusDevice composes a Modbus transport and adds semantic access by register alias, scaling, validation, and background polling.
Quickstart
A Modbus transport holds no unit address of its own: it serves any number of unit addresses on the line. Every I/O method takes the target’sunit_id as a keyword argument:
ModbusRTUTransport for serial devices. It supports both Modbus serial-line transmission modes: RTU framing (the default) and ASCII framing, via framer:
Register and data types
Modbus defines four address spaces. The Modbus transports name them with theRegisterType vocabulary, and the typed access path dispatches on it:
Values wider than 16 bits span consecutive registers.
DataType names the encoding, and register_count() reports the span:
Typed access
read_typed and write_typed handle the multi-register encode and decode, so callers work in native Python types rather than assembling 16-bit words:
False (big-endian, high word first):
"input"and"discrete"are read-only.write_typedraisesValueErrorrather than issuing a doomed request.- Single-bit spaces require
"bool". Passing any otherdata_typefor"coil"or"discrete"raisesValueError. - Coil writes require an actual
bool. There is no numeric coercion, sowrite_typed("coil", addr, 1, "bool")raises rather than silently treating1asTrue. - Register count follows from the data type.
read_typedreads exactly the spanregister_count()reports, so callers never pass a count.
register_count, decode_registers, and encode_value are also available as module-level functions for callers that hold raw registers already and only need the codec.
Atomic multi-step sequences
Hold the transport lock across several ops to keep them atomic, for example selecting a page or bank register and then reading from it:with reconnects rather than reusing it.
Sharing one connection across unit addresses
An RS-485 multi-drop line, or a TCP-to-serial gateway fronting one, often serves several devices at different unit addresses over what is physically one connection. Build a single transport and address each device byunit_id per call instead of opening a connection per device. Callers that share the transport pass a holder identity to open/close, so the connection opens once and tears down only when the last owner leaves:
unit_id range is 0 to 255 on ModbusTCPTransport and 0 to 247 on ModbusRTUTransport (Modbus over Serial Line reserves 248-255, so a real RTU/ASCII slave will never have one of those addresses); check_unit_id() validates an address against the transport’s range up front. This is the same shared-ownership mechanism described in Transports: shared ownership, applied to one line instead of one device with two categories.
For config-driven devices, ModbusDevice wraps this pattern: pass the same transport to several devices, each with its own unit_id.
Configuration
ModbusTCPTransport
ModbusRTUTransport
Neither transport carries a unit address: every I/O method takes
unit_id as a keyword argument. The valid range is 0 to 255 on ModbusTCPTransport and 0 to 247 on ModbusRTUTransport (248-255 are reserved on a real serial line, never assigned to a slave).
Method reference
Error handling
Device-side failures carry the standard Modbus exception-code name, so the message identifies the protocol-level cause rather than just reporting a failure: