Skip to content

Latest commit

 

History

History
685 lines (441 loc) · 18 KB

File metadata and controls

685 lines (441 loc) · 18 KB

netzsim REST API

Generated by scripts/gen_api_doc.py from the FastAPI app — do not edit the endpoint reference by hand; rerun the script after API changes. The always-current interactive version is the built-in Swagger UI at http://localhost:8000/docs (ReDoc at /redoc).

Base URL: http://localhost:8000 (configure with NETZSIM_HOST/NETZSIM_PORT). No authentication — netzsim is a local teaching tool. All bodies and responses are JSON (Content-Type: application/json).

Conventions

  • Bus/line/transformer ids are pandapower element indices — integers matching the order of grid_structure.buses (and the insertion order of lines/transformers). /network is the id directory.
  • Numeric safety: result floats are rounded to 6 digits and non-finite values (NaN/±Inf) become null, so every payload parses in a browser.
  • Strict observability (NETZSIM_EXPOSE_GROUND_TRUTH=false): the solved ground truth is stripped from /state, /ws, /history, and the day-curve endpoints downgrade a requested view=truth to the measured layer (the est view keeps its estimate/measured layers but loses the truth arrays).
  • Errors use FastAPI's standard shape {"detail": "..."} with 404 (unknown element/resource), 409 (conflicting state, e.g. export already running), 400 (invalid grid document) and 422 (validation).

WebSocket /ws

ws://localhost:8000/ws pushes one JSON StepResult per solved step (the latest result is sent immediately on connect). Client messages are ignored (keepalive only). The payload equals GET /state.

Result shapes

StepResult (per step, /state · /ws · /history): step, day, time_of_day ("HH:MM"), converged, solve_ms, timestamp (unix s), buses[], lines[], trafos[], ext_grids[], summary, plus the runtime layers batteries[], controllers[], ronts[], and the observability projection measurements (readings ONLY at placed meters) with observed_summary, and estimated (the latest WLS run: buses/lines/trafos, solve_ms, seq, per-cell results on districts). The truth arrays (buses/lines/trafos/ext_grids/summary) are absent in strict mode.

Day-curve endpoints (/node|line|trafo/{id}/profiles?view=truth|measured|est) return per-view layers: the truth curves in the full input raster, the measured layer only for metered elements in their device's TAF raster (15-min means for TAF 7, pass-through for TAF 9/10/14), and the estimate in the pinned estimation raster. Absent layers are []/null.

Endpoint reference

Core

Health, topology, live results and per-element day curves (api/core.py).

GET /manual

The German user manual (docs/Benutzerhandbuch.pdf), for the Hilfe menu.

GET /health

Liveness + identity probe. app identifies netzsim when several services share a port range (e.g. netzsim next to rtheatflow) — the dev launcher only treats a listener as "already running" if it answers with app=netzsim, otherwise it moves to the next free port.

GET /status

Engine state: running, step, day, steps_per_day, tick interval, n_days.

GET /network

Static topology: buses (with layout coordinates), lines, transformers, ext_grids, ONS cells, element counts — the id directory for all other calls.

GET /node/{bus}/profiles

Daily curves at one bus. view picks the layers the caller may see: truth (load/generation split + voltage), measured (only the meter's own quantities in the metering raster), est (all layers overlaid).

parameter in type required
bus path integer yes
view query 'truth' | 'measured' | 'est' no

GET /line/{line}/profiles

Daily current + loading curve for one line, with its rated current. Lines carry no meters — the measured view is deliberately empty.

parameter in type required
line path integer yes
view query 'truth' | 'measured' | 'est' no

GET /trafo/{trafo}/profiles

Daily power exchange + loading curve for one transformer, with its rating. The measured layer appears only for a metered transformer.

parameter in type required
trafo path integer yes
view query 'truth' | 'measured' | 'est' no

GET /state

The latest solved StepResult (404 until the first solve).

GET /history

Recent StepResults from the in-memory ring buffer (newest last).

parameter in type required
limit query integer no

GET /

Tiny built-in HTML live monitor (WebSocket-fed; no build step needed).

Engine control

Start/pause/seek the accelerated-tick loop and the real-PV day calendar (api/control.py).

POST /control/start

Start the realtime loop.

POST /control/pause

Pause the loop (the last result stays served).

POST /control/resume

Resume a paused loop.

POST /control/seek

Jump to a step within the day (wraps at steps_per_day).

parameter in type required
step query integer yes

POST /control/interval

Set the accelerated-tick interval (real seconds per simulated step).

parameter in type required
seconds query number yes

POST /control/seekday

Jump to a specific real-PV day (wraps within the available days).

parameter in type required
day query integer yes

GET /pv/days

Real-PV day calendar for the day slider (empty when no cache is loaded).

Runtime equipment

Batteries, overload controllers, rONTs and per-node DERs, all placed while the simulation runs (api/equipment.py).

GET /batteries

Current batteries + available modes + whether price data is loaded.

POST /battery

Deploy a battery at a bus (strategy self | peak | price).

Body (BatteryRequest):

field type default
bus integer required
capacity_kwh number 10.0
power_kw number 5.0
mode string 'self'
soc0 number 0.5

POST /battery/{idx}/mode

Switch a deployed battery's operating strategy (self | peak | price).

parameter in type required
idx path integer yes
name query string yes

POST /battery/{idx}/size

Resize a deployed battery — standard home units at a node, freely chosen energy/power for a large battery at the substation busbar.

parameter in type required
idx path integer yes
capacity_kwh query number yes
power_kw query number yes

DELETE /battery/{idx}

Remove a deployed battery.

parameter in type required
idx path integer yes

GET /battery/{idx}/profiles

Daily SOC + charge/discharge curve (+ price) for one battery, current day.

parameter in type required
idx path integer yes

GET /controllers

Placed overload controllers with their live curtailment factors.

POST /controller

Place an overload controller (station = whole grid, bus = one node, cell = one spliced ONS cell, mv = the coordinating MV level).

Body (ControllerRequest):

field type default
scope 'station' | 'bus' | 'cell' | 'mv' 'station'
bus integer | null
cell string | null
limit_pct number 100.0

POST /controller/{cid}/config

Change a controller's loading limit.

parameter in type required
cid path integer yes
limit_pct query number yes

DELETE /controller/{cid}

Remove an overload controller.

parameter in type required
cid path integer yes

GET /ronts

Activated rONTs with their live tap positions.

POST /ront

Activate an rONT on a station transformer (one per trafo).

Body (RontRequest):

field type default
trafo integer required
v_target number 1.0
deadband number 0.015

POST /ront/{rid}/config

Change an rONT's voltage setpoint / deadband.

parameter in type required
rid path integer yes
v_target query number | null no
deadband query number | null no

DELETE /ront/{rid}

Deactivate an rONT (the transformer's original tap data is restored).

parameter in type required
rid path integer yes

GET /node/{bus}/der

The bus's configurable DERs (PV kWp, EV charge window), derived live from the profile rows — LoadStudio-assigned systems are editable too.

parameter in type required
bus path integer yes

POST /pv

Add a rooftop-PV system at a bus at runtime.

Body (PvRequest):

field type default
bus integer required
kwp number 5.0

POST /pv/{sgen}

Rescale a PV system's peak power (kWp).

parameter in type required
sgen path integer yes
kwp query number yes

DELETE /pv/{sgen}

Remove a PV system.

parameter in type required
sgen path integer yes

POST /ev

Add an EV home-charging load at a bus at runtime (1-4 h window).

Body (EvRequest):

field type default
bus integer required
kw number 11.0
start_min integer 1080
dur_min integer 120

POST /ev/{load}

Move an EV's charge window (start instant + 1-4 h duration).

parameter in type required
load path integer yes
start_min query integer yes
dur_min query integer yes

DELETE /ev/{load}

Remove an EV charging load.

parameter in type required
load path integer yes

External nodes

Live P/Q feed for individual buses — fully controlled nodes, see docs/EXTERNAL_NODES.md (api/ext.py).

GET /ext

Placed external nodes with their live status (applied value, telegram age, stale flag).

POST /ext

Attach an external node at a bus: from now on the bus's injection is fully controlled by pushed values (one node per bus).

Body (ExtCreateRequest):

field type default
bus integer required
name string | null
hold_s number 30.0
on_timeout 'hold' | 'zero' 'hold'
p_max_kw number 50.0

GET /ext/{eid}/history

The node's received-value day ring: the APPLIED kW per step of the current day (null = the engine has not passed that step since the node was placed). This is the node's 'day graph' — an external node has no forecast, only what actually arrived.

parameter in type required
eid path integer yes

PUT /ext/{eid}/value

THE hot path: push a setpoint into the node's mailbox (latest wins; the engine samples it non-blocking on its next tick).

parameter in type required
eid path integer yes

Body (ExtValueRequest):

field type default
p_kw number required
q_kvar number 0.0

POST /ext/values

Batch variant for multi-node feeders — tolerant per entry (unknown ids and out-of-bound values are reported, valid entries still apply).

Body (body):

field type default

DELETE /ext/{eid}

Detach an external node (the bus falls back to its grid profile — for an external node's zeroed row that means 0 kW).

parameter in type required
eid path integer yes

Observability & estimation

Meter placement (per-device TAF fidelity) and the WLS estimation policy (api/measurements.py).

GET /estimation/config

The active estimation policy (an operator setting: survives grid swaps).

POST /estimation/config

Swap the estimation policy; the estimator rebuilds its profile knowledge on the next solved step, so the effect is visible within seconds.

Body (EstimationConfigModel):

field type default
pv_pseudo boolean False
ev_pseudo boolean False
load_basis 'profile' | 'slp' 'profile'
slp_annual_kwh number 4000.0
pseudo_std_pct number 50.0
zero_injection boolean True
hierarchy 'auto' | 'monolithic' | 'hierarchical' 'auto'

GET /measurements

Current meter placement + coverage + available presets. expose_ground_truth tells the UI whether the true power flow is available (reveal toggle).

POST /measurements/node

Install a smart meter at a bus (upsert: an optional mode sets or changes the device's TAF fidelity — full = TAF 9/10/14 1-min telemetry, standard = TAF 7 15-min Lastgang).

Body (NodeMeterRequest):

field type default
bus integer required
mode 'full' | 'standard' | null

DELETE /measurements/node/{bus}

parameter in type required
bus path integer yes

POST /measurements/trafo

Install a measurement at a transformer (upsert; optional per-device TAF mode, see /measurements/node).

Body (TrafoMeterRequest):

field type default
trafo integer required
mode 'full' | 'standard' | null

DELETE /measurements/trafo/{trafo}

parameter in type required
trafo path integer yes

POST /measurements/mode

Meter fidelity: 'full' (V/P/Q/I every step) or 'standard' (German Lastgang metering: 15-minute mean active power only).

parameter in type required
name query string yes

POST /measurements/preset

Bulk placement: all_nodes | all_trafos | substation_trafos | digital_stations | cell_full | clear. digital_stations = one station measurement per ONS cell; cell_full (requires cell=<id>) = full SMGW rollout of that one cell.

parameter in type required
name query string yes
cell query string | null no

Grid catalog & load generation

The committed grid dataset, user grid imports, LPG load assignment and the runtime grid swap (api/grids.py).

GET /grids

List the importable grids of the committed dataset + user imports.

GET /grids/{grid_id}

Net-free topology preview of a catalog grid (+ converter notes).

parameter in type required
grid_id path string yes

POST /grids/import

Import a grid file (gridgen/gridedit JSON) into the user catalog.

The document is written to user_grids/ and validated by actually converting it; a file that does not convert is removed again (400).

Body (GridImportRequest):

field type default
doc object required
name string | null

GET /loadgen/archetypes

List the cached LPG household archetypes (steps, metadata).

POST /loadgen/assign

Preview LPG load + EV + PV assignment (deterministic given the policy).

Body (AssignRequest):

field type default
grid_id string required
policy LoadgenPolicy {'mode': 'round_robin', 'seed': 0, 'scale': 1.0, 'power_factor': 0.95, 'jitter_minutes': 0, 'ev_penetration': 0.0, 'ev_charger_kw': 11.0, 'ev_charger_mix': False, 'ev_daily_kwh': 8.0, 'pv_penetration': 0.0, 'pv_kwp': 5.0, 'pv_mix': False, 'mfh': 'off', 'mfh_min': 3, 'mfh_max': 6}

POST /config/apply

Convert a catalog grid (optionally with LPG loads + EV + PV) and swap the running engine onto it.

Body (ApplyGridRequest):

field type default
grid_id string required
loadgen LoadgenPolicy | null

GET /config/active

Metadata of the currently loaded grid (id, counts, load source, notes).

Recording & export

Session recording of the live step stream and the offline bulk export of whole days (api/recordings.py).

GET /recording

State of the session recorder (active recording, steps, size).

POST /recording/start

Start recording every published step to data/recordings//.

Body (body):

field type default

POST /recording/stop

Finish the active recording (flush, close, write metadata.json).

GET /recordings

Stored recordings (finished ones carry metadata.json).

GET /recordings/{rid}/download

The recording as a ZIP of CSVs + metadata.json.

parameter in type required
rid path string yes

DELETE /recordings/{rid}

Remove a stored recording (and its cached ZIP).

parameter in type required
rid path string yes

POST /export/days

Simulate whole days of the CURRENT setup as fast as possible and store them as a recording pack (appears under /recordings when finished).

Body (ExportDaysRequest):

field type default
days integer | array[integer] required
name string | null
estimate boolean True

GET /export

Progress of the bulk export (steps done/total, ETA, errors).

POST /export/cancel

Stop the running bulk export; the partial pack is kept and finalized.

Scenarios

Save the configured live setup as a recipe file and replay it (api/scenarios.py).

GET /scenarios

Saved scenarios (name, description, grid, created).

POST /scenarios

Save the CURRENT live setup as a scenario recipe: grid + loadgen policy

  • runtime DER ops + batteries + meters + the engine clock.

Body (ScenarioSaveRequest):

field type default
name string required
description string ''

DELETE /scenarios/{sid}

parameter in type required
sid path string yes

POST /scenarios/{sid}/load

Replay a scenario recipe: apply grid + loads, then the runtime layers (DER ops, batteries, meters), seek to the stored clock and run.

parameter in type required
sid path string yes