Lightning: radar overlay + proximity-alert follow-on #87

Closed
opened 2026-07-18 05:31:46 +00:00 by claude-bot · 3 comments
Contributor

Near-term: add a lightning/CG-strike overlay as another radar layer alongside the existing NWS CONUS WMS products (Leaflet supports the extra layer button with no structural change). Longer-term follow-on: a new alert type where a lightning strike within a configurable radius of a location triggers a notification to that location — this reuses the per-location point + notification-dispatch machinery but needs a lightning data source (commercial feeds like Blitzortung-derived services, or a suitable free source) and its own polling job and dedup keying. Missed because radar was scoped to NWS reflectivity products and alerting to official NWS/SPC products. Overlay: effort S, value Medium. Proximity alert: effort M-L (new data source + poller + alert type), value Medium-High for anyone outdoors — worth its own issue when the overlay lands and a data source is chosen.


Filed from the 2026-07-17 codebase audit (docs/.internal/report-2026-07-17.md), finding I-17.

Near-term: add a lightning/CG-strike overlay as another radar layer alongside the existing NWS CONUS WMS products (Leaflet supports the extra layer button with no structural change). Longer-term follow-on: a new alert type where a lightning strike within a configurable radius of a location triggers a notification to that location — this reuses the per-location point + notification-dispatch machinery but needs a lightning data source (commercial feeds like Blitzortung-derived services, or a suitable free source) and its own polling job and dedup keying. Missed because radar was scoped to NWS reflectivity products and alerting to official NWS/SPC products. Overlay: effort S, value Medium. Proximity alert: effort M-L (new data source + poller + alert type), value Medium-High for anyone outdoors — worth its own issue when the overlay lands and a data source is chosen. --- _Filed from the 2026-07-17 codebase audit (`docs/.internal/report-2026-07-17.md`), finding I-17._
Author
Contributor

Data-source finding (blocks the near-term overlay too)

While picking this up for v1.5.0 I checked for a free lightning tile/WMS source — the near-term overlay assumes one exists ("add a lightning layer alongside the NWS CONUS WMS products"). It doesn't, as far as I can find:

  • Iowa State Mesonet (already used here for warning images): only NEXRAD radar WMS responds (n0q.cgi → 200). Candidate lightning endpoints .../wms/us/nldn.cgi and .../wms/goes/glm.cgi return 400 — they aren't real services. NLDN data is commercial (Vaisala), so IEM doesn't redistribute it as free tiles.
  • RainViewer (already wired): exposes radar + satellite only — no lightning.
  • Remaining options all carry a real cost/complexity decision: a commercial feed (Vaisala Xweather / similar — paid API key), Blitzortung-derived tiles (community, no clean embeddable tile API + usage constraints), or rendering our own tiles from raw GOES GLM netCDF (heavy — out of proportion for an overlay).

So both halves of this issue — the overlay AND the proximity alert — hinge on the same lightning-data-source decision, which is a product/cost call for the maintainer, not something to pick silently. Recommend deferring this out of v1.5.0 until a source is chosen: if a paid feed is acceptable I can wire the overlay (and later the proximity alert) against it; otherwise it stays parked. The other 8 v1.5.0 issues are unaffected.

(Filed the finding here rather than building an empty/placeholder overlay.)

## Data-source finding (blocks the near-term overlay too) While picking this up for v1.5.0 I checked for a **free lightning tile/WMS source** — the near-term overlay assumes one exists ("add a lightning layer alongside the NWS CONUS WMS products"). It doesn't, as far as I can find: - **Iowa State Mesonet** (already used here for warning images): only NEXRAD radar WMS responds (`n0q.cgi` → 200). Candidate lightning endpoints `.../wms/us/nldn.cgi` and `.../wms/goes/glm.cgi` return **400** — they aren't real services. NLDN data is commercial (Vaisala), so IEM doesn't redistribute it as free tiles. - **RainViewer** (already wired): exposes `radar` + `satellite` only — no lightning. - Remaining options all carry a real cost/complexity decision: a **commercial feed** (Vaisala Xweather / similar — paid API key), **Blitzortung**-derived tiles (community, no clean embeddable tile API + usage constraints), or **rendering our own tiles from raw GOES GLM** netCDF (heavy — out of proportion for an overlay). So *both* halves of this issue — the overlay AND the proximity alert — hinge on the same lightning-data-source decision, which is a product/cost call for the maintainer, not something to pick silently. **Recommend deferring this out of v1.5.0** until a source is chosen: if a paid feed is acceptable I can wire the overlay (and later the proximity alert) against it; otherwise it stays parked. The other 8 v1.5.0 issues are unaffected. (Filed the finding here rather than building an empty/placeholder overlay.)
Author
Contributor

Reopening with a data source — Weather Pulse (AllisonHouse) ENTLN

The maintainer has a Weather Pulse subscription with an ENTLN lightning placefile feed, which is viable. Confirmed the feed format directly:

  • GRLevelX placefile at a per-subscriber URL (token in the path → treated as a secret, stored as LIGHTNING_PLACEFILE_URL in the server .env, never committed/logged/rendered).
  • Requires ?version=&lat=&lon= params (500 without) and returns clusters within a ~250-mi ring of that point.
  • Body is repeating TimeRange: <startZ> <endZ> + Icon: lat,lon,angle,file,idx,"Total: N in past 30 min" pairs (cell-clustered density, not individual strokes — adequate for overlay + proximity), plus a header and one Line: range-ring to ignore.

