GridGhost is a lightweight, high-performance Modbus (and soon BACnet) device simulator designed for BMS (Building Management System) testing, commissioning, and development. It allows engineers to simulate complex field devices with dynamic data generators without physical hardware.
Warning
BETA VERSION: This project is currently in Beta. While core Modbus features are stable, you may encounter bugs. Contributions and feedback are welcome!
Important
Platform Support: The current release provides a native Windows Installer. However, since GridGhost is built on .NET 8 and Avalonia UI, support for Linux and macOS is in the roadmap and technically compatible.
- Multi-Protocol Support: Modbus TCP (Fully implemented), BACnet (Roadmap).
- Niagara Integration Support:
- 16-bit Scaled Registers: Automatic conversion between simulation floats and Modbus Int16/UInt16 using configurable scale/offset.
- Packed Booleans: Define multiple boolean points within a single Modbus register (bit-wise mapping).
- Enum Bitfields: Map integer simulation values to specific bit-ranges in a register for high-density Niagara integration.
- Standardized Exception Codes: Correctly returns Exception Code 2 (Illegal Data Address) for unmapped registers, ensuring reliable scan synchronization.
- Direct Store Integration: No polling loops. Modbus registers map directly to the internal simulation store for real-time reactivity.
- Persistence & Logging:
- Auto-Save: Device configurations (Network, Points, etc.) are automatically saved to
%APPDATA%\GridGhost\config.json. - Structured Logging: Diagnostic logs are written in JSONL format to
%APPDATA%\GridGhost\logs\. - Regression Harness: Built-in C#
SmokeRunnerservice for automated self-tests of protocol compliance.
- Auto-Save: Device configurations (Network, Points, etc.) are automatically saved to
- Robust Lifecycle: Thread-safe device start/stop operations with comprehensive state tracking (Starting, Running, Stopping, Faulted).
- Dynamic Data Generators:
- Sine Wave: Perfect for temperature and CO2 simulation.
- Ramp: For testing high/low alarms.
- Random: For simulating sensor noise.
- Static: For manual command/status testing.
- Template System: Quickly create devices from JSON templates (Energy Meters, AHUs, VAVs, etc.).
- Point Map UI: Dedicated view for Modbus mapping with Niagara-style addressing (e.g., 40001, 30001).
- Editable Device Config: Change ports and point types on the fly (requires stop/start for stability).
- Modern UI: Dark-themed, responsive Avalonia UI.
GridGhost is optimized for usage with Tridium Niagara. It supports the following advanced features:
Instead of using 32-bit floats (which take two registers), you can use int16 or uint16 with a scale.
Example: A temperature of 25.5 with a scale of 10.0 will be written as 255 in the Modbus register.
You can save Modbus bandwidth and memory by packing up to 16 booleans into a single holding or input register.
"modbus": {
"address": 10,
"kind": "Holding",
"bitField": { "startBit": 0, "bitLength": 1 }
}Simulate Niagara enums (Ordinal points) by mapping values to labels.
"enumMapping": [
{ "value": 0, "label": "Off" },
{ "value": 1, "label": "Heating" }
]GridGhost implements a proactive validation layer that intercepts Modbus requests for unmapped registers. Instead of a generic server failure (Code 4), it returns Illegal Data Address (Code 2), allowing Niagara and other supervisors to accurately map available data points without timing out or failing the device.
GridGhost v1.2.0 introduces strict compliance features to match the robustness of hardware devices:
-
Strict Exception Handling:
- Code 02 (Illegal Data Address): Returned if any address in a Read/Write request is unmapped. This ensures supervisors like Niagara fail fast on configuration errors instead of receiving garbage data.
- Code 03 (Illegal Data Value): Returned if attempting to write to a point marked as
Access: Read.
-
New Function Codes verified:
- FC 05 (Write Single Coil) & FC 15 (0x0F) (Write Multiple Coils).
- FC 06 (Write Single Register) & FC 16 (0x10) (Write Multiple Registers).
-
Access Control & Overrides:
Access: Set toRead,Write, orReadWrite(Default) in your template.OverrideMode: Set toForceStaticto automatically switch a Generator-controlled point to "Static" mode when written to externally.
-
Export Map:
-
Generate a CSV file containing the full Modbus map (Name, Address, Type, Scale, Access) directly from the device view.
GridGhost v1.4.0 features a landing splash screen using a frame-based PNG sequence.
- Path:
DeviceSim/DeviceSim.App/Assets/splash_frames/ - Naming:
ezgif-frame-001.pngtoezgif-frame-048.png. - Performance: Frames are pre-cached on startup. If assets are missing, the app falls back to the GridGhost static icon.
- Framework: .NET 8, Avalonia UI
- Protocols: NModbus4
- MVVM: CommunityToolkit.Mvvm
- Basic Simulation Engine.
- Modbus TCP Server implementation.
- Template-based device instantiation.
- Direct binding loop-free architecture.
- Auto-Save Configuration: Persist your workspace configuration to JSON.
- Structured Logging: Save simulation logs to JSONL for analysis.
- Custom Templates UI: A proper visual editor for creating and modifying templates within the app.
- BACnet/IP Support: Full implementation of a simulated BACnet stack.
- Scripting Engine: Use C# or Python scripts to define complex point dependencies (e.g., if Pump is ON, Flow increases).
- Web Dashboard: Remote monitor for the running simulation.
- .NET 8 SDK
dotnet run --project DeviceSim/DeviceSim.App/DeviceSim.App.csprojTo generate a single-file executable for Windows:
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=trueTo build the Windows installer (requires Inno Setup 6):
- Run
build.ps1to publish the app. - Compile
setup.isswith ISCC.exe.
./build.ps1
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup.iss- .NET 8 SDK
libfontconfig1(for Avalonia UI)
Use the provided script or dotnet commands:
# Make script executable
chmod +x scripts/publish_linux.sh
# Run
./scripts/publish_linux.shOr manually:
dotnet publish DeviceSim/DeviceSim.App/DeviceSim.App.csproj -c Release -r linux-x64 --self-contained false -o ./publish/linux-x64cd publish/linux-x64
./DeviceSim.AppNote: Binding to ports < 1024 (e.g. standard Modbus 502) requires root privileges or
CAP_NET_BIND_SERVICE. If you seeAccessDenied, either run withsudoor use ports > 1024 (e.g. 1502).
Licensed under the Apache License, Version 2.0.
Created with ❤️ for the BMS community.