Registry / http-networking / pymodbus

pymodbus

JSON →
library3.15.0pypypi✓ verified 25d ago

Pymodbus is a fully featured Modbus protocol stack implemented in Python, offering client and server capabilities for TCP, UDP, and serial communication. It primarily leverages `asyncio` for modern asynchronous operations and is actively maintained with frequent minor releases focusing on bug fixes and incremental improvements. The current version is 3.12.1.

pip install pymodbus
INSTALL
IMPORT
SIG · PYMODBUS
P
pymodbus
http-networkingpythonv3.15.0
Install
1.7s avg
Import
315ms
Disk
17MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v3.15.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.95 runs
installs and imports cleanly · install 0.0s · import 0.330s · 18.9MB
glibc
py 3.103.95 runs
installs and imports cleanly · install 1.7s · import 0.300s · 19MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

ModbusTcpClient
from pymodbus.client import ModbusTcpClient
from pymodbus.client.sync import ModbusTcpClient
Pymodbus v3.x is primarily asyncio-based. Synchronous clients (e.g., in `pymodbus.client.sync`) were removed or heavily refactored in major version 3 and should not be used for new development.
StartAsyncTcpServer
from pymodbus.server import StartAsyncTcpServer
from pymodbus.server.sync import ModbusTcpServer
Pymodbus v3.x server implementations are primarily asynchronous. Synchronous servers were removed or heavily refactored. Use `StartAsyncTcpServer` for TCP, `StartAsyncUdpServer` for UDP, or `StartAsyncSerialServer` for serial.
ModbusSlaveContext
from pymodbus.datastore import ModbusSlaveContext, ModbusSequentialDataBlock
Used for defining server data storage. The `ModbusSequentialDataBlock` is a common block type.

This quickstart demonstrates a basic asynchronous Modbus TCP server and client. The server runs on localhost:5020, serving a simple datastore. The client connects, reads initial holding registers, writes new values, and then reads again to verify the write operation, before gracefully shutting down the server.

