Skip to content

floko808/modbus_server_simul

Repository files navigation

Modbus Server Simulator

A lightweight Modbus server simulator that supports both RTU (serial) and TCP (network) communication modes. Available as a CLI tool and a GUI application (tkinter). Useful for testing Modbus master/client software, PLC integrations, and SCADA systems without needing real hardware.

Disclaimer: This software is provided "as is", without warranty of any kind. Use it at your own risk. The authors are not responsible for any damage, data loss, or issues caused by the use of this software. It is intended for development and testing purposes only — do not use it as a substitute for certified industrial equipment in production environments. See the LICENSE file for full terms.

Features

  • RTU mode — communicates over a serial port (RS-485/RS-232)
  • TCP mode — communicates over a network socket
  • All four primary Modbus function codes:
    FC Name Data Type Access
    1 Read Coils Boolean (1 bit) Read/Write
    2 Read Discrete Inputs Boolean (1 bit) Read-Only
    3 Read Holding Registers 16-bit registers Read/Write
    4 Read Input Registers 16-bit registers Read-Only
  • Multiple data types for FC 3 & 4:
    Type Size Range
    Float32 2 registers IEEE 754 float
    Int16 1 register -32768 to 32767
    UInt16 1 register 0 to 65535
    Int32 2 registers -2147483648 to 2147483647
    UInt32 2 registers 0 to 4294967295
  • Live value editing — change register/coil values while the server is running; Modbus clients see the update immediately
  • CSV import/export — bulk-load or save data point configurations
  • Live PDU tracing — logs every Modbus request/response for debugging
  • Quiet mode (CLI only) — suppress all output for headless/automated use
  • Single-binary distribution — built with PyInstaller for Linux and Windows, no Python needed on target

Requirements

  • Python 3.10+
  • Dependencies listed in requirements.txt:
    • pymodbus (>= 3.12, < 4.0)
    • pyserial (>= 3.5, < 4.0)

Installation

Option 1: Virtual environment (development)

# Run the setup script — creates a .venv and installs dependencies
./setup_venv.sh

# Activate the environment
source .venv/bin/activate

Option 2: Pre-built binaries

Standalone binaries are available in dist/ (Linux) and dist_win/ (Windows). Copy them anywhere and run directly — no Python installation needed.

# CLI version
./dist/modbus_server_simul --help

# GUI version
./dist/modbus_server_simul_gui              # Linux
dist_win\modbus_server_simul_gui.exe        # Windows

CLI usage

The CLI simulator (modbus_server_simul.py) is configured entirely via command-line flags. The only required flag is -D (data point), which can be repeated.

Data point format

-D FC:ADDRESS:VALUE[:TYPE]
Field Description
FC Function code: 1 (Coils), 2 (Discrete Inputs), 3 (Holding Registers), 4 (Input Registers)
ADDRESS Modbus register/coil address (non-negative integer)
VALUE Value to serve — 0/1 for FC 1 & 2, numeric for FC 3 & 4
TYPE (optional, FC 3/4 only) Data type: float32 (default), int16, uint16, int32, uint32

Examples

RTU mode — simulate a device on serial port with multiple data types:

./modbus_server_simul -i 100 -S /dev/ttyUSB0 -b 19200 \
  -D 1:99:1 \
  -D 2:10:1 \
  -D 3:2100:123.45 \
  -D 4:2000:98.765

This creates a server with:

  • Unit ID 100 on /dev/ttyUSB0 at 19200 baud
  • Coil 99 = ON (FC 1)
  • Discrete Input 10 = ON (FC 2)
  • Holding Register 2100 = 123.45 as Float32 (FC 3)
  • Input Register 2000 = 98.765 as Float32 (FC 4)

TCP mode with mixed data types — combine different register types:

./modbus_server_simul -m tcp -H 0.0.0.0 -p 5020 -i 1 \
  -D 1:0:1 \
  -D 2:5:0 \
  -D 3:0:3.14:float32 \
  -D 3:2:42:int16 \
  -D 3:3:1000:uint16 \
  -D 3:4:-100000:int32 \
  -D 3:6:4000000000:uint32

This starts a TCP Modbus server on port 5020 with mixed data types across contiguous holding registers. When the type is omitted (e.g. -D 3:0:42.0), it defaults to float32.

Quiet mode — suppress all output:

./modbus_server_simul -q -i 69 -D 3:100:3.14

All CLI flags

Flag Description Default
-m, --mode Communication mode: rtu or tcp rtu
-D, --data Data point (repeatable): FC:ADDRESS:VALUE[:TYPE] required
-i, --id Slave/Unit ID (1–247) 69
-q, --quiet Suppress informational output off
-V, --version Show version and exit
RTU Settings
-S, --port Serial port path /dev/ttyUSB0
-b, --baudrate Baud rate 19200
-P, --parity Parity: N, E, O N
-d, --bytesize Data bits: 7 or 8 8
-s, --stopbits Stop bits: 1 or 2 1
TCP Settings
-H, --host Bind address 0.0.0.0
-p, --tcp-port TCP port 5020

GUI version

The graphical interface (modbus_server_simul_gui.py) provides the same functionality as the CLI with a point-and-click interface built on tkinter.

Running the GUI

# From source (requires virtual environment)
source .venv/bin/activate
python modbus_server_simul_gui.py

# Or use the pre-built binary
./dist/modbus_server_simul_gui              # Linux
dist_win\modbus_server_simul_gui.exe        # Windows

GUI layout

  • Server Configuration (top) — select RTU or TCP mode, set Unit ID, and configure serial/network settings. Irrelevant settings are greyed out based on the selected mode.
  • Data Points table (middle) — the central table showing all configured data points with columns for Function Code, Data Type, Address, and Value.
  • Start / Stop (control bar) — start or stop the Modbus server. Shows a live status indicator.
  • Log (bottom) — timestamped console showing PDU traffic and server events. Click Clear Log to reset.

Adding data points

Use the input fields below the table:

  1. Select a Function Code from the dropdown (FC1–FC4).
  2. Select a Data Type (Float32, Int16, UInt16, Int32, UInt32). For FC 1/2 this is automatically set to Bit.
  3. Enter the Address (register/coil number).
  4. Enter the Value.
  5. Click Add or press Enter.

To remove rows, select them in the table and click Remove (or press Delete).

Inline editing (double-click)

Double-click any cell in the table to edit it inline:

  • Function Code and Data Type cells open a dropdown selector.
  • Address and Value cells open a text editor — press Enter to save, Escape to cancel.
  • Coil/Discrete values (FC 1/2) open a 0 / 1 dropdown for quick toggling.

Live value editing

While the server is running, you can double-click the Value column to change values on the fly. The change is pushed to the server's in-memory registers immediately — any Modbus client reading that address will see the new value on the next request. The FC, Type, and Address columns are locked while the server is running since changing them would require a server restart.

CSV import / export

Import — click Import CSV to load data points from a CSV file. The expected format:

FC,Type,Address,Value
1,Bit,99,1
2,Bit,10,0
3,Float32,2100,123.45
3,Int16,200,-1234
3,UInt16,300,65000
3,Int32,400,-100000
3,UInt32,500,3000000000
4,Float32,0,98.765

The FC column accepts multiple formats: 1, FC1, or FC1 - Coils (same for FC 2/3/4). The header row is optional. For FC 1/2, the Type column can be omitted or set to Bit. A 3-column format (FC, Address, Value) is also supported — the type defaults to Float32 for FC 3/4.

Export — click Export CSV to save all current data points to a CSV file with the same 4-column format. Useful for backing up a configuration or sharing it between machines.

A sample CSV file (example_data.csv) is included in the project.

Building the binaries

The project uses PyInstaller to create standalone executables.

# Activate the virtual environment
source .venv/bin/activate

# Install build dependencies
pip install pyinstaller

# Build the CLI (Linux)
pyinstaller --onefile --clean --name modbus_server_simul modbus_server_simul.py

# Build the GUI (Linux)
pyinstaller --onefile --clean --name modbus_server_simul_gui modbus_server_simul_gui.py

Cross-compiling for Windows

Windows builds are done via Wine with a Windows Python installation:

# Install Windows Python under Wine (one-time setup)
wine python-3.13.4-amd64.exe /quiet InstallAllUsers=0 PrependPath=1

# Install dependencies in Windows Python
wine ~/.wine/drive_c/users/$USER/AppData/Local/Programs/Python/Python313/python.exe \
  -m pip install pymodbus pyserial pyinstaller

# Build the GUI with the banana icon
wine ~/.wine/drive_c/users/$USER/AppData/Local/Programs/Python/Python313/python.exe \
  -m PyInstaller --onefile --clean --name modbus_server_simul_gui --icon=banana.ico \
  --distpath dist_win --workpath build_win --specpath build_win modbus_server_simul_gui.py

Versioning

The project follows Semantic Versioning (MAJOR.MINOR.PATCH):

  • MAJOR — breaking changes (CLI flags renamed, CSV format changed, etc.)
  • MINOR — new features (new data types, new GUI controls, etc.)
  • PATCH — bug fixes and small improvements

The version number lives in version.py and is displayed in:

  • The GUI title bar
  • The CLI via --version / -V

All changes are tracked in CHANGELOG.md following the Keep a Changelog format.

Project structure

modbus_server_simul/
  LICENSE                       # BSD 3-Clause License
  modbus_server_simul.py        # CLI simulator — Modbus RTU/TCP server
  modbus_server_simul_gui.py    # GUI simulator — tkinter graphical interface
  version.py                    # Single source of truth for the version number
  CHANGELOG.md                  # Release history and change tracking
  example_data.csv              # Sample CSV for importing data points
  banana.ico                    # Application icon (Windows builds)
  requirements.txt              # Python dependencies
  setup_venv.sh                 # Virtual environment setup script
  dist/                         # Built Linux binaries
  dist_win/                     # Built Windows executables (.exe)

How it works

  1. Argument parsing — the CLI parses -D flags into (function_code, address, value, data_type) tuples. The GUI collects the same data from the table. Both validate inputs (address range, value range, overlapping addresses) before proceeding.
  2. Device building — each data point is converted into a SimData entry in the appropriate data store (coils, discrete inputs, holding registers, or input registers) using the native pymodbus data type (e.g. DataType.FLOAT32, DataType.INT16). pymodbus handles encoding values into 16-bit registers internally.
  3. Server startup — pymodbus starts either a serial (RTU) or TCP server with the configured device. In the GUI, the server runs in a background thread with its own asyncio event loop so the interface stays responsive.
  4. Request handling — when a Modbus master sends a request, pymodbus looks up the value in the data store and responds. The PDU trace handler logs every transaction to the console or GUI log panel.
  5. Live editing (GUI only) — value changes are written directly into the server's in-memory register arrays using a thread lock to prevent torn reads. Coils and discrete inputs are stored as packed bitmasks (16 bits per register), so toggling a single coil uses bit-level manipulation at the correct offset.

License

This project is licensed under the BSD 3-Clause License — a permissive open-source license that allows free use, modification, and redistribution with minimal restrictions. See the LICENSE file for the full text.

USE AT YOUR OWN RISK. This software comes with no warranties. The authors disclaim all liability for any damages arising from its use. It is designed for development, testing, and educational purposes. It should not be used in safety-critical or production industrial environments without proper validation.

About

Modbus Server Simulator — RTU/TCP with CLI and GUI (tkinter). Supports FC1-FC4, multiple data types, live editing, CSV import/export.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors