Generated by
scripts/gen_api_doc.pyfrom 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 athttp://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).
- Bus/line/transformer ids are pandapower element indices — integers
matching the order of
grid_structure.buses(and the insertion order of lines/transformers)./networkis 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 requestedview=truthto the measured layer (theestview 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).
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.
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.
Health, topology, live results and per-element day curves (api/core.py).
The German user manual (docs/Benutzerhandbuch.pdf), for the Hilfe menu.
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.
Engine state: running, step, day, steps_per_day, tick interval, n_days.
Static topology: buses (with layout coordinates), lines, transformers, ext_grids, ONS cells, element counts — the id directory for all other calls.
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 |
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 |
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 |
The latest solved StepResult (404 until the first solve).
Recent StepResults from the in-memory ring buffer (newest last).
| parameter | in | type | required |
|---|---|---|---|
limit |
query | integer | no |
Tiny built-in HTML live monitor (WebSocket-fed; no build step needed).
Start/pause/seek the accelerated-tick loop and the real-PV day calendar (api/control.py).
Start the realtime loop.
Pause the loop (the last result stays served).
Resume a paused loop.
Jump to a step within the day (wraps at steps_per_day).
| parameter | in | type | required |
|---|---|---|---|
step |
query | integer | yes |
Set the accelerated-tick interval (real seconds per simulated step).
| parameter | in | type | required |
|---|---|---|---|
seconds |
query | number | yes |
Jump to a specific real-PV day (wraps within the available days).
| parameter | in | type | required |
|---|---|---|---|
day |
query | integer | yes |
Real-PV day calendar for the day slider (empty when no cache is loaded).
Batteries, overload controllers, rONTs and per-node DERs, all placed while the simulation runs (api/equipment.py).
Current batteries + available modes + whether price data is loaded.
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 |
Switch a deployed battery's operating strategy (self | peak | price).
| parameter | in | type | required |
|---|---|---|---|
idx |
path | integer | yes |
name |
query | string | yes |
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 |
Remove a deployed battery.
| parameter | in | type | required |
|---|---|---|---|
idx |
path | integer | yes |
Daily SOC + charge/discharge curve (+ price) for one battery, current day.
| parameter | in | type | required |
|---|---|---|---|
idx |
path | integer | yes |
Placed overload controllers with their live curtailment factors.
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 |
Change a controller's loading limit.
| parameter | in | type | required |
|---|---|---|---|
cid |
path | integer | yes |
limit_pct |
query | number | yes |
Remove an overload controller.
| parameter | in | type | required |
|---|---|---|---|
cid |
path | integer | yes |
Activated rONTs with their live tap positions.
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 |
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 |
Deactivate an rONT (the transformer's original tap data is restored).
| parameter | in | type | required |
|---|---|---|---|
rid |
path | integer | yes |
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 |
Add a rooftop-PV system at a bus at runtime.
Body (PvRequest):
| field | type | default |
|---|---|---|
bus |
integer | required |
kwp |
number | 5.0 |
Rescale a PV system's peak power (kWp).
| parameter | in | type | required |
|---|---|---|---|
sgen |
path | integer | yes |
kwp |
query | number | yes |
Remove a PV system.
| parameter | in | type | required |
|---|---|---|---|
sgen |
path | integer | yes |
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 |
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 |
Remove an EV charging load.
| parameter | in | type | required |
|---|---|---|---|
load |
path | integer | yes |
Live P/Q feed for individual buses — fully controlled nodes, see docs/EXTERNAL_NODES.md (api/ext.py).
Placed external nodes with their live status (applied value, telegram age, stale flag).
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 |
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 |
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 |
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 |
|---|
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 |
Meter placement (per-device TAF fidelity) and the WLS estimation policy (api/measurements.py).
The active estimation policy (an operator setting: survives grid swaps).
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' |
Current meter placement + coverage + available presets. expose_ground_truth
tells the UI whether the true power flow is available (reveal toggle).
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 | — |
| parameter | in | type | required |
|---|---|---|---|
bus |
path | integer | yes |
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 | — |
| parameter | in | type | required |
|---|---|---|---|
trafo |
path | integer | yes |
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 |
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 |
The committed grid dataset, user grid imports, LPG load assignment and the runtime grid swap (api/grids.py).
List the importable grids of the committed dataset + user imports.
Net-free topology preview of a catalog grid (+ converter notes).
| parameter | in | type | required |
|---|---|---|---|
grid_id |
path | string | yes |
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 | — |
List the cached LPG household archetypes (steps, metadata).
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} |
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 | — |
Metadata of the currently loaded grid (id, counts, load source, notes).
Session recording of the live step stream and the offline bulk export of whole days (api/recordings.py).
State of the session recorder (active recording, steps, size).
Start recording every published step to data/recordings//.
Body (body):
| field | type | default |
|---|
Finish the active recording (flush, close, write metadata.json).
Stored recordings (finished ones carry metadata.json).
The recording as a ZIP of CSVs + metadata.json.
| parameter | in | type | required |
|---|---|---|---|
rid |
path | string | yes |
Remove a stored recording (and its cached ZIP).
| parameter | in | type | required |
|---|---|---|---|
rid |
path | string | yes |
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 |
Progress of the bulk export (steps done/total, ETA, errors).
Stop the running bulk export; the partial pack is kept and finalized.
Save the configured live setup as a recipe file and replay it (api/scenarios.py).
Saved scenarios (name, description, grid, created).
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 | '' |
| parameter | in | type | required |
|---|---|---|---|
sid |
path | string | yes |
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 |