Pegelonline (Water Levels)
Heimdall integrates with the German federal Pegelonline REST API (WSV) to provide near-real-time water level data for gauging stations near the current GPS position.
How It Works
- The
heimdall-pegelonlinecrate runs a background task (every 5 minutes) that queries the WSV API. - It uses the latest GPS position from TimescaleDB to determine the search center.
- Stations are filtered by a whitelist (specific station shortnames) or by radius (default 30 km).
- Results are cached in memory, sorted by distance (nearest first).
- The cache is served via the REST and GraphQL endpoints below.
Configuration
Add to platform/api/config/default.toml:
[pegelonline]
enabled = false
base_url = "https://pegelonline.wsv.de/webservices/rest-api/v2"
radius_km = 30.0
stations = [
# Whitelist mode: specific station shortnames
"MANNHEIM", "KÖLN", "DUISBURG-RUHRORT",
"HEIDELBERG UP", "FRANKFURT OSTHAFEN",
# Empty list = radius mode
]
Environment override: HEIMDALL__PEGELONLINE__ENABLED=true
Whitelist mode (non-empty stations): searches with a 200 km radius, filters by shortname, and then drops any whitelisted station farther than radius_km from the current position (radius_km acts as a max distance).
Radius mode (stations = []): uses radius_km around current position.
REST Endpoints
| Method | Path | Permission | Description |
|---|---|---|---|
| GET | /v1/pegel/nearest | pegel:read | Nearest gauging station |
| GET | /v1/pegel/stations | pegel:read | All cached stations |
Query params: water (waterway name filter), radius (override radius in km).
GraphQL
pegelNearest(water: String, radius: Float)→GqlPegelStationpegelStations(water: String)→[GqlPegelStation]
Response Fields
| Field | Type | Description |
|---|---|---|
station_id | string | Station UUID (WSV) |
shortname | string | Station shortname (e.g. "MANNHEIM") |
longname | string | Station full name |
water_shortname | string | Waterway shortname (e.g. "RHEIN") |
water_longname | string | Waterway full name |
latitude | float | Station latitude |
longitude | float | Station longitude |
km | float? | River kilometer |
agency | string | Responsible WSV agency |
level_cm | float? | Current water level in cm (null if unavailable) |
trend | int? | Level trend: -1 falling, 0 stable, 1 rising (null if unavailable) |
distance_km | float | Distance from current GPS position |
Example
GET /v1/pegel/nearest?water=RHEIN
{
"station_id": "a26e57c8-d8c9-4d0c-a3ad-2974e7c0e31e",
"shortname": "MANNHEIM",
"longname": "MANNHEIM",
"water_shortname": "RHEIN",
"water_longname": "RHEIN",
"latitude": 49.4875,
"longitude": 8.4660,
"km": 424.0,
"agency": "WSA Mannheim",
"level_cm": 312,
"trend": 0,
"distance_km": 0.3
}
RBAC Permissions
| Permission | Description |
|---|---|
pegel:read | View water level data |
Assigned to: role_admin (wildcard) and role_api_read_only. (Removed from role_developer in migration 20260624 — the developer role is for external API/OAuth management only.)
Frontend Hook
Use the usePegel hook from @elcto/ui:
import { usePegel } from '@elcto/ui';
const { data, loading } = usePegel({ water: 'RHEIN' });
// data: PegelData | null
The hook polls every 5 minutes and retries after 10 seconds on a 404 (no data yet).