Feature: live NEXRAD / weather-radar tile overlay on the map
Follow-on to the common mapping engine + PSK Reporter map (#3565). Add a read-only weather-radar overlay on top of the OSM basemap to track live storms, refreshing every 10–15 min with aggressive timestamped caching. Reusable on any MapView consumer (PSK Reporter map now; AetherModem APRS tab later).
Why it's a clean fit
MapView is already a slippy-tile renderer (EPSG:3857, XYZ {z}/{x}/{y}.png, shared cached QNetworkAccessManager, per-layer opacity). Radar is just a second tile layer above OSM at reduced opacity — minimal new code, no API key on the recommended path.
Providers (deep-research verified)
Primary (US): Iowa Environmental Mesonet (IEM) N0Q base reflectivity
- Latest CONUS composite:
https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/ridge::USCOMP-N0Q-0/{z}/{x}/{y}.png (-0 = moving "latest", short TTL).
- Immutable archived frame:
ridge::USCOMP-N0Q-YYYYMMDDHHMM/{z}/{x}/{y}.png (cache forever; use for animation).
- Cache tiers:
/cache/tile.py/... = 5-min; /c/tile.py/... = 14-day (prefer /c/ for stable/timestamped names).
- Animation: layer suffix
nexrad-n0q-mXXm (XX = 05–55 by 5 → ~11 frames), or WMS-Time …/cgi-bin/wms/nexrad/n0q-t.cgi? (nexrad-n0q-wmst, 5-min steps, archive to 2011).
- Cadence: N0Q regenerated every 5 min, CONUS.
- Attribution: "Radar data: Iowa Environmental Mesonet (IEM), Iowa State University."
Fallback (global): RainViewer (key-less, free)
- Index:
GET https://api.rainviewer.com/public/weather-maps.json → host, radar.past[], radar.nowcast[] (each time Unix ts + path like /v2/radar/1609402200).
- Tile URL:
{host}{path}/{size}/{z}/{x}/{y}/{color}/{options}.png (size 256/512, color = scheme id, options = {smooth}_{snow}). Max zoom ~7.
- Frame paths embed the timestamp → naturally immutable; only re-fetch the index per refresh.
- Attribution: "Weather radar by RainViewer."
Authoritative (future, not v1): NOAA/NWS
- Public domain, time-enabled, but WMS/ArcGIS-export only — not XYZ tiles → needs a separate WMS
GetMap layer. Skip for v1.
- nowCOAST GeoServer WMS 1.3.0
https://nowcoast.noaa.gov/geoserver/observations/weather_radar/ows (layer conus_base_reflectivity_mosaic); ArcGIS ImageServer https://mapservices.weather.noaa.gov/eventdriven/rest/services/radar/radar_base_reflectivity_time/ImageServer. Credit "NOAA/NWS."
Refresh & caching
- NEXRAD precip-mode volume scans complete ~4.5–6 min; IEM 5-min. A 10–15 min client refresh is conservative and compliant.
- Address every frame by explicit UTC timestamp → immutable URL → cache indefinitely in the shared
QNetworkDiskCache. Use the "latest"/-0 pointer only for the live tip with a short TTL. Re-fetch only the index/latest pointer on the interval.
Integration points (from codebase scout)
src/gui/map/MapView.cpp ctor: add a second tile layer after m_map->addItem(new QGVLayerOSM()) — QGVLayerOSM(url) accepts an XYZ template with ${z}/${x}/${y}; set setOpacity(...) + setZValue(5) (above OSM, below m_markerLayer). Reuses the shared NAM + 256 MB disk cache automatically.
- New
MapView API: setWeatherOverlay(enabled) / opacity setter (keep it generic + reusable, not PSK-specific).
src/gui/PskReporterMapDialog.cpp top bar: "Radar" checkbox + opacity slider following the existing Paths-checkbox + AppSettings pattern (keys e.g. RadarOverlayEnabled, RadarOpacity).
- dBZ legend can reuse
MapView::setLegend(...).
- New files only if needed:
src/gui/map/MapWeatherLayer.{h,cpp} (a QGVLayerTilesOnline/QGVLayerOSM subclass) — required if IEM turns out to be TMS (Y-flipped) or for the RainViewer index→URL builder.
Open questions / pre-build checks
Proposed scope
- Phase 1: IEM N0Q latest-frame overlay on
MapView — toggle + opacity slider + dBZ legend + valid-time label, 10-min refresh, timestamped caching, off by default.
- Phase 2: animation loop (last ~10 frames) + global RainViewer option.
Read-only public data throughout; no API keys on the recommended path.
💻 Generated with Claude Code (Fable 5.0) with architecture by @jensenpat
Feature: live NEXRAD / weather-radar tile overlay on the map
Follow-on to the common mapping engine + PSK Reporter map (#3565). Add a read-only weather-radar overlay on top of the OSM basemap to track live storms, refreshing every 10–15 min with aggressive timestamped caching. Reusable on any
MapViewconsumer (PSK Reporter map now; AetherModem APRS tab later).Why it's a clean fit
MapViewis already a slippy-tile renderer (EPSG:3857, XYZ{z}/{x}/{y}.png, shared cachedQNetworkAccessManager, per-layer opacity). Radar is just a second tile layer above OSM at reduced opacity — minimal new code, no API key on the recommended path.Providers (deep-research verified)
Primary (US): Iowa Environmental Mesonet (IEM) N0Q base reflectivity
https://mesonet.agron.iastate.edu/cache/tile.py/1.0.0/ridge::USCOMP-N0Q-0/{z}/{x}/{y}.png(-0= moving "latest", short TTL).ridge::USCOMP-N0Q-YYYYMMDDHHMM/{z}/{x}/{y}.png(cache forever; use for animation)./cache/tile.py/...= 5-min;/c/tile.py/...= 14-day (prefer/c/for stable/timestamped names).nexrad-n0q-mXXm(XX = 05–55 by 5 → ~11 frames), or WMS-Time…/cgi-bin/wms/nexrad/n0q-t.cgi?(nexrad-n0q-wmst, 5-min steps, archive to 2011).Fallback (global): RainViewer (key-less, free)
GET https://api.rainviewer.com/public/weather-maps.json→host,radar.past[],radar.nowcast[](eachtimeUnix ts +pathlike/v2/radar/1609402200).{host}{path}/{size}/{z}/{x}/{y}/{color}/{options}.png(size 256/512, color = scheme id, options ={smooth}_{snow}). Max zoom ~7.Authoritative (future, not v1): NOAA/NWS
GetMaplayer. Skip for v1.https://nowcoast.noaa.gov/geoserver/observations/weather_radar/ows(layerconus_base_reflectivity_mosaic); ArcGIS ImageServerhttps://mapservices.weather.noaa.gov/eventdriven/rest/services/radar/radar_base_reflectivity_time/ImageServer. Credit "NOAA/NWS."Refresh & caching
QNetworkDiskCache. Use the "latest"/-0pointer only for the live tip with a short TTL. Re-fetch only the index/latest pointer on the interval.Integration points (from codebase scout)
src/gui/map/MapView.cppctor: add a second tile layer afterm_map->addItem(new QGVLayerOSM())—QGVLayerOSM(url)accepts an XYZ template with${z}/${x}/${y}; setsetOpacity(...)+setZValue(5)(above OSM, belowm_markerLayer). Reuses the shared NAM + 256 MB disk cache automatically.MapViewAPI:setWeatherOverlay(enabled)/ opacity setter (keep it generic + reusable, not PSK-specific).src/gui/PskReporterMapDialog.cpptop bar: "Radar" checkbox + opacity slider following the existingPaths-checkbox +AppSettingspattern (keys e.g.RadarOverlayEnabled,RadarOpacity).MapView::setLegend(...).src/gui/map/MapWeatherLayer.{h,cpp}(aQGVLayerTilesOnline/QGVLayerOSMsubclass) — required if IEM turns out to be TMS (Y-flipped) or for the RainViewer index→URL builder.Open questions / pre-build checks
tile.py/1.0.0/TMS (Y-flipped) or XYZ/Google like OSM? Page documentsZ/X/Y— verify against QGeoView's loader and flip Y if genuinely TMS.tile.py(WMS-T extent starts 2011; tile-cache vs archive availability TBD).Proposed scope
MapView— toggle + opacity slider + dBZ legend + valid-time label, 10-min refresh, timestamped caching, off by default.Read-only public data throughout; no API keys on the recommended path.
💻 Generated with Claude Code (Fable 5.0) with architecture by @jensenpat