Skip to content

Live NEXRAD / weather-radar tile overlay on the map (storm tracking) #3574

@jensenpat

Description

@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 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.jsonhost, 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

  • IEM Y-axis: is tile.py/1.0.0/ TMS (Y-flipped) or XYZ/Google like OSM? Page documents Z/X/Y — verify against QGeoView's loader and flip Y if genuinely TMS.
  • RainViewer terms: confirm free-tier redistribution/commercial-use terms for a shipped desktop app; respect ~10-min frame cadence.
  • dBZ ramp: source exact NWS standard reflectivity color breakpoints for the legend (not enumerated in verified sources).
  • IEM per-timestamp archived-frame availability window via tile.py (WMS-T extent starts 2011; tile-cache vs archive availability TBD).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    GUIUser interfaceNew FeatureNew feature requestmaintainer-reviewRequires maintainer review before any action is taken

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions