A cross-platform Modbus simulator — Slave and Master, in one desktop toolkit.
Built with Go · Wails 2 · Vue 3
English · 中文
Slave register simulation → scan-group polling → random mutation → wire-level logs
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 Go + Wails binaries for Windows, macOS and Linux, with standalone desktop bundles and manual release downloads.
- 🌏 Bilingual UI — full English / 简体中文, switchable at runtime.
- Screenshots
- Features
- Download
- Supported Function Codes
- Transport Modes
- Build from Source
- Quick Start (Tutorial)
- Architecture
- Contributing
- Changelog
- macOS First Launch
- License
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.
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.
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 · 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.
- 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
.modbusprojfiles for quick scenario switching - Serial port support — auto-detect system serial ports, configurable baud rate, data bits, stop bits, parity
- 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 Go logs 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
- Version upgrades — open Releases from Help and download the Go/Wails version manually.
- Unified error system — structured
ModbusErrorwith categorized error types (connection/protocol/application), serialized to JSON for frontend parsing - Shared Vue components — common composables, types and i18n shared between both Wails apps via the
shared-frontendnpm workspace
Download ModbusSlave or ModbusMaster from the latest Release.
| Platform | Bundle |
|---|---|
| macOS 13+ (Apple Silicon / Intel) | Universal .zip; extract and move the .app to Applications |
| Windows x64 / ARM64 | Standalone .exe for the matching architecture; requires WebView2 |
| Linux x64 | .tar.gz; binary requires GTK3 and WebKitGTK 4.0 |
The Go/Wails release replaces Rust/Tauri and requires manual installation. Verify downloads with SHA256SUMS or release-manifest.json; the previous updater cannot install these bundles.
Legacy v1 projects can be imported. Go saves v2 projects that older Rust releases cannot read, so keep your original backup. See the migration guide.
| 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 |
| 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 |
Install Go 1.27+, Node.js 22+ and the native Wails dependencies for your platform. Ubuntu 22.04 requires libgtk-3-dev libwebkit2gtk-4.0-dev; macOS requires Xcode Command Line Tools.
npm ci --ignore-scripts
npm run dev:slave:go
npm run dev:master:go
# Production bundles
npm run build:slave:go
npm run build:master:go
# Regenerate changed bindings
npm run bindings:slave:go
npm run bindings:master:go
# Validation
npm test --workspace shared-frontend
npm run test:goThe scripts use Wails v2.14.0 and supply the macOS CGO flags. See Go development.
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 (
npm run dev:slave:go/npm run dev:master:go). Open bothModbusSlaveandModbusMaster.
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.
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.
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).
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.
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.
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
.modbusprojproject files, so a saved scenario replays identically after reload.
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.
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.
That's the full round-trip — server, registers, polling, simulation, write-back and wire-level inspection, all on your desktop.
go/internal/ Protocols, transports, projects, simulation and state
go/cmd/slavegui/ Slave Wails desktop host
go/cmd/mastergui/ Master Wails desktop host
frontend/ Slave Vue frontend
master-frontend/ Master Vue frontend
shared-frontend/ Themes, translations and shared components
scripts/ Go/Wails versioning and artifact validation
Go owns protocol behavior and application state; Vue calls generated Wails bindings. The former Rust implementation remains available in Git tags v0.17.8 and earlier.
Issues and pull requests are welcome. For a code change, please make sure npm run test:go passes (plus the frontend type checks) before opening a PR.
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.
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.