Plan (split into two)

Phase A — dashboard overlay (auth-gated): services/lightning.py fetches + parses the placefile (appending lat/lon), returns recent cluster points; GET /api/lightning/strikes?lat=&lon= (auth required, cached ~60s, fail-soft); a "Lightning" toggle on the radar modal plots them as age-colored Leaflet markers (our own markers, not their icon sheets). Config: LIGHTNING_PLACEFILE_URL (secret), LIGHTNING_ON_PUBLIC_PAGES (default false).

Phase B — proximity alert (follow-on): a poll job computes distance from each opted-in location to recent clusters and fires a "lightning within N mi" notification (per-location radius, deduped/cooldown) through the existing notifier path.

Licensing boundary (per the maintainer's call)

Overlay + proximity default to authenticated/personal use only. Display on the unauthenticated public pages stays behind LIGHTNING_ON_PUBLIC_PAGES (off by default), so redistributing the licensed ENTLN data is an explicit, documented opt-in the operator owns — not something baked in.

Starting Phase A now.

## Reopening with a data source — Weather Pulse (AllisonHouse) ENTLN The maintainer has a Weather Pulse subscription with an ENTLN lightning placefile feed, which is viable. Confirmed the feed format directly: - GRLevelX placefile at a per-subscriber URL (token in the path → treated as a **secret**, stored as `LIGHTNING_PLACEFILE_URL` in the server `.env`, never committed/logged/rendered). - **Requires `?version=&lat=&lon=` params** (500 without) and returns clusters within a ~250-mi ring of that point. - Body is repeating `TimeRange: <startZ> <endZ>` + `Icon: lat,lon,angle,file,idx,"Total: N in past 30 min"` pairs (cell-clustered density, not individual strokes — adequate for overlay + proximity), plus a header and one `Line:` range-ring to ignore. ## Plan (split into two) **Phase A — dashboard overlay (auth-gated):** `services/lightning.py` fetches + parses the placefile (appending lat/lon), returns recent cluster points; `GET /api/lightning/strikes?lat=&lon=` (auth required, cached ~60s, fail-soft); a "Lightning" toggle on the radar modal plots them as age-colored Leaflet markers (our own markers, not their icon sheets). Config: `LIGHTNING_PLACEFILE_URL` (secret), `LIGHTNING_ON_PUBLIC_PAGES` (default **false**). **Phase B — proximity alert (follow-on):** a poll job computes distance from each opted-in location to recent clusters and fires a "lightning within N mi" notification (per-location radius, deduped/cooldown) through the existing notifier path. ## Licensing boundary (per the maintainer's call) Overlay + proximity default to **authenticated/personal** use only. Display on the unauthenticated public pages stays behind `LIGHTNING_ON_PUBLIC_PAGES` (**off by default**), so redistributing the licensed ENTLN data is an explicit, documented opt-in the operator owns — not something baked in. Starting Phase A now.
Author
Contributor

Complete — both phases shipped for v1.6.0, sourced from the Weather Pulse (AllisonHouse) ENTLN placefile.

  • Phase A — overlay (#119): services/lightning.py parses the placefile clusters (fail-soft, cached, secret feed URL via LIGHTNING_PLACEFILE_URL); GET /api/lightning/strikes (auth); a toggle on the radar map plots age-colored markers (disabled when no feed is configured, so the commercial feed is never fetched unsolicited). Verified live against your real feed (55/55 clusters).
  • Phase B — proximity alerts (#120): poll_lightning job fires a "Lightning Nearby" notification when recent clusters fall within a per-location radius (lightning_alert_radius_mi) to channels with the notify_lightning toggle — advisory severity (respects quiet hours), cooldown-limited, snooze-aware, dispatched through the existing notifier path. Migration 0029. Default (no radius set) is a no-op.

Licensing boundary held: everything is authenticated/personal by default; LIGHTNING_ON_PUBLIC_PAGES (off) is reserved for a future opt-in to show lightning on the unauthenticated public pages. The feed URL is set as a secret in the server .env and appears nowhere in the repo.

Complete — both phases shipped for **v1.6.0**, sourced from the Weather Pulse (AllisonHouse) ENTLN placefile. - **Phase A — overlay (#119):** `services/lightning.py` parses the placefile clusters (fail-soft, cached, secret feed URL via `LIGHTNING_PLACEFILE_URL`); `GET /api/lightning/strikes` (auth); a ⚡ toggle on the radar map plots age-colored markers (disabled when no feed is configured, so the commercial feed is never fetched unsolicited). Verified live against your real feed (55/55 clusters). - **Phase B — proximity alerts (#120):** `poll_lightning` job fires a "Lightning Nearby" notification when recent clusters fall within a per-location radius (`lightning_alert_radius_mi`) to channels with the `notify_lightning` toggle — advisory severity (respects quiet hours), cooldown-limited, snooze-aware, dispatched through the existing notifier path. Migration 0029. Default (no radius set) is a no-op. Licensing boundary held: everything is authenticated/personal by default; `LIGHTNING_ON_PUBLIC_PAGES` (off) is reserved for a future opt-in to show lightning on the unauthenticated public pages. The feed URL is set as a secret in the server `.env` and appears nowhere in the repo.
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/WeatherBot#87
No description provided.