Skip to content

Repository files navigation

🔌 ModbusSim

A cross-platform Modbus simulator — Slave and Master, in one desktop toolkit.

Release Downloads Stars License: MIT Platform

Built with Rust · Tauri 2 · Vue 3

English · 中文

ModbusMaster polling a simulated slave over TCP
Slave register simulation → scan-group polling → random mutation → wire-level logs


Why this project

Testing a Modbus integration usually means wiring up a real PLC or borrowing a master station. This project puts both ends on your desktop:

  • 🛰️ Slave & Master in one repo — simulate a field device, or drive one, with no external hardware.
  • 🔌 Five transports, one core — TCP, TCP+TLS, RTU, ASCII and RTU-over-TCP, covering function codes FC01–FC06 / FC15 / FC16.
  • 📈 Built-in data simulation — every register can run its own data source (Fixed / Random / Sine / Sawtooth / Triangle / Counter / CSV playback) or an independent periodic mutation schedule; 20,000+ registers with virtual scrolling.
  • 🌐 Network reach — route Master TCP, TCP+TLS and RTU-over-TCP connections through a SOCKS5 proxy with optional authentication and proxy-side DNS.
  • 🖥️ Native desktop app — small Rust + Tauri binaries for Windows, macOS and Linux, with in-app auto-update.
  • 🌏 Bilingual UI — full English / 简体中文, switchable at runtime.

Table of Contents

Screenshots

Slave · 20,000 registers with live random mutation

ModbusSlave runs a real Modbus TCP server on 0.0.0.0:502 with two slave devices. The register table virtual-scrolls through 20,000+ holding registers; Random Mutation changes values in place (orange flashes) and the value panel on the right decodes the selected register as Signed / Unsigned / Hex / Binary at once.

ModbusSlave with running server, mutating registers and value panel

Master · New Connection dialog

One dialog covers every transport — TCP (with optional TLS), RTU serial, ASCII serial or RTU-over-TCP — with target address, port, slave ID and timeout. Network transports also accept a SOCKS5 proxy with optional username/password authentication and proxy-side DNS resolution, so the target is reachable even behind a jump host or an industrial gateway.

New Connection dialog

Master · scan groups fill the table

Add scan groups (e.g. holding registers 0–59 and coils 0–31) with a custom poll interval per group and a per-group slave ID override. The connection tree shows each group's function code and range; the data table refreshes on every poll with the values served by the Slave, decoded as Unsigned / Signed / Hex / Binary / Float32.

Master data table polling the slave

Master · communication log with decoded TX/RX frames

The bottom log panel records every request/response pair — direction, function code and a readable detail (R 0 x60, 60 regs) side by side, filterable by direction / FC / text and exportable to CSV.

ModbusMaster communication log with decoded frames

Features

🛰️ ModbusSlave — Slave Simulator

  • Multi-transport — TCP, TCP+TLS, RTU (serial), ASCII (serial), RTU-over-TCP
  • Modbus TCP over TLS — TLS 1.2+ encryption, PEM and PKCS#12 certificate formats, optional mTLS (mutual authentication with client certificates)
  • Multiple slave devices — create connections on any port, add multiple slave devices per connection
  • Four register types — Coils (FC01), Discrete Inputs (FC02), Holding Registers (FC03), Input Registers (FC04)
  • Full protocol support — Read (FC01–04), Write Single (FC05/06), Write Multiple (FC15/16), with Modbus exception codes
  • Register table — address search/filter, inline value editing, Ctrl/Shift multi-select, virtual scrolling (20,000+ registers), multi-format display (Auto / U16 / I16 / Hex / Bin / Float32 with 4 byte orders)
  • Default initialization — new slaves pre-fill addresses 0–20,000 across all four register types; batch-add supports up to 50,000 entries per operation
  • Value panel — Signed/Unsigned/Hex/Binary (16-bit), Long/Float (32-bit), Double (64-bit), all byte orders (AB CD / CD AB / BA DC / DC BA)
  • Per-point data sources — every register can run its own simulation source: Fixed, Random, Sine, Sawtooth, Triangle, Counter or CSV sequence playback; each point carries an independent update interval and wave parameters (amplitude / frequency / offset / phase / wave period), and the configuration round-trips through project save/load
  • Per-point periodic mutation — right-click a register for single-point config, or multi-select rows and open the Simulation Settings drawer to apply one schedule (Flip / Increment / Decrement / Random) to every selected point at once; discrete points flip, analog points ramp between min/max bounds with a configurable step; the drawer lists all active simulations with mode, period, bounds and a live current value, each with per-row stop; the minimum period is 100 ms, all schedules run concurrently and independently on a single 100 ms backend tick, and settings persist with the project
  • Communication log — real-time TX/RX logging with search, direction/function-code filtering, and CSV export
  • Project files — save/load complete configurations as .modbusproj files for quick scenario switching
  • Serial port support — auto-detect system serial ports, configurable baud rate, data bits, stop bits, parity

