8000
Skip to content

Repository files navigation

Renewables SCADA Device Emulation and API

Full-stack SCADA device management and protocol bridging for renewable energy plants, using MQTT and the Sparkplug B JSON protocol.

Beta software. This project is under active development and is not yet production-ready. APIs, data models, and configuration may change between releases. Contributions and feedback are welcome.

Always-on service. This module is designed to run as a persistent, independent stack — separate from the core API platform. In production it is managed by Systemd Quadlet units (rootless Podman), which handle automatic startup on boot and container restarts without manual intervention.

Overview

The SCADA Device Emulation and Bridge API serves two primary roles:

  1. Device Emulation and Simulation: Runs a multi-process, physics-based fleet launcher that simulates real-world telemetry (turbines, solar arrays, BESS batteries, and weather stations) publishing Sparkplug B JSON payloads over an MQTT broker.
  2. SCADA Protocol Bridging: Runs an ingestor worker that subscribes to raw MQTT data streams, resolves device-to-plant mappings, standardizes tag naming, and forwards telemetry to the downstream core platform (renewables-api).

Component Breakdown

  • Astro Web UI (frontend/): An operator dashboard (running on port 4322) to manage simulated devices, dynamically inspect telemetry, and configure metric simulator behaviors.
  • FastAPI Bridge API (backend/): Provides REST endpoints (running on port 8001) to manage the SQLite device registry (data/scada.db) and query the in-memory MQTT LKV (Last Known Value) cache.
  • Fleet Launcher (simulator/): A Python orchestration script that spawns independent async simulator processes for each configured device, mapping weather station datasets and dynamic mathematical functions onto telemetry tags.
  • Ingestor Worker (scada_ingestor): A lightweight worker process that bridges MQTT streams to the central SCADA database by routing messages based on name prefixes.

Key Concepts

  1. Sparkplug B over MQTT: All emulated devices publish Sparkplug B JSON payloads (NBIRTH, NDATA, NDEATH), providing a standardised device lifecycle and telemetry model.
  2. Python Fleet Launcher: The fleet launcher (simulator/fleet_launcher.py) spawns one lightweight Python process per emulated device. It polls the API every 10 seconds and picks up new or deleted devices without a restart.
  3. Dynamic Metric Configuration: Metric definitions are stored in the device_metrics DB table. On first access the backend seeds per-type defaults (all strategy=physics). You can change any metric to sine, random, ramp, or constant via the API; the simulator picks this up at next startup.
  4. Ingestor & Forwarding: The scada_ingestor worker subscribes to MQTT streams, resolves plant mapping (e.g. WT_ → Wind Plant), and forwards structured payloads to the downstream API.

Architecture

Frontend (Astro) ──HTTP──▶ Backend (FastAPI)
                                  │
                                  ▼
                            SQLite DB (devices, device_metrics, mappings)
                            ./data/weather/ (shared weather CSV)

        MQTT Broker (Mosquitto) ◀── Sparkplug B JSON ──▶ Fleet Launcher
                 │                                         (N × Python processes)
                 └──────────▶ Ingestor (MqttAdapter) ──▶ renewables-api (TimescaleDB)
renewables-scada-mqtt/
├── backend/
│   ├── scripts/                # Utility scripts (seeding, etc.)
│   └── src/
│       ├── domain/devices/         # Device + DeviceMetric models, per-type defaults
│       ├── infrastructure/
│       │   ├── connectors/         # MqttAdapter, MQTT LKV Cache
│       │   └── persistence/        # SQLAlchemy/SQLite
│       └── infrastructure/worker/  # Ingestor (MQTT → HTTP forwarding)
├── frontend/                       # Astro UI (Dashboard, Device Registry, Browse)
├── simulator/
│   ├── fleet_launcher.py           # Spawns per-device processes
│   └── src/                        # Physics models + DynamicMetricLoader
├── Ingestor.Dockerfile             # Ingestor container build
├── docker-compose.yml              # Broker, API, UI, Ingestor
└── manage.py                       # Orchestration script

Getting Started

Prerequisites

  • Podman and podman-compose
  • Python 3.12+

Launch the Stack

# Production mode — starts infrastructure + fleet launcher
python3 manage.py up

# Dev mode — bind-mounts source, hot-reloads API and frontend, runs fleet launcher
python3 manage.py dev

up and dev both start infrastructure in the background then run the fleet launcher in the foreground. Ctrl+C stops the simulators; manage.py down stops the containers.

Mock Data & Seeding

# Seed mock sites and stations
PYTHONPATH=. python3 backend/scripts/seed_mock_data.py --clear

Other Commands

python3 manage.py build   # Rebuild backend/frontend images after code changes
python3 manage.py fleet   # Fleet launcher only (infrastructure must already be running)
python3 manage.py down    # Stop and remove containers
python3 manage.py status  # Show container status

Service Endpoints

Service URL
Management UI http://localhost:4322
Bridge API (Swagger) http://localhost:8001/docs
MQTT Broker localhost:1883

Ingestor Environment Variables

Variable Default Description
SCADA_INTAKE_URL mqtt_broker:1883 MQTT broker address
SCADA_INTAKE_PLANT_ID 1 Fallback plant ID when no prefix matches
SCADA_INTAKE_FORWARD_URL (empty) Downstream renewables-api endpoint; empty = discard
PLANT_ID_WIND SCADA_INTAKE_PLANT_ID Plant ID for WT_ devices
PLANT_ID_SOLAR SCADA_INTAKE_PLANT_ID Plant ID for INV_ devices
PLANT_ID_WEATHER SCADA_INTAKE_PLANT_ID Plant ID for WX_ devices
PLANT_ID_BESS SCADA_INTAKE_PLANT_ID Plant ID for BESS_ devices

Further Documentation

Document Description
renewables-api The companion platform that ingests, stores, and visualizes telemetry from this bridge. Refer to that repo for fleet management details, metric strategies, and adding new device types.
renewables-db TimescaleDB + Redis infrastructure required by renewables-api. Must be running before the ingestor can forward telemetry.

About

Physics-based MQTT fleet simulator and Sparkplug B protocol bridge for renewable energy SCADA. Multi-process Python simulator with IEC power curves, AR(1) weather engine, and dynamic metric strategies.

Topics

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

0