Developer guide

ModbusSimulator with Python: pymodbus Guide (2026)

Spin up a Modbus TCP or RTU slave in a few lines of Python using pymodbus 3.x — full working code, plus when a scripted simulator beats a GUI tool (and vice versa).

Quick take: pymodbus is a pure-Python, actively maintained Modbus client/server/simulator library. For CI pipelines and scripted test data, it's the fastest path to a working slave. For manual, ad-hoc register poking across a team, a GUI simulator is still less friction.

Why simulate Modbus in Python instead of using a GUI tool?

Three reasons engineering teams reach for pymodbus specifically: it runs headless in CI/CD without a display, register values can be scripted and version-controlled alongside test code, and a server starts/stops in milliseconds so you can spin up dozens of simulated slaves in a single test run without licensing per-instance.

Installing pymodbus

pip install pymodbus

pymodbus 3.x supports Python 3.9+ and ships both synchronous and asyncio server APIs. The examples below use the synchronous API, which is the simplest starting point for a one-off simulated slave.

Minimal Modbus TCP slave simulator

This starts a Modbus TCP server on port 502 with holding registers pre-loaded with test values — enough to point any Modbus master (SCADA, PLC, or another script) at 127.0.0.1:502 and start polling immediately:

from pymodbus.datastore import (
    ModbusSequentialDataBlock,
    ModbusSlaveContext,
    ModbusServerContext,
)
from pymodbus.server import StartTcpServer

# Pre-load holding registers 0-9 with test values
store = ModbusSlaveContext(
    di=ModbusSequentialDataBlock(0, [0] * 100),   # discrete inputs
    co=ModbusSequentialDataBlock(0, [0] * 100),   # coils
    hr=ModbusSequentialDataBlock(0, [111, 222, 333, 0, 0, 0, 0, 0, 0, 0]),  # holding registers
    ir=ModbusSequentialDataBlock(0, [0] * 100),   # input registers
)
context = ModbusServerContext(slaves=store, single=True)

StartTcpServer(context=context, address=("0.0.0.0", 502))

Any master reading holding registers 0-2 (function code 03) will get back 111, 222, 333 immediately — no PLC, no wiring, no real device required.

Updating register values while the server runs

Because store is a live Python object, you can update register values from another thread while the server is serving requests — useful for simulating a sensor value that changes over time in a test scenario:

import random, threading, time

def drift_holding_register():
    while True:
        value = random.randint(200, 250)
        store.setValues(3, 0, [value])  # function code 3 = holding register
        time.sleep(2)

threading.Thread(target=drift_holding_register, daemon=True).start()

Simulating Modbus RTU (serial) with pymodbus

Swap StartTcpServer for StartSerialServer to simulate an RTU slave over a real or virtual COM port (pair with a null-modem emulator like com0com on Windows to test without hardware):

from pymodbus.server import StartSerialServer

StartSerialServer(
    context=context,
    port="COM5",       # or /dev/ttyUSB0 on Linux
    baudrate=9600,
    parity="N",
    stopbits=1,
    bytesize=8,
)

pymodbus vs. a desktop Modbus simulator

Scenariopymodbus (scripted)Desktop GUI simulator
CI/CD integration testBest fit — headless, fast startupNot designed for headless runs
Non-developer manually checking a SCADA screenRequires writing codeBest fit — point and click register edits
Dozens of simulated slaves at onceEasy to script and loopManageable, more clicking per slave
Live traffic view / packet inspectionNeeds Wireshark or logging codeOften built in
License costFree, open sourceFree tier, paid license for continued use

The two aren't mutually exclusive — many teams use pymodbus in automated test suites and a desktop simulator for manual exploratory testing during development.

Related pages

Prefer a GUI over writing Python?

ModbusSimulator gives you master + slave modes, multiple simulated devices, and live register editing — no code required. Free 30-day trial, then a $99 one-time license.

Download Free tier

FAQ

What is the best Python library for simulating a Modbus slave?

pymodbus is the de facto standard — an actively maintained, pure-Python implementation of the Modbus protocol with client, server, and simulator APIs for both TCP and serial (RTU/ASCII).

Can pymodbus simulate a Modbus TCP and RTU slave at the same time?

Yes, but as two separate server processes — StartTcpServer and StartSerialServer are separate entry points. You can run both in the same script using threads or asyncio if you need a slave reachable over both transports.

Do I need real hardware to test with a pyModbusSimulator?

No. A pymodbus TCP server binds to 127.0.0.1 or any local interface, so a Modbus master (SCADA, PLC logic, or another script) can poll it exactly like a real device with zero physical hardware.

Is pymodbus good enough for CI/CD test pipelines?

Yes — it's a common choice for automated integration tests because it starts and stops in milliseconds, requires no license, and its ModbusServerContext lets you script register values per test case.

When should I use a GUI Modbus simulator instead of pymodbus?

When you (or non-developer teammates) need to manually poke register values, watch live traffic, or configure multiple slaves without writing code. A desktop simulator with a GUI is faster for ad-hoc PLC/SCADA testing; pymodbus wins for scripted, repeatable, or CI-driven tests.