Usage cookbook

Worked, use-case-driven examples for hochwasser. Everything prints JSON to stdout; pipe into jq at will. See the README for the command/option reference and the GLOSSARY for every domain term (especially the two different lhpClass scales).

Attribution reminder (CC BY 4.0): when you show this data to anyone, cite “Quelle: Länderübergreifendes Hochwasserportal (LHP)” (https://www.hochwasserzentralen.de) and display the updated timestamp. Every output of this CLI carries both.

“Are there flood warnings right now?”

hochwasser alerts

An empty data array (exit 0) is the happy answer: no active alerts. An answer whose envelope reports anything but "status": "success" is an error instead (exit 1, The API reported status "error" … : <the API's message>), never printed as data or written to -o. Headlines only:

hochwasser --compact alerts | jq -r '.data[] | [.id, .lhpClassName, .areaDesc] | @tsv'

“Warnings in Bavaria and Saxony, with full detail”

hochwasser alerts --states BY,SN --cap

--states is validated (a typo exits 2 instead of silently returning everything); --cap adds the Common Alerting Protocol block — the cap.info.instruction field carries the “what should I do” text:

hochwasser --compact alerts --states BY --cap \
  | jq -r '.data[] | "\(.areaDesc): \(.cap.info.severity // "n/a") — \(.cap.info.instruction // "-")"'

“How bad is it at the gauges?”

# Everything in Berlin
hochwasser stations --states BE

# Only gauges actually showing flood (class >= 1), nationwide
hochwasser stations --min-class 1

# Gauges on waters whose name contains "Elbe" (case-insensitive; ß = ss, so NEISSE finds "Lausitzer Neiße";
# ä/ö/ü = ae/oe/ue, so Roeder finds "Große Röder"; a double space, tab or no-break space counts as one space)
hochwasser stations --water elbe

# Combine: Saxon Elbe gauges at class >= 2, in English
hochwasser stations --states SN --water elbe --min-class 2 --lang en

Note: stations gives the flood classification only. For measured water levels use the sibling pegel-online-cli (pegel current DRESDEN).

“One-screen national overview”

hochwasser situation

Per state: station count per lhpClass (classes, keys in the order "0".."4", then "-1" — read them by key, not by position) plus the state’s worst class, worst first. Every state is listed (with --states, each requested one): a state without any LHP gauge in the data (Hamburg, today) comes last with stations: 0 and worstClass/worstClassName null — “no gauges”, not class -1 “no data”. The national worstClass is null only when no gauge was returned at all. As a terminal table:

hochwasser --compact situation \
  | jq -r '.states[] | [.state, .stations, .worstClass, .worstClassName] | @tsv' \
  | column -t

The aggregate also carries the national worstClass, the updated timestamp and the response’s lang (the API cache can answer --lang en in German; class names then stay German) — a one-liner health check:

hochwasser --compact situation | jq -r '"\(.worstClassName) (Stand: \(.updated))"'

“Put it on a map” (GeoJSON)

# All alert areas (Polygons, or LineStrings for river reaches)
hochwasser alerts --geojson -o alerts.geojson

# Bavarian gauges as points, only those classified 0 or higher
# (drops "no data" (-1) and unclassified (lhpClass null) gauges)
hochwasser stations --states BY --min-class 0 --geojson -o bayern-pegel.geojson

The CLI refuses to overwrite an existing file (exit 2) unless you pass --force — also when a symlink, even a dangling one, sits at that path — and confirms what it wrote on stderr:

2026-10-09T14:03:12.481Z INFO  [hochwasser.output] Wrote 243 features (130359 bytes) to bayern-pegel.geojson

Items without a usable geometry (an alert area without a GeoJSON geometry, a gauge without coordinates, a position outside ±180/±90) can’t go on a map and are left out — but never silently: the confirmation adds the count, and a note names them, to a file and to stdout alike:

2026-10-09T14:03:12.481Z INFO  [hochwasser.output] Wrote 1 feature (13599 bytes) to map.geojson; 2 alerts skipped (no usable geometry)
2026-10-09T14:03:12.481Z INFO  [hochwasser.output] 2 alerts left off the map (no usable geometry): BY_1 (class 6, Sehr großes Hochwasser, Donau), BY_2 (class 2, …)

Open the file at https://geojson.io or load it into Leaflet/QGIS. Coordinates are [longitude, latitude] (RFC 7946), and the collection’s bbox is [west, south, east, north] around the exported features. The collection’s top-level source, licence and updated members are your attribution — keep them. updated always carries a +01:00 offset, also in summer; convert it to German local time before you show it.

“Demo it without a flood” (test system)

The production alerts feed is usually empty (good!). The LHP test system serves fixed data with plenty of alerts:

hochwasser --base-url https://api.hochwasserzentralen.de/public/v1/test alerts --cap
hochwasser --base-url https://api.hochwasserzentralen.de/public/v1/test stations --min-class 2

A --base-url on plain http: to a host other than loopback (a mirror) gets one warning record on stderr before the first request — WARN [hochwasser.http] requests to <host> are sent unencrypted (http:, not https:), or “the base URL’s credentials are sent unencrypted …” with a user:password@ (never printed). stdout and the exit code are unchanged.

Scripting patterns

# Exit-code driven: 0 = call worked (an empty alert list still exits 0)
if hochwasser --compact alerts --states NW > alerts.json; then
  count=$(jq '.data | length' alerts.json)
  echo "NRW has $count active flood alert(s) (Stand: $(jq -r .updated alerts.json))"
fi

# Cron-friendly: alarm when any gauge in a state reaches class 3 — and fail closed:
# a check that could not run (no network, an API error, no gauge with data) alarms too,
# so "no alarm" always means "checked, and below class 3".
out=$(hochwasser --compact situation --states RP)
code=$?
if [ "$code" -ne 0 ]; then
  notify-send "Hochwasser RP: Prüfung fehlgeschlagen (Exit $code)"; exit "$code"
fi
worst=$(printf '%s\n' "$out" | jq -e '.worstClass') || {
  notify-send "Hochwasser RP: keine Einstufung erhalten"; exit 1   # worstClass null: no gauge
}
if [ "$worst" -lt 0 ]; then
  notify-send "Hochwasser RP: keine Daten an den Pegeln (Klasse $worst)"; exit 1
fi
if [ "$worst" -ge 3 ]; then notify-send "Hochwasser RP: Klasse $worst"; fi

# Save the raw response for later processing (refuses to clobber; --force to allow)
hochwasser stations -o stations-$(date +%F).json

# Robustness knobs for flaky networks
hochwasser --timeout 60000 --max-retries 5 stations

Exit codes recap

Code Meaning
0 success (an empty result is success)
2 usage error: bad flag, unknown state code, bad --min-class, refused overwrite
4 HTTP 404
6 network/transport failure
1 anything else (unfollowed 3xx redirect, non-JSON body, an envelope whose status isn’t success, a nationwide station list without any gauge, server 5xx after retries)

View the source on GitHub →