Caution
This repo is almost entirely vibe-coded. Do not expect quality, but also, let me assure you it would be even worse if I attempted to write this myself.
Postgres database of GB power grid data, fed from the Elexon BMRS Insights API.
nix develop # auto-starts an ephemeral Postgres in .postgres/
uv sync --extra dev
gb-grid migrate # apply yoyo migrations (the devShell does this for you)
gb-grid backfill --from 2026-04-01 --to 2026-05-01
gb-grid run # always-on ingester (run under systemd in prod)
gb-grid status
gb-grid sql # opens psql against $GB_GRID_DATABASE_URLThe devShell exports GB_GRID_DATABASE_URL and standard PG* vars, so psql,
pg_dump, GUI clients (host 127.0.0.1, port 5433, user = $USER, no
password), the test suite, and the CLI all just work.
| Table | Source | Cadence |
|---|---|---|
fuelinst |
BMRS FUELINST |
5 min |
b1610 |
BMRS B1610 (per-BMU actuals) |
30 min, ~5 working days lag |
boalf |
BMRS BOALF (balancing acceptances) |
5 min |
pn |
BMRS PN (physical notifications) |
5 min |
mels |
BMRS MELS (max export levels) |
5 min |
system_prices |
BMRS settlement system prices | hourly |
gb-grid migrate— apply pending yoyo migrationsgb-grid backfill --from YYYY-MM-DD --to YYYY-MM-DD [--dataset fuelinst,b1610,...]gb-grid materialize-dispatch --from YYYY-MM-DD --to YYYY-MM-DD [--bmu PEHE-1 ...]— recompute per-BMU dispatch series intobmu_dispatch(5-min resolution, only BMUs with BOA acceptances in the window)gb-grid run— always-on async scheduler (also rolls the materialized table forward)gb-grid status— row counts and latest timestampsgb-grid sql— openpsqlagainst the configured database
The devShell starts an ephemeral Grafana on http://localhost:3000 (anonymous
Editor access; admin/admin if you want to log in). It's provisioned from
grafana/:
provisioning/datasources/postgres.yaml— the local Postgres datasource (uidgbgrid)provisioning/dashboards/dashboards.yaml— file provider pointing atgrafana/dashboards/dashboards/bmu_dispatch.json— pick a station (or click one on the map) to see station-aggregate PN, dispatched, MEL and B1610, a stacked dispatched-per-BMU breakdown, and turn-up / curtailment
Note
The PN / Dispatched / B1610 series on the station-total panel still need work: the three are sourced from different streams (interpolated PN+BOALF vs. half-hourly settlement actuals) and don't always reconcile cleanly, especially around BOA acceptances and during B1610's ~5-working-day lag. Treat them as a sanity check on each other, not as the same number.
Backfill, then materialize, then open Grafana:
gb-grid backfill --from 2026-04-01 --to 2026-04-07
gb-grid materialize-dispatch --from 2026-04-01 --to 2026-04-07
xdg-open http://localhost:3000/d/bmu-dispatchSchema lives in src/gb_grid/migrations/ as numbered SQL files, applied with
yoyo-migrations. Add a new file
(e.g. 0002.add-foo.sql) and gb-grid migrate will apply it on next run.
| Env var | Purpose | Default |
|---|---|---|
GB_GRID_DATABASE_URL |
Postgres connection URL | (set by devShell; required otherwise) |
GB_GRID_API_BASE |
BMRS API base URL | https://data.elexon.co.uk/bmrs/api/v1 |
GB_GRID_HTTP_TIMEOUT |
HTTP timeout (seconds) | 60 |
Deployed as a NixOS LXC container — see
nix-config/gb-grid.nix for the host
recipe. The flake exposes packages.default (the Python app) for downstream
consumers.