Skip to main content

GridOS (under construction)

License: MIT Python 3.11+ CI FastAPI

GridOS is a lightweight FastAPI service for DER device registration, telemetry ingestion, telemetry lookup, and basic control workflows.

The repository still contains broader experimental areas such as digital twin simulation, forecasting, and optimisation. Those modules remain available for contributors. The supported first-run experience is intentionally smaller so that a new user can clone the repository, start the API, send telemetry, and confirm a working result without being forced into a large deployment.

What The Current Release Supports

Area Supported launch scope
API service FastAPI app with /, /health, /docs, device routes, telemetry routes, and control routes
Telemetry Single and batch ingestion, latest-value lookup, and bounded history queries
Control Command acceptance with honest adapter status reporting
Live device connectivity Modbus TCP and MQTT adapters with built-in device/broker simulators; connect, poll live telemetry, and dispatch control over REST
Register maps Named Modbus register maps including SunSpec-style inverter and battery presets, plus inline custom maps
Browser demo A no-terminal /demo page that drives the full device lifecycle for prospects
Economic dispatch & ROI Value-stacked battery dispatch (arbitrage + demand-charge + degradation) and a baseline-vs-optimised ROI backtest, via /api/v1/economics/*
Authentication Optional API-key gate on mutating endpoints (GRIDOS_REQUIRE_AUTH), off by default
Default storage In-memory mode for local development and demos
Persistent storage SQLite file backend with no external service or extra dependencies
Optional persistence InfluxDB and TimescaleDB when configured explicitly
Packaging Editable install, reduced dependency groups, Docker image, and CI workflows

What Is Still Experimental

Area Current position
Protocol adapters Present in the repository but not part of the launch-critical path
Digital twin simulation Experimental helper modules, not required for first use
Forecasting Optional module, not mounted in the default app
Optimisation Optional module, not mounted in the default app
Large multi-service deployment Deferred until the core local path stays stable

Why The Scope Is Smaller

This smaller scope is intentional. It is better for GridOS to be simple, reliable, and truthful than broad and internally inconsistent. The current work focuses on a dependable end-to-end path that works from a fresh clone. Experimental modules are still available for contributors, but the public launch story now matches what the repository can support immediately.

Architecture At A Glance

flowchart LR
    A[Client or Script] --> B[FastAPI Service]
    B --> C[Device Routes]
    B --> D[Telemetry Routes]
    B --> E[Control Routes]
    D --> F[In-Memory Storage by Default]
    F --> G[History and Latest Queries]
    D -. optional .-> H[InfluxDB]
    D -. optional .-> I[TimescaleDB]
    J[Experimental Modules] -. not in default app .-> B

Repository Layout

Path Role
src/gridos/main.py Active FastAPI entry point for the reduced launch path
src/gridos/api/ API routes, dependency wiring, and WebSocket manager
src/gridos/models/ Small Pydantic model surface for the supported workflow
src/gridos/storage/ Storage interface plus optional persistent backends
src/gridos/digital_twin/ Experimental simulation and ML helpers kept outside the default runtime path
docs/ Documentation aligned to the current supported scope
requirements/ Reduced dependency groups for base, dev, ml, and production
tests/ Regression tests for the lightweight supported path

Quick Start

Run from source

git clone https://github.com/iceccarelli/GridOS.git
cd GridOS
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
cp .env.example .env
uvicorn gridos.main:app --host 0.0.0.0 --port 8000 --reload

Then open:

http://localhost:8000/docs

Run with Docker Compose

cp .env.example .env
docker compose up --build

Then open:

http://localhost:8000/docs

Live Device Connectivity (Modbus)

GridOS can talk to real DER hardware over Modbus TCP, and ships a built-in device simulator so the full loop is demonstrable without hardware:

pip install -e ".[adapters]"

# Terminal 1 — emulate a battery on Modbus TCP:
gridos simulate --port 5020

# Terminal 2 — run the API, then drive the device over REST:
gridos serve

Register a device with an adapter_config, then connect, poll live telemetry, and dispatch control:

BASE=http://127.0.0.1:8000/api/v1
curl -s -X POST $BASE/devices/register -H 'Content-Type: application/json' -d '{
  "device": {"device_id":"batt-1","name":"Battery","der_type":"battery","rated_power_kw":100},
  "adapter_config": {"protocol":"modbus_tcp","host":"127.0.0.1","port":5020}
}'
curl -s -X POST $BASE/devices/batt-1/connect      # attach + connect the adapter
curl -s -X POST $BASE/devices/batt-1/poll         # read LIVE telemetry, persist + broadcast it
curl -s -X POST $BASE/control/batt-1 -H 'Content-Type: application/json' \
     -d '{"device_id":"batt-1","mode":"power_setpoint","setpoint_kw":40}'

A complete scripted walkthrough (including a restart to prove device persistence) lives at scripts/demo_modbus.sh.

Register maps (SunSpec)

The Modbus adapter resolves a register map from adapter_config["register_map"], which may be a named preset or an inline custom map. Presets include gridos_default, sunspec_inverter, and sunspec_battery:

{"protocol": "modbus_tcp", "host": "127.0.0.1", "port": 5020, "register_map": "sunspec_inverter"}

The sunspec_* presets approximate the SunSpec information models for common inverter/battery measurement points using fixed scale factors; full SunSpec scale-factor decoding is a future enhancement, and inline maps cover exact hardware. The simulator can emulate any map: gridos simulate seeds registers from the chosen layout.

Live Device Connectivity (MQTT)

For EV chargers and IoT gateways that push telemetry, GridOS ships an MQTT adapter and a self-contained broker simulator:

# Terminal 1 — broker simulator that also publishes battery telemetry:
gridos simulate --protocol mqtt --port 1883

# Register an MQTT device and drive it the same way as Modbus:
curl -s -X POST $BASE/devices/register -H 'Content-Type: application/json' -d '{
  "device": {"device_id":"ev-1","name":"EV Charger","der_type":"ev_charger","rated_power_kw":11},
  "adapter_config": {"protocol":"mqtt","host":"127.0.0.1","port":1883,
                     "telemetry_topic":"gridos/mqtt-sim/telemetry"}
}'
curl -s -X POST $BASE/devices/ev-1/connect
curl -s -X POST $BASE/devices/ev-1/poll

For production, point the adapter at any MQTT broker (e.g. Mosquitto).

Browser Demo

Run gridos serve and open http://127.0.0.1:8000/demo — a no-terminal page that registers a device, connects its adapter, polls live telemetry (with an auto-poll mode), and dispatches a setpoint, all from the browser. Start gridos simulate alongside it and a prospect can watch the full loop without touching a command line.

Economic Dispatch & ROI

GridOS can answer the question a battery owner actually cares about: how much money does this asset make? The economics engine solves a value-stacked MILP (PuLP/CBC) that minimises the total electricity bill across three streams — energy arbitrage, monthly demand-charge reduction, and throughput-based degradation cost — then backtests the optimised schedule against a no-battery baseline.

pip install -e ".[economics]"   # pulls the PuLP solver

# Representative-day demo (prints savings + payback):
PYTHONPATH=src python scripts/roi_demo.py

# Or over REST:
BASE=http://127.0.0.1:8000/api/v1
curl -s -X POST $BASE/economics/roi -H 'Content-Type: application/json' -d '{
  "load_kw": [50, 50, 120, 120, 60, 60, 50, 50],
  "solar_kw": [0, 0, 30, 40, 20, 10, 0, 0],
  "battery": {"capacity_kwh": 215, "max_discharge_kw": 100, "capex": 95000}
}'

The economics routes are mounted by default. Without the [economics] extra they return a clear 503 with remediation rather than crashing the app.

ROI figures are representative-day backtests under perfect foresight of load and solar — illustrative, not guarantees. A receding-horizon (MPC) controller and per-site interval data are the honest next steps before quoting a figure.

Live Control (MPC)

The ROI backtest above assumes perfect foresight. A real site does not have it - it forecasts the next few hours and re-plans continuously. GridOS ships that loop: a forecaster learns the site's daily shape from history, and a receding-horizon controller re-optimises every control block, committing only the next action against live data.

PYTHONPATH=src python scripts/mpc_demo.py

The closed loop scores itself against a perfect-foresight oracle and a no-battery baseline, reporting the capture rate - the share of achievable savings the live controller realises under imperfect foresight. A low capture rate points at the forecast model (which is pluggable), not the solver.

Cold starts without historical telemetry can underperform the baseline; real deployments seed the controller with site history. The capture rate keeps that honest rather than hiding it.

Authentication

By default GridOS runs open, which suits local development and demos. To require credentials on mutating endpoints, set two environment variables:

GRIDOS_REQUIRE_AUTH=true
GRIDOS_API_KEYS=gos_your_first_key,gos_your_second_key

When enabled, POST /api/v1/devices/register, DELETE /api/v1/devices/{id}, POST /api/v1/telemetry/, POST /api/v1/telemetry/batch, and POST /api/v1/control/{id} require a matching X-API-Key header. Read endpoints remain open. Check the current posture at GET /api/v1/auth/status.

Default Runtime Behavior

The default .env.example enables in-memory storage. That means the first run does not require any external database.

Mode Intended use
GRIDOS_USE_INMEMORY_STORAGE=true Local development, demos, and validation
GRIDOS_USE_INMEMORY_STORAGE=false + GRIDOS_STORAGE_BACKEND=sqlite Persistent local file storage, no external service
GRIDOS_USE_INMEMORY_STORAGE=false + InfluxDB config Explicit persistent backend setup
GRIDOS_USE_INMEMORY_STORAGE=false + TimescaleDB config Explicit persistent backend setup

Installation Targets

Install target Command
Core development path pip install -e ".[dev]"
Add persistent storage drivers pip install -e ".[storage]"
Add adapter extras pip install -e ".[adapters]"
Add ML extras pip install -e ".[ml]"

Testing

Protect the supported scope first.

pytest tests/test_api.py tests/test_models.py tests/test_storage.py -v --tb=short

Documentation Guide

The most important docs for the current release are:

Document Purpose
docs/quickstart.md Get a working local instance running
docs/deployment.md Understand the supported deployment story
docs/api_reference.md Confirm the active and optional API surface
docs/models.md Understand the real model layer
docs/adapters.md See the adapter framework boundaries
docs/architecture.md See the reduced launch architecture

Contributing

Contributions are welcome, especially when they improve startup reliability, telemetry handling, testing, packaging, and documentation consistency. The priority is to strengthen the lightweight path before expanding the public scope again.

License

GridOS is released under the MIT License.

Metadata

Release files for gridos 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gridos 0.4.0
File Size Uploaded
gridos-0.4.0.tar.gz 104.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gridos 0.4.0
File Interpreter ABI Platform
gridos-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 229.5 kB

Release files / gridos-0.4.0.tar.gz

Download URL gridos-0.4.0.tar.gz
Size 104.9 kB
Tags Source
SHA-256 checksum
How to use checksums
704e4a8a53cad3fe81e7271a4c397ce63e6c4a52a4563cddf33075c955eedb2f
BLAKE2b-256 checksum
How to use checksums
70cdebc429cc10d583844187f6957e492dea566139eb588ae98e6a6268b88252
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.1

Release files / gridos-0.4.0-py3-none-any.whl

Download URL gridos-0.4.0-py3-none-any.whl
Size 124.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f497e7c25113379fff7dfc08d5721f6da7db2404ea961e9739c967a4cb6bcf1a
BLAKE2b-256 checksum
How to use checksums
e4a66099ba2a116152f497dac4b3aa5937f152d4a79253d20914c6b0e4124150
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.1

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page