import asyncio import logging from pymodbus.client import ModbusTcpClient from pymodbus.server import StartAsyncTcpServer from pymodbus.datastore import ModbusSlaveContext, ModbusSequentialDataBlock logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) async def run_modbus_server(): # Setup a simple Modbus datastore for Slave ID 1 store = ModbusSlaveContext( di=ModbusSequentialDataBlock(0, [17]*10), co=ModbusSequentialDataBlock(0, [17]*10), hr=ModbusSequentialDataBlock(0, [17]*10), ir=ModbusSequentialDataBlock(0, [17]*10) ) context = ModbusSlaveContext(slaves={0x01: store}, single=False) server_task = StartAsyncTcpServer( context=context, address=("localhost", 5020), allow_reuse_address=True ) log.info("Modbus TCP Server starting on localhost:5020") await server_task # This will block until cancelled async def run_modbus_client(): await asyncio.sleep(1) # Give server a moment to start log.info("Modbus TCP Client connecting to localhost:5020") client = ModbusTcpClient("localhost", 5020) if await client.connect(): log.info("Client connected successfully.") # Read holding registers (address 0, count 5, slave ID 1) result = await client.read_holding_registers(address=0, count=5, slave=1) if result.is_success(): log.info(f"Read holding registers: {result.registers}") else: log.error(f"Failed to read holding registers: {result}") # Write to holding registers (address 0, values [99, 98, 97], slave ID 1) write_result = await client.write_registers(address=0, values=[99, 98, 97], slave=1) if write_result.is_success(): log.info(f"Wrote to holding registers.") else: log.error(f"Failed to write holding registers: {write_result}") # Read again to verify write result_after_write = await client.read_holding_registers(address=0, count=5, slave=1) if result_after_write.is_success(): log.info(f"Read holding registers after write: {result_after_write.registers}") else: log.error(f"Failed to read holding registers after write: {result_after_write}") client.close() log.info("Client disconnected.") else: log.error("Client failed to connect.") async def main(): server_task = asyncio.create_task(run_modbus_server()) try: await run_modbus_client() finally: server_task.cancel() # Signal server to shut down try: await server_task except asyncio.CancelledError: log.info("Server task cancelled successfully.") except Exception as e: log.error(f"Server task ended with unexpected error: {e}") if __name__ == "__main__": asyncio.run(main())
Debug
Known issues
breakingPymodbus v3.0.0 introduced a significant shift from synchronous (blocking) to asynchronous (asyncio-based) operations. Code using `pymodbus.client.sync` or `pymodbus.server.sync` from v2.x will be incompatible with v3.x and require complete refactoring to use the new `asyncio` patterns.
fix
Rewrite client/server logic using `asyncio` and the new `pymodbus.client` and `pymodbus.server` modules (e.g., `ModbusTcpClient`, `StartAsyncTcpServer`). All I/O operations must be `await`ed.
affects: >=3.0.0
breakingThe traditional datastore classes (e.g., `ModbusSlaveContext`, `ModbusSequentialDataBlock`) are slated for deprecation and eventual removal in Pymodbus v4.0.0. New `SimData` and `SimDevice` classes have been introduced as the preferred modern approach for defining server data storage.
fix
For new projects, consider adopting `SimData` and `SimDevice` introduced in v3.12.0. For existing projects, be aware that a refactor will be necessary upon upgrading to v4.0.0 or later.
affects: >=3.12.0
gotchaPymodbus version `3.10.0` was officially marked as 'DO NOT USE THIS RELEASE it is broken' by the maintainers. It contained critical bugs that caused unexpected behavior.
fix
Users running `3.10.0` should immediately upgrade to `3.11.0` or later to avoid critical issues. Version `3.11.0` specifically addressed the problems in `3.10.0`.
affects: 3.10.0
gotchaIncorrect byte or word order is a common issue when communicating with Modbus devices from different manufacturers. Pymodbus defaults to certain orders, but devices may expect others (e.g., Big-Endian vs. Little-Endian, or swapped words).
fix
Explicitly specify `byteorder` and `wordorder` parameters when reading/writing registers, or when converting between registers and other data types, to match the device's expectations. Common options are `Endian.Big` and `Endian.Little`.
affects: All versions
Errors
Common errors & fixes
ModuleNotFoundError: No module named 'pymodbus.client.sync'
In pymodbus versions 3.x and later, the synchronous and asynchronous client modules (`client.sync` and `client.async`) were refactored and consolidated.
fix
Update your import statements to use `from pymodbus.client import ModbusTcpClient` for synchronous TCP communication or `from pymodbus.client import AsyncModbusTcpClient` for asynchronous TCP.
AttributeError: 'ModbusIOException' object has no attribute 'registers'
A Modbus operation failed to receive a valid response from the device (e.g., due to a timeout or connection error), returning a `ModbusIOException` object instead of a successful response object that would contain a `registers` or `bits` attribute. The code then attempts to access this missing attribute.
fix
Always check the `isError()` method of the response object returned by Modbus client operations before attempting to access its data attributes. If `isError()` returns `True`, handle the exception rather than trying to read registers.
Modbus Error: [Input/Output] Unable to decode request
Pymodbus received a response from the Modbus device that it could not parse or decode, often because the packet was malformed, incomplete, or the device does not strictly adhere to the Modbus protocol specification.
fix
Verify the device's Modbus implementation and communication settings (e.g., framer type, baud rate, parity). Ensure reliable network communication (no packet loss or fragmentation). Adding small delays between consecutive Modbus requests can sometimes help with devices that are sensitive to polling speed.
'H' format requires 0<= number <= 65535
This error occurs when attempting to write a numerical value larger than a 16-bit unsigned integer (65535) into a single Modbus register using functions like `write_register`. Modbus registers are fundamentally 16-bit.
fix
If you need to write larger values (e.g., 32-bit integers, floats), you must split them into multiple 16-bit registers. Use `pymodbus.payload.BinaryPayloadBuilder` to correctly convert and write these values across multiple registers using `write_registers`.
Upgrade
Version history
3.15.0latest on PyPI · released Aug 13, 2026
Audit
Dependencies

No dependency data recorded yet.

Agent activity
15 hits · last 30 days
node
12
OpenAI (training)
1
Resources
pymodbus — pip install pymodbus · libregistry