Repository navigation
Getting started
modbus-sim needs Python 3.10 or newer; its only dependency is PyYAML.
pip install modbus-sim
pip install 'modbus-sim[serial]' # also for real serial ports (pyserial)
modbus-sim --version # modbus-sim 0.2.0modbus-sim profiles # what is bundled
modbus-sim map eastron-sdm630 # its register map
modbus-sim serve eastron-sdm630 # unit 1, Modbus TCP on 127.0.0.1:5020In a second terminal, read phase 1 voltage — register 30001 in Eastron's manual, input register address 0 on the wire:
$ modbus-sim read input 0 -t float32
input 0: 230.091 [4366 1741]The hex in brackets is what the device sent: 4366 1741 is 230.09 as an IEEE
754 float, most significant word first.
modbus-sim serve binds to 127.0.0.1 by default. Use --host 0.0.0.0 to
reach it from other machines (a PLC, a gateway, a VM), and --port for
another port. Port 502 needs root on Linux, so the default is 5020.
A bench file puts several devices behind one server, each with its own unit ID, like a Modbus TCP gateway:
devices:
- {profile: eastron-sdm630, unit: 1, name: meter}
- {profile: omron-e5cc, unit: 2, name: controller,
model_params: {time_scale: 10}} # heats ten times faster than real time
- {profile: sunspec-inverter, unit: 3, name: inverter,
model_params: {time_scale: 120}} # a day in 12 minutesmodbus-sim serve --bench examples/real-devices.yaml
modbus-sim read holding 40000 -c 2 -t string -u 3 # 'SunS'
modbus-sim list # devices, faults, request countsThis is the bench of the Browser demo.
Any Modbus master works. With pymodbus (3.10 or newer):
from pymodbus.client import ModbusTcpClient
c = ModbusTcpClient("127.0.0.1", port=5020)
c.connect()
r = c.read_input_registers(0, count=2, device_id=1)
print(c.convert_from_registers(r.registers, c.DATATYPE.FLOAT32)) # 230.1
c.close()modbus-sim also has a minimal client of its own, handy in tests:
from modbus_sim.client import ModbusClient
with ModbusClient("127.0.0.1", 5020) as c:
print(c.read_holding_registers(40002, 2, unit=3)) # [1, 66]: SunSpec model 1modbus-sim serve --bench examples/real-devices.yaml --rtu-over-tcp # RTU frames over TCP
modbus-sim serve --bench examples/real-devices.yaml --pty # prints e.g. /dev/pts/7
modbus-sim serve eastron-sdm630 --serial /dev/ttyUSB0 --baud 9600 --parity NWith --pty (Linux/macOS), point your RTU master at the printed device. On
Windows, use --serial COM5 with a virtual null-modem pair such as com0com.
modbus-sim inject meter phase_loss phase=2 # device fault
modbus-sim inject controller no_response # the next request gets no answer
modbus-sim get inverter ac_power operating_state
modbus-sim clear meter # all faults of the meterThese go to the control port (5021, loopback only). See Fault injection recipes for using them from tests.
A profile is a YAML file with points; modbus-sim map checks it and prints
the result. The format is in the
README:
name: tank
word_order: CDAB
points:
- {name: level, table: input, address: 0, type: float32, unit: m,
source: [{type: sine, offset: 2.0, amplitude: 0.5, period: 120}]}
- {name: pump, table: coil, address: 0}modbus-sim map tank.yaml
modbus-sim serve tank.yamlmodbus-sim · MIT licensed · Eastron, Omron and SunSpec are trademarks of their owners; modbus-sim is not affiliated with them.