📡 ModbusMaster — Master Tool

  • Multi-transport — TCP, TCP+TLS, RTU (serial), ASCII (serial), RTU-over-TCP
  • Modbus TCP over TLS — TLS 1.2+ encryption, PEM and PKCS#12 certificate formats, accept-invalid-certs mode for self-signed certificate testing
  • SOCKS5 proxy — route TCP, TCP+TLS and RTU-over-TCP connections through a SOCKS5 proxy (IPv4/IPv6) with optional username/password authentication and proxy-side DNS resolution; credentials are redacted from Rust debug output and the UI explains the RFC 1929 / project-file security boundary
  • Scan groups — periodic polling with custom intervals per register group, per-group slave ID override
  • Device discovery — slave ID scan (1–247), register address scan, auto-add discovered devices to scan groups
  • Multi-format data view — Unsigned, Signed, Hex, Binary, Float32 (AB CD / CD AB), virtual scrolling
  • Write operations — write single/multiple coils and registers (FC05/06/15/16)
  • Communication log — TX/RX logging with search/filter (direction, function code, text) and CSV export
  • Auto-reconnect — configurable reconnection with exponential backoff (1s → 2s → 4s → … → 30s max)
  • Project files — save/load connection and scan group configurations
  • Connection-on-scan — auto-prompt to scan devices after a successful connection
  • In-app auto-update — silently downloads and verifies signed updates in the background, then offers install now / skip this version / install on next launch (6 h check throttle, "later" snoozes 24 h)

🧩 Shared Architecture

  • Unified error system — structured ModbusError with categorized error types (connection/protocol/application), serialized to JSON for frontend parsing
  • Shared Vue components — common composables, types and i18n shared between both Tauri apps via the shared-frontend npm workspace

Download

Pre-built installers for every platform are on the Releases page.

Platform Installer
Windows .msi / .exe (NSIS)
macOS .dmg (Apple Silicon & Intel)
Linux .AppImage / .deb / .rpm

Both apps auto-update from GitHub Releases since v0.16.0. Since v0.17.2 updates download and verify in the background first, then offer install now / skip this version / install on next launch. macOS users need one extra step on first launch.

Note: As of v0.16, the native egui edition (assets with the -egui- suffix) is discontinued. Please migrate to the Tauri installers listed above.

China mirror

Users in mainland China may have unstable access to GitHub Releases. Recommended mirror for direct installer downloads:

Starting from v0.16.0, the in-app updater automatically falls back through multiple proxies — no manual action needed. However, the very first upgrade from a pre-0.16 build has no in-app updater at all; download and install the new version once via the mirror above, after which updates route through proxies automatically.

Supported Function Codes

Code Function Slave (Server) Master (Client)
FC01 Read Coils Read Read/Poll
FC02 Read Discrete Inputs Read Read/Poll
FC03 Read Holding Registers Read Read/Poll
FC04 Read Input Registers Read Read/Poll
FC05 Write Single Coil Write Write
FC06 Write Single Register Write Write
FC15 Write Multiple Coils Write Write
FC16 Write Multiple Registers Write Write

Transport Modes

