Germany
DWD RV Radar Composite
How Germany's DWD RV radar composite, reached through the Bright Sky community proxy, converts its integer units to mm/h and where a request gets no reading at all.
At a glance
- Product
- RV composite: 2-hour nowcast forecast, 5-minute steps
- Grid
- 1 km cells; a 3x3 window (1000 m) sampled per point
- Cadence
- New timestep every 5 minutes
- Coverage
- Germany plus a thin border fringe, reaching into northern Denmark
- Access
- api.brightsky.dev, no API key; requires a compressed Accept-Encoding for format=plain
- Units
- precipitation_5 in 0.01 mm / 5 min; mm/h = value x 0.12
- Licence
- CC BY 4.0 (Deutscher Wetterdienst open data), accessed through Bright Sky's community proxy
- Required attribution
- DWD requires the source be duly acknowledged; DWD publishes its own attribution templates. The licence attaches to the DWD data itself, not to Bright Sky, which is a third-party proxy and not a licence holder.
How it signals an absence
Three different facts, and only one of them is a zero.
On the wire these three collapse onto one field. A measurement is radarStatus: "available"; no coverage is radarStatus: "out-of-coverage"; and no measurement, a failed or empty attempt, is radarStatus: "temporarily-unavailable". That field describes the outcome of the whole routing pass, not the one network this page is about: NowcastRouter walks the registered national adapters in order and returns as soon as one reports a measurement, so a point this adapter reports as out-of-coverage can still come back available if a different adapter further down the order answers instead, and can come back temporarily-unavailable rather than out-of-coverage if any other adapter in the pass failed instead of declining. radarCoverage sits beside it: "ok" appears only together with available, and "model-fallback", meaning Open-Meteo's model nowcast answered instead, can appear with either out-of-coverage or temporarily-unavailable.
| Signal | Upstream meaning | We report | Why |
|---|---|---|---|
HTTP 404 | lat/lon outside the DWD radar grid | out-of-coverage | Permanent for this point; the grid's geography does not change between requests. |
HTTP 422 | Bright Sky rejected the coordinate | out-of-coverage | Handled identically to 404: the router moves on to the next adapter or the model fallback. |
empty radar array | Feed returned no timesteps | unavailable | Inside the grid, but this response has nothing to read. Worth asking again on the next cycle. |
every cell in the sampled window is non-numeric | No valid cell in the window | unavailable | A single non-numeric cell next to real neighbours is silently excluded from the max, not treated as a gap by itself; only a window with no valid cell at all reports unavailable. |
precipitation_5 cell 0 | Measured zero | measurement | The radar looked and the maximum across the window was no rain falling. The only one of the above that may be shown as 0 mm/h. |
What the product is
DWD, Germany's national weather service, publishes RV, a radar composite that carries a two-hour nowcast forecast at five-minute steps over a 1 km grid. We do not talk to DWD directly: the request goes through Bright Sky, a community-maintained JSON proxy over DWD's open data. There is no API key. The licence attaches to the DWD data underneath, not to Bright Sky, which is a third-party proxy and not itself a licence holder: DWD publishes its open spatial data, including this radar composite, under CC BY 4.0, and requires the source be duly acknowledged.
A request asks for a small window around the point, distance=1000 meters, rather than a single cell, and the window comes back as a 3-by-3 grid of integers per timestep. The value reported for the point is the maximum across that window, which matches the drone-conservative pessimism the rest of the pipeline applies when providers disagree: take the reading that is worse for flying, not the one closest to the exact coordinate.
A units conversion, not a straight read
Unlike Met Office, which publishes a rate directly, Bright Sky's precipitation_5 field is an integer count in units of 0.01 mm per 5 minutes. Getting to mm/h needs one multiplication: value * 0.12. A raw 25 is 3.0 mm/h, not 25 mm/h; treating the raw integer as a rate would overstate it roughly eightfold.
Three ways to have no rate
A request can decline in three different ways, only one of which is a rate. Outside the DWD radar grid, Bright Sky answers with HTTP 404, and occasionally 422 when it rejects the coordinate outright; both are treated the same way, as a permanent fact about the point. Inside the grid, the feed can still return no timesteps at all, an empty radar array, which is a gap in the feed rather than a confirmed absence of coverage. And within a returned window, an individual cell can come back non-numeric rather than a value; that cell alone is skipped from the maximum rather than treated as a zero, but if every cell in the window is non-numeric the point has no reading at all for that timestep.
Only a numeric cell, including 0, is a rate. Zero here means the radar looked at the window and the maximum across it was measured as no rain falling, the same "measured zero" distinction every source in this reference makes somewhere.
An encoding requirement that refuses the request outright
format=plain also refuses to answer at all without a compressed Accept-Encoding: Bright Sky rejects a plain request for that endpoint with an error naming br, zstd or gzip as the accepted encodings. Most HTTP clients negotiate this automatically; this one sets the header explicitly so the request stays portable across environments that might not.
Reading one point yourself
curl -s \
-H "Accept-Encoding: gzip, br" \
"https://api.brightsky.dev/radar?lat=52.52&lon=13.405&distance=1000&format=plain" \
| jq '.radar[-1].precipitation_5'
# Each cell is in units of 0.01 mm / 5 min. Convert with:
# mm/h = max(cell for cell in window) * 0.12- Without a compressed Accept-Encoding, Bright Sky refuses format=plain outright with an error naming br, zstd or gzip as acceptable. Most fetch clients negotiate this by default; setting it explicitly keeps the request portable to ones that do not.
- The window returned is a small grid, not a single cell. Sampling with max rather than the nearest cell matches the conservative merge the rest of the pipeline applies when sources disagree on a safety-relevant reading.
Or call the API instead
The same reading, normalised, with the source that answered named in the response. No key and no signup for the demo endpoint.
curl "https://api.droneinfo.app/v1/demo/weather/point?lat=52.52&lon=13.405"