Skip to content

zEhmsy/gridghost

Repository files navigation

GridGhost 👻

GitHub License GitHub Stars GitHub Forks GitHub Issues

.NET Version Language Platform Framework

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.

GridGhost Logo

Features

  • 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# SmokeRunner service for automated self-tests of protocol compliance.
  • 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.

Niagara Integration Guide

GridGhost is optimized for usage with Tridium Niagara. It supports the following advanced features:

1. 16-bit Scaled Numerics

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.

2. Packed Booleans (Bitfields)

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 }
}

3. Enum Mappings

Simulate Niagara enums (Ordinal points) by mapping values to labels.

"enumMapping": [
  { "value": 0, "label": "Off" },
  { "value": 1, "label": "Heating" }
]

4. Reliable Scanning (Exception Code 2)

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.

5. Modbus Perfection (Niagara Grade)

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 to Read, Write, or ReadWrite (Default) in your template.
    • OverrideMode: Set to ForceStatic to 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.

Splash Animation sequence

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.png to ezgif-frame-048.png.
  • Performance: Frames are pre-cached on startup. If assets are missing, the app falls back to the GridGhost static icon.

Tech Stack

  • Framework: .NET 8, Avalonia UI
  • Protocols: NModbus4
  • MVVM: CommunityToolkit.Mvvm

Roadmap 🗺️

Phase 1: Core & Modbus (Completed)

  • Basic Simulation Engine.
  • Modbus TCP Server implementation.
  • Template-based device instantiation.
  • Direct binding loop-free architecture.

Phase 2: Persistence & Usability (Completed)

  • 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.

Phase 3: BACnet & Advanced Simulation

  • 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.

Building and Running

Prerequisites

  • .NET 8 SDK

Running from source

dotnet run --project DeviceSim/DeviceSim.App/DeviceSim.App.csproj

Creating the Executable

To generate a single-file executable for Windows:

dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true

Creating the Installer

To build the Windows installer (requires Inno Setup 6):

  1. Run build.ps1 to publish the app.
  2. Compile setup.iss with ISCC.exe.
./build.ps1
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" setup.iss

Linux Build & Run

Prerequisites

  • .NET 8 SDK
  • libfontconfig1 (for Avalonia UI)

Build

Use the provided script or dotnet commands:

# Make script executable
chmod +x scripts/publish_linux.sh
# Run
./scripts/publish_linux.sh

Or manually:

dotnet publish DeviceSim/DeviceSim.App/DeviceSim.App.csproj -c Release -r linux-x64 --self-contained false -o ./publish/linux-x64

Run

cd publish/linux-x64
./DeviceSim.App

Note: Binding to ports < 1024 (e.g. standard Modbus 502) requires root privileges or CAP_NET_BIND_SERVICE. If you see AccessDenied, either run with sudo or use ports > 1024 (e.g. 1502).

License

Licensed under the Apache License, Version 2.0.


Created with ❤️ for the BMS community.