Mode Transport Framing Use Case
TCP TCP/IP socket MBAP header Standard Modbus TCP
TCP+TLS TLS over TCP MBAP header Secure Modbus TCP (TLS 1.2+)
RTU Serial port Slave ID + CRC-16 RS-485/RS-232 devices
ASCII Serial port : + hex + LRC + CRLF Legacy serial devices
RTU-over-TCP TCP/IP socket Slave ID + CRC-16 Industrial gateways

Build from Source

Prerequisites

Steps

# install frontend dependencies (npm workspaces — run once at the repo root)
npm install

# run the Slave
cd crates/modbussim-app && cargo tauri dev

# run the Master
cd crates/modbusmaster-app && cargo tauri dev

Build installers

cd crates/modbussim-app && cargo tauri build
cd crates/modbusmaster-app && cargo tauri build

Run tests

cargo test --workspace

Quick Start (Tutorial)

A full round-trip in six steps — drive the simulated Slave from the Master, no hardware required. (Screenshots show the Chinese UI; flip to English any time with the 中 / EN toggle.)

Install first: grab the installer for your platform from the Releases page, or run from source (cargo tauri dev). Open both ModbusSlave and ModbusMaster.

Step 1 · Slave — create a server with registers

Open ModbusSlave and click 新建连接 (New Connection): pick TCP, a port (e.g. 502) and random initialization — the server starts with a device pre-filled across all four register types (coils, discrete inputs, holding and input registers). Turn on 随机变化 (Random Mutation) to make values move; click any row to decode it in the value panel.

ModbusSlave with running server, mutating registers and value panel

Tip · default init & batch add: new slaves pre-fill addresses 0–20,000 across all four register types, and batch-add handles up to 50,000 entries per operation.

Step 2 · Master — create a connection

Open ModbusMaster and click 新建连接 (New Connection). The defaults already target the local Slave: address 127.0.0.1, port 502, slave ID 1. Tick 启用 TLS (Enable TLS) for a secure link. Click 创建 (Create), then 连接 (Connect).

New Connection dialog

Tip · SOCKS5 proxy: on TCP, TCP+TLS and RTU-over-TCP, tick Use SOCKS5 proxy to route the connection through a proxy with optional username/password authentication and proxy-side DNS resolution — handy when the target sits behind a jump host or industrial gateway.

Step 3 · Master — scan groups fill the table

Add scan groups (e.g. holding registers 0–59 and coils 0–31) and start polling. The connection tree shows each group with its function code and range; the table refreshes on every poll with the values served by the Slave.

Master data table polling the slave

Step 4 · Slave — drive values with data sources & mutation

Back on the Slave, make the registers move and watch them surface on the Master's next poll:

  • Right-click → 数据源 (Data Source) on any register — pick Fixed, Random, Sine, Sawtooth, Triangle, Counter or CSV sequence playback, each with its own update interval and wave parameters.
  • Right-click → 模拟设置 (Open Simulation Settings) on any row — or Ctrl/Shift multi-select several rows first — to apply one schedule (翻转 / 递增 / 递减 / 随机) to all selected points at once. The drawer also lists every active simulation with its live current value and a per-row stop; single-point tuning stays one right-click away via 周期变位 (Periodic Mutation).
  • Both settings persist in .modbusproj project files, so a saved scenario replays identically after reload.

Step 5 · Master — write back

Use 写入 (Write) on the Master to send FC05/06/15/16 — single/multiple coils and registers. Confirm the change lands on the Slave's table (and in its communication log) before the next poll.

Step 6 · Read the wire — decoded frames

Expand 通信日志 (Communication Log) at the bottom: every TX/RX pair is decoded — direction, function code and a readable detail (R 0 x60, 60 regs), filterable by direction / function code / text and exportable to CSV. The master's auto-reconnect attempts are all logged.

Communication log with decoded frames

That's the full round-trip — server, registers, polling, simulation, write-back and wire-level inspection, all on your desktop.

Architecture

ModbusSim/
├── crates/
│   ├── modbussim-core/            # Core library: protocol, transports, registers, logging
│   │   └── src/
│   │       ├── slave.rs / master.rs           # Slave & Master connection (TCP/RTU/ASCII/RtuOverTcp dispatch)
│   │       ├── frame.rs / pdu.rs / parse.rs   # RTU/ASCII frame encode/decode, Modbus PDU parsing
│   │       ├── mbap.rs                        # MBAP frame encoding/decoding (for TLS mode)
│   │       ├── tls_slave.rs / tls_master.rs   # TLS-enabled Modbus TCP slave server & master client
│   │       ├── ascii_slave.rs / ascii_master.rs       # ASCII serial transport
│   │       ├── rtu_slave.rs / rtu_master.rs           # RTU serial transport
│   │       ├── rtu_tcp_slave.rs / rtu_tcp_master.rs   # RTU-over-TCP transport
│   │       ├── socks5.rs                      # SOCKS5 CONNECT proxying for Master network transports
│   │       ├── transport.rs                   # Transport enum, serial config, TLS config, port enumeration
│   │       ├── register.rs                    # Register types, encoding/decoding (incl. wide 32-bit values)
│   │       ├── data_source.rs                 # Per-point data sources (sine, counter, CSV playback…)
│   │       ├── mutation.rs                    # Per-point periodic mutation schedules
│   │       ├── reconnect.rs                   # Reconnect policy with exponential backoff
│   │       ├── error.rs                       # Unified ModbusError enum
│   │       ├── project.rs                     # .modbusproj file save/load/migrate
│   │       ├── config.rs                      # Connection & scan-group configuration types
│   │       └── log_collector.rs / log_entry.rs / log_helpers.rs  # Thread-safe log ring buffer
│   ├── modbussim-app/             # Slave Tauri application — ModbusSlave
│   └── modbusmaster-app/          # Master Tauri application — ModbusMaster
├── frontend/                      # Slave Vue 3 frontend
├── master-frontend/               # Master Vue 3 frontend
└── shared-frontend/               # Shared Vue components, composables, i18n
Layer Stack
Backend Rust, Tokio (async runtime), tokio-modbus, tokio-serial, native-tls (macOS Security.framework / Linux OpenSSL / Windows SChannel), serialport
Frontend Vue 3, TypeScript, Vite, @tanstack/vue-virtual
Desktop Tauri 2

Contributing

Issues and pull requests are welcome. For a code change, please make sure cargo test --workspace passes (plus the frontend type checks) before opening a PR.

Changelog

See CHANGELOG.md or the Releases page.

Starting from v0.16.0, both apps check GitHub Releases on startup and prompt to install new versions. Users on pre-0.16 builds need to upgrade manually once.

macOS First Launch

The bundles are not Apple-notarized (no paid Developer Program). On first launch macOS shows "ModbusSlave / ModbusMaster cannot be opened — Apple could not verify…" with only Done and Move to Trash buttons. This is the standard macOS 15 (Sequoia) block for ad-hoc-signed apps — the app is not damaged.

How to allow it (pick one)

1. GUI path

  • Double-click the .app, see the block dialog, click Done.
  • Open System Settings → Privacy & Security, scroll to the bottom.
  • You'll see "ModbusSlave was blocked…" — click Open Anyway and enter your password.
  • The next dialog has an Open button; click it. Subsequent launches go straight through.

2. One-line Terminal

xattr -dr com.apple.quarantine "/Applications/ModbusSlave.app"
xattr -dr com.apple.quarantine "/Applications/ModbusMaster.app"

Strips the quarantine flag so macOS stops blocking.

Anonymous Usage Analytics

ModbusSim sends an anonymous app_started event on launch via Aptabase, so the author can see install counts, active usage, and version/OS distribution. It collects no personal data — only app version, OS, locale, and an approximate country derived from your IP (the IP itself is never stored). You can turn it off anytime via the ⓘ "About" popover in the toolbar.

License

MIT

About

Cross-platform Modbus simulation suite — ModbusSlave (server) + ModbusMaster (client). Tauri 2 / Vue 3 and native Rust / egui builds. TCP, TCP+TLS, RTU, ASCII, RTU-over-TCP.

Topics

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages