bacsys-pymod
Production-grade Modbus TCP / RTU driver for Python. Library + one-shot CLI.
Distribution name
bacsys-pymod, import namepymod.
import pymod
with pymod.Client.tcp("10.0.0.5", 502, unit_id=1) as c:
results = c.read([
pymod.Holding(start=0, count=10, dtype="float32"),
pymod.Coil(start=0, count=16),
pymod.Holding(start=0, count=2, dtype="bit", bit_index=8),
])
for r in results:
print(r.values if r.ok else f"failed: {r.error}")
Highlights
- Modbus TCP with concurrent connections and request pipelining (TID demultiplexing).
- Modbus RTU over a serial port — sequentialized internally, safe to share across callers.
- Modbus RTU over TCP for serial-to-Ethernet gateways (Moxa-style).
- All standard function codes (FC01/02/03/04/05/06/15/16) plus a registration hook for custom FCs.
- Heterogeneous batch reads — pass a list of typed items (Holding, Input, Coil, Discrete) and the planner coalesces adjacent same-area ranges into the minimum number of Modbus requests.
- Typed values —
int16,uint16,int32,uint32,float32,int64,uint64,float64, plus bit extraction from registers. - All four PLC byte/word orderings (ABCD / CDAB / BADC / DCBA) configurable per item.
- Sync facade for Flask / scripts / REPL —
pymod.Client.tcp(...)is a normal blocking object backed by an internal asyncio loop. - Server mode — callback-based, no internal datastore. Bring your own data, use it for protocol bridging (e.g. Modbus → BACnet / MQTT).
pymodCLI —read,write,scan,serve, plus an interactive--guidewizard.- Python 3.11+, pure Python (one runtime dep:
pyserial),mypy --strictclean.
Install
pip install bacsys-pymod
Once installed:
import pymod
print(pymod.__version__)
…and the pymod CLI is on PATH.
Quick examples
TCP — sync client (Flask, scripts, REPL)
import pymod
client = pymod.Client.tcp("127.0.0.1", 502, unit_id=1, timeout_s=0.5)
client.connect()
try:
results = client.read([pymod.Holding(start=0, count=10, dtype="int16")])
print(results[0].values)
finally:
client.close()
TCP — async client
import asyncio, pymod
async def main():
async with pymod.AsyncClient.tcp("127.0.0.1", 502, unit_id=1) as c:
results = await c.read([pymod.Holding(start=0, count=10, dtype="int16")])
print(results[0].values)
asyncio.run(main())
Serial RTU
client = pymod.Client.rtu("COM5", baudrate=9600, parity="N", unit_id=1)
…the rest of the API is identical to the TCP client.
Modbus TCP server (callback-based)
import asyncio, pymod
async def on_read(area, address, count):
return store.read(area, address, count)
async def on_write(area, address, values):
store.write(area, address, values)
async def main():
async with pymod.Server(host="0.0.0.0", port=502,
on_read=on_read, on_write=on_write):
await asyncio.Future()
asyncio.run(main())
The server has no internal datastore — the host application owns the data, the server is just a Modbus protocol terminator. Perfect for bridging Modbus to other industrial protocols.
CLI
pymod read --host 127.0.0.1 --port 502 --area holding --start 0 --count 10 --dtype int16
pymod write --host 127.0.0.1 --port 502 --area holding --start 0 --values 1,2,3 --dtype uint16
pymod scan --host 127.0.0.1 --port 502
pymod serve --host 0.0.0.0 --port 5020 --holding 0=100,1=200
pymod --guide # interactive wizard
Each subcommand has detailed --help.
Documentation
Full docs at https://bacsys-pymod.readthedocs.io/.
License
MIT. See LICENSE.
Metadata
Release files for bacsys-pymod 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| bacsys_pymod-0.1.0.tar.gz | 8.8 MB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| bacsys_pymod-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 8.9 MB
Release files / bacsys_pymod-0.1.0.tar.gz
| Download URL | bacsys_pymod-0.1.0.tar.gz |
|---|---|
| Size | 8.8 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
44c221a8ba23e5153d306fd24b7376d12e5fd6ac0561e503c721ee258b53ca52
|
|
BLAKE2b-256 checksum How to use checksums |
98f3ceefa3e9cf3d85460970e63de80ea3238895efc646f59df9409dcde4a222
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Release files / bacsys_pymod-0.1.0-py3-none-any.whl
| Download URL | bacsys_pymod-0.1.0-py3-none-any.whl |
|---|---|
| Size | 54.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f809c41818a6c4324b0ddf18f08f1102b2a8140fe560b1410e4a30564649aef1
|
|
BLAKE2b-256 checksum How to use checksums |
0760a08f1f6d1f5b05a54d530968ffa2734833a0fee3bfbac691fc06a8457b51
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.0
|
Security for bacsys-pymod 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.