Releases: jpettitt/weather-radar-card
v3.7.0
Stable release. 3.7 graduates to stable. Drop-in upgrade from 3.6.x or any 3.7 pre-release — no breaking changes, no config changes required.
Headline features
Smooth motion — opt-in motion_compensation: true. During each frame transition, rain slides along its actual direction of travel instead of crossfading in place, so the loop reads as one continuously drifting rain field. Pyramidal Lucas-Kanade optical flow, runs in a Web Worker, works across all three radar sources. Built on top of @genericJE's #156. Pairs naturally with smooth_animation.
type: 'custom:weather-radar-card'
smooth_animation: true
motion_compensation: trueAdjustable playback speed — toolbar button cycles ¼× / ½× / 1× / 2× / 4×, with a YAML default. Optional per-user persistence (viewer_layer_control: true) so each viewer's chosen speed follows them across browsers and devices. Contributed by @genericJE.
Also in 3.7
- NOAA radar rebuilt on NCEP's opengeo GeoServer (the radar.weather.gov backend) — newest frame ~2 minutes behind real time instead of 15–25, every frame a distinct scan, and a new Frame interval dropdown (2 / 5 / 10 min). The newest-frame label now reads "Latest" rather than "Now" since radar always lags real time.
- Canvas rendering for lightning and hazard overlays — strikes, alert polygons, and fire perimeters paint to canvas instead of per-item DOM. Identical visuals and clickability; soak-validated during live storms at 10,000 simultaneous lightning strikes with the page fully responsive.
- Stability wave — full-project code-review remediation: refresh/state races (no more duplicate-frame accumulation on long-running dashboards), DWD coverage clipping + single shared boundary mask, exponential backoff on alert/wildfire fetch failures, bounded caches, antimeridian fixes for Alaska.
- 11-language translation parity for all the new editor strings.
Notes for upgraders
Legacy frame_count is still honoured but now warns when combined with past_minutes / frame_stride_minutes (it's ignored in that case — use the time fields). It will be removed in the next major.
Full 3.7 changelog: v3.6.5...v3.7.0
v3.7.0-beta2
Beta pre-release. One deliberate exception to the beta feature freeze: a new NOAA radar source that directly resolves live beta feedback and removes the line's biggest freshness deficit. Everything else stays fixes-only until 3.7.0. Upgrading from beta1 is drop-in — no config changes required.
NOAA radar: ~2 minutes behind real time (was 15–25)
NOAA now serves from NCEP's opengeo GeoServer — the same backend radar.weather.gov runs on. It publishes the radar layer's actual frame timestamps, so the card requests exact scan times instead of guessing a grid:
- Newest frame ~2 min old (measured; the legacy server refused anything fresher than ~14 min)
- Every frame is a distinct radar scan — the duplicate-frame quantisation from alpha2 is gone by construction
- New "Frame interval" dropdown: 2 / 5 / 10 minutes (default 5, restoring the 3.6-era 12–13 frames per hour — and yes, this fixes "the increment shown is 10 minutes instead of 5" from the beta1 feedback; thank you for reporting it)
- Colour bar updated to the modern radar.weather.gov reflectivity ramp
- Legacy
frame_countconfigs migrate back to their 3.6-era time spans - If the new server's listing is ever unavailable, the card falls back to the old server for that cycle and recovers automatically
type: 'custom:weather-radar-card'
data_source: NOAA
past_minutes: 120
frame_stride_minutes: 2 # full native scan cadence, or pick in the editorAlso in beta2
- The newest-frame label reads "Latest" instead of "Now" — radar frames always lag real time by source, and the label shouldn't overstate freshness. Localised in all 11 languages.
- Translation catch-up: all 3.7 editor strings (playback speed, per-user persistence, motion compensation) are now properly translated in all 10 non-English locales.
Full changelog: v3.7.0-beta1...v3.7.0-beta2
v3.7.0-beta1
Beta pre-release — 3.7 is feature complete. No further features before 3.7.0; fixes only from here. Suitable for adventurous daily-driver dashboards. No breaking changes — upgrading from 3.6.x or any 3.7 alpha is drop-in.
Headline features
Smooth motion — opt-in motion_compensation: true. During each frame transition, rain slides along its actual direction of travel instead of crossfading in place, so the loop reads as one continuously drifting rain field. Powered by pyramidal Lucas-Kanade optical flow, runs in a Web Worker, and works across all three radar sources (DWD, RainViewer, NOAA). Built on top of @genericJE's foundational work in #156.
type: 'custom:weather-radar-card'
smooth_animation: true
motion_compensation: trueAdjustable playback speed — the toolbar button cycles ¼× / ½× / 1× / 2× / 4×, with a YAML default (playback_speed). Admins can opt in to per-user persistence (viewer_layer_control: true), so each viewer's chosen speed follows them across browsers and devices. Contributed by @genericJE.
show_playback: true
playback_speed: 1
viewer_layer_control: true # optional: persist per-user overridesAlso in 3.7: stability and performance
- Canvas rendering for lightning and hazard overlays — strikes, alert polygons, and fire perimeters paint to canvas instead of per-item DOM. Identical visuals and clickability; soak-validated during live storms at 10,000 simultaneous strikes with the page fully responsive.
- Full-project code-review remediation — refresh and state races fixed (no more duplicate-frame accumulation on long-running dashboards), DWD coverage clipping + single shared boundary mask, exponential backoff on alert/wildfire fetch failures, bounded caches, antimeridian fixes for Alaska.
- NOAA cadence fix — frame interval matched to NOAA's real publication cadence; no more duplicate frames in the loop.
What to test
Motion compensation across radar sources, playback-speed persistence across devices, lightning under storm load, hazard-polygon clicks at various zooms. Issues → GitHub.
Full changelog: v3.6.5...v3.7.0-beta1
v3.7.0-alpha3
Alpha pre-release — stability wave for the 3.7 line. No new features, no breaking changes, no config changes. If alpha2 was working for you, this is a strict upgrade; install to exercise the fixes and report findings.
What's fixed
Everything from a full-project code review plus four issues debugged live during the alpha2 soak:
Radar pipeline
- Long-running dashboards no longer accumulate duplicate frames — the 5-minute refresh now checks the source actually published something new before shifting the loop.
- Pan/zoom no longer triggers a full teardown + refetch after frame dedup (and the same-shape init guard survives tracked-marker GPS jitter).
- The periodic-refresh timer can no longer fork into parallel chains after rate-limit retries or sleep/wake.
DWD radar (the big one for German users)
- The coverage mask is now a single shared layer instead of one per frame — at 12 h history the old design created ~144 mask layers ≈ ~900 redundant tile requests per init, and the boundary visibly wobbled during forecast playback.
- Forecast rain no longer renders outside the coverage boundary — the radar pane is clipped to the coverage region via
clip-path. - Fixed a mask-pane leak where dedup compaction left orphaned layers attached forever.
Overlays
- NWS alerts / wildfire polling now backs off exponentially on fetch failures, so an api.weather.gov rate-limit block actually clears instead of being kept alive by the retry cadence.
- Opening the editor no longer freezes the UI under a large lightning backlog — strikes now materialise newest-first in time-budgeted slices.
- A transient NIFC failure no longer blanks displayed wildfire perimeters; NOAA "soft-error" tiles (200 OK with an XML body) are detected and retried.
- Hidden cards now fully stop wind, wildfire, and alerts work (previously some loops kept running off-screen).
State & misc
- Per-user state (playback speed) can no longer be wiped by a hydrate/write race or lost on dashboard navigation.
- Editing the card no longer rebuilds the map on every keystroke.
- Three unbounded caches bounded; antimeridian handling fixed for Alaska/Aleutian geometries; playback-speed button no longer jumps to ¼× after a non-preset YAML value; strict-CSP construction crash fixed.
Internal
- Per-tick progress-bar work reduced to changed-segments-only; post-pan motion-comp/clip refresh debounced 250 ms; ~45 new regression tests (591 total).
Full changelog: v3.7.0-alpha2...v3.7.0-alpha3
v3.7.0-alpha2 — motion compensation (opt-in, source-agnostic; @genericJE-built)
⚠️ Alpha pre-release. Continues the 3.7 pre-release line from 3.7.0-alpha1 (per-user state framework). Adds opt-in motion compensation for radar transitions plus a handful of related improvements.
Not recommended for production dashboards — install only if you want to exercise the motion-comp pipeline across radar sources and report findings. HACS users: you'll only see this in your update list if you've enabled "Show beta versions" in HACS settings.
What's new
Motion compensation for radar transitions (#183) — built on top of @genericJE's #156. Rain visibly drifts between frames instead of teleporting to its new position while the old fades out. The implementation kept the snapshot-capture infrastructure and the dual-translate animation pattern that @genericJE built in #156, and swapped two pieces:
- Algorithm: SAD block-matcher → pyramidal Lucas-Kanade optical flow.
- Channel extraction: alpha → distance-from-white intensity.
Together those make motion compensation source-agnostic — works for all three radar sources (DWD, RainViewer, NOAA) instead of being effectively DWD-only. LK runs in a Web Worker by default so slow devices stay smooth; falls back to synchronous main-thread execution under strict CSPs. Auto-skipped on frame pairs without enough gradient signal for a confident vector (light rain, clear sky). Default off — enable via the new toggle in the editor's Animation section or in YAML:
type: 'custom:weather-radar-card'
smooth_animation: true
smooth_overlap: 0
motion_compensation: trueFull architecture and design decisions in docs/motion-compensation-feature-design.md.
Changed
NOAA frame interval bumped from 5 → 10 min (SOURCE_CAPS.NOAA.intervalMin). The empirical publication cadence on NOAA's eventdriven WMS service is ~5-9 min (mean ~7), and the server snaps any TIME query within a publication window to the same physical frame. Requesting at the previous 5-min stride was returning duplicate frames for every other request. Behaviour change for NOAA users: the same past_minutes value now yields half as many frames in the loop, but every frame is unique. Legacy frame_count: N configs auto-migrate to the new stride preserving frame count (e.g. frame_count: 12 migrates to past_minutes: 110 instead of the previous 55 — 12 distinct frames covering twice the real time span). Tracking a server-side fix upstream at the NOAA / weather.gov API repo.
Fixed
Stale frames on resume from long-hidden / device-sleep windows. The visibility-visible handler previously did a single _updateRadar to catch the most recent missed publication — enough for a few-minute tab switch. After longer hidden periods (device sleep, hours-tabbed-away) the single-frame update left the rest of the loop holding hour-old timestamps; the displayed radar would show one fresh frame and N-1 stale ones. Now tracks the wall-clock time of the last frame fetch; on visibility-visible, if >10 min (= 2× the refresh period) has elapsed, scraps the loop entirely and re-fetches every slot from scratch. Brief load state on resume from sleep, but the loop content is correct after.
How to report feedback
Open an issue at https://github.com/jpettitt/weather-radar-card/issues — particularly interested in:
- Motion compensation visual quality across DWD / RainViewer / NOAA — does the rain drift look natural?
- Storm core "jumping" on convective storms (known v1 limitation — single global vector can't track within-cell reorganisation; dense per-region flow is a v2 project).
- NOAA cadence change — is the reduced frame count acceptable for your typical loop length?
- Stale-frame re-init — does the resume behavior feel right after sleep / long-hidden windows?
Full Changelog: v3.7.0-alpha1...v3.7.0-alpha2
v3.7.0-alpha1 — first exercise of viewer-state framework (adjustable playback speed)
⚠️ Alpha pre-release. First user-visible consumer of the per-user state framework that shipped dormant in 3.6.5 (#175). Two weeks of feedback expected before promotion through beta / rc / stable, matching the 3.6.1-rc1 → 3.6.1 cadence.
Not recommended for production dashboards — install only if you want to exercise the persistence path and report findings. HACS users: you'll only see this in your update list if you've enabled "Show beta versions" in HACS settings.
What's new
Adjustable playback speed (#157) — contributed by @genericJE, their third contribution after #155 and #172. Toolbar button cycles ¼× / ½× / 1× / 2× / 4×; editor dropdown sets the YAML default. Built on top of the viewer-state framework from #175.
Sparse-storage convention: a user's runtime override clears automatically when the chosen value matches the YAML default. The practical effect — an admin editing the YAML default propagates the new value to every viewer who hasn't explicitly overridden via the toolbar.
viewer_layer_control admin toggle — new editor toggle in the Animation section. Opt-in to per-user, per-card preference persistence via Home Assistant's frontend storage. Off by default; when off the toolbar speed button still works but the value is session-only.
type: 'custom:weather-radar-card'
show_playback: true # exposes the toolbar speed button
playback_speed: 1 # YAML default; users can override via toolbar
viewer_layer_control: true # admin opt-in to persist overrides per-user across browsers/devicesWhen viewer_layer_control is first enabled, the card auto-mints a _layer_state_id nonce into the card YAML — the per-card storage key that lets a single user have different preferences across different cards on the same dashboard.
Internal changes
First end-to-end exercise of the per-card identity nonce + ViewerState hydrate path introduced in 3.6.5's framework. The WS hydrate round-trip races against the toolbar's first paint — on a fresh page load with a non-1× override stored, the speed button label briefly shows the YAML default then snaps to the override once HA's frontend/get_user_data resolves (typically one render frame). Documented for awareness; alpha audience can confirm whether this single-frame flicker is acceptable.
How to report feedback
Open an issue at https://github.com/jpettitt/weather-radar-card/issues — particularly interested in:
- Per-user persistence working correctly across devices when logged into HA
- Cross-card preference isolation (set different speeds on two cards on the same dashboard)
- The hydrate-race flicker — perceptible / acceptable / not?
Full Changelog: v3.6.5...v3.7.0-alpha1
v3.6.5
Patch release. Two small QoL fixes (lightning popup distance now respects HA's unit_system; broken Blitzortung-integration link in the docs corrected) and the per-user state framework lands on main as dormant infrastructure for v3.7.
No breaking changes. Drop-in patch over 3.6.4. HACS users with auto-update will see this as a routine update.
Fixed
Lightning strike distance now uses HA's preferred length unit (#176)
The popup that opens when you click a lightning strike was always showing distance in "km" regardless of HA's unit_system setting. Imperial users had to mentally convert.
Now reads hass.config.unit_system.length and formats as "45 km" or "28 mi" accordingly — same signal already used by the Leaflet scale control and range rings. Wildfire / NWS-alert popups don't display distances, so this only affects the lightning popup.
Broken Blitzortung-integration link in docs (#177)
🙏 Thanks to @mweinelt for catching this. The README, configuration docs, overlays docs, and lightning-feature-design all linked the Blitzortung integration as home-assistant.io/integrations/blitzortung/ — a 404, because there's no native HA Blitzortung integration. The actual integration is the third-party HACS one at github.com/mrk-its/homeassistant-blitzortung. All four references corrected.
While fixing it, audited every URL in shipped docs (118 unique URLs) and confirmed this was the only real broken link.
Internal
- Per-user state framework added on
main(#175). Newsrc/viewer-state.tswraps HA's frontend storage WebSocket API to support v3.7's per-user runtime customisation features (layer visibility panel, playback speed override). Dormant in this release — no consumer wired up yet, no behaviour change. Documented indocs/viewer-state-api.mdfor contributors.
Upgrade notes
No config changes. Drop-in patch over 3.6.4.
Full Changelog: v3.6.4...v3.6.5
v3.6.4
Patch release. Tablet-friendly timeline scrubbing for touchscreen dashboards (opt-in via YAML), a lightning-strike layering fix, and an internal HACS-on-PR ops cleanup.
No breaking changes. Drop-in patch over 3.6.3. HACS users with auto-update will see this as a routine update.
What's new
Tablet-friendly timeline scrubbing (#172)
🙏 Big thanks to @cgjolberg for this contribution — the first community PR landed since the repo transferred. New YAML-only progress_bar_touch_height option to enlarge the tappable/draggable progress-bar region upward over the lower map area, while keeping the visible segmented track at 8 px and leaving the bottom chrome unchanged.
Set the height to whatever your touchscreen design wants (44 px matches Apple HIG / WCAG touch-target guidance) and the extra area becomes a reliable scrub zone — the lower edge of the map in that strip is consumed by scrubbing instead of pan/pinch.
Default unchanged. Mouse/desktop users see no difference. Real-hardware tested on a landscape touchscreen tablet with a demo video in the PR.
type: 'custom:weather-radar-card'
show_progress_bar: true
progress_bar_touch_height: 44Fixed
Lightning strikes — newest renders on top within each pane (#171)
Leaflet's L.Marker defaults to z-index by screen-Y position (southern markers on top), not DOM-insertion order. So when two strikes were close together on screen, the southern one would render on top regardless of arrival time — visually wrong for a "what's happening now" overlay.
Added explicit zIndexOffset derived from each strike's timestamp so the most recent strike always wins within its pane, matching Blitzortung's own web map convention.
Internal
- HACS validation no longer runs on PRs (#173). Since 3.6.3's #165 stopped tracking the built JS bundle in git, HACS validation against fork PRs always failed because the fork has no GitHub release with the bundle attached. Validation still runs on push to main and the daily cron; PR code is fully validated by the Build matrix.
Upgrade notes
No config changes. Drop-in patch over 3.6.3.
Full Changelog: v3.6.3...v3.6.4
v3.6.3
Patch release. Fixes the GUI editor showing empty/invisible input fields under LOCATION, ANIMATION, APPEARANCE, OVERLAYS, and several marker fields on current HA versions. The card itself was unaffected — only the GUI editor was broken; YAML editing always worked.
No new features, no breaking changes. Drop-in patch over 3.6.2. HACS users with auto-update will see this as a routine update.
Fixed
GUI editor inputs invisible on current HA versions (#166)
HA frontend removed ha-textfield on 2026-04-01 (commit "Migrate all from ha-textfield to ha-input #30349"). Our editor's 14 textfield usages then rendered as zero-height invisible elements — users opening the editor saw section headers (LOCATION, ANIMATION, etc.) with empty space below them. Centre coordinates, frame delays, transition time, height/width, wildfire min acres, wildfire radius, and marker positions were uneditable via the GUI editor on recent HA versions.
YAML editing always worked as the escape hatch, but the GUI was effectively broken.
Migrated all usages to the replacement element ha-input (1-to-1 API mapping; helper="..." renamed to hint="..." per the new element's webawesome convention).
Changed
- Marker action buttons now use
ha-button. Add Marker, Remove (per marker), and Reset Color (per marker) in the Markers sub-page render with HA's native pill-button style (theme color, white text, ripple) instead of browser-default. Cosmetic only; behaviour unchanged.
Internal
- New
docs/ha-elements-guide.md— contributor/agent reference capturing what we learned aboutha-*Web Component lifecycle, the lazy-load failure mode that hid this bug, and how to verify new elements before shipping. - CI workflow triggers deduplicated — PR commits no longer run validation twice (#169).
Upgrade notes
No config changes. Drop-in patch over 3.6.2.
Full Changelog: v3.6.2...v3.6.3
v3.6.2 — bandwidth optimisation + housekeeping
Patch release. Bandwidth optimisation for mobile users via AbortController on tile + data fetches, cleanup of phantom dependencies, and a doc-block above the markercluster race workaround.
No new features, no behaviour changes for existing configs. The [3.6.1] wind-source registry stays Experimental.
Changed
AbortController on tile + data fetches (#159)
Radar tiles, wildfire perimeter fetches, NWS alerts (+ per-zone shape fetches), and the RainViewer JSON metadata call now cancel their HTTP requests when superseded by a fresh fetch, when the card tears down, or when Leaflet unloads the tile (pan-out-of-view / zoom).
Previously the generation-counter trick discarded stale responses but the browser still downloaded the full payload first. On mobile or rate-limited connections a low-zoom continental pan can trigger dozens of tile requests that immediately get superseded — those now show as (canceled) in DevTools Network instead of completing.
Steady-state playback is unchanged (tiles recycle across frames without unloading → no abort, correct). src/wind-grid-fetcher.ts intentionally not instrumented — its request-coalescing makes correct cancellation tricky and the 60 s cache TTL already provides similar bandwidth conservation. Revisit when 3.7's layer-control panel adds explicit per-card cancellation.
Internal
- Phantom dependencies removed.
randombytes,safe-buffer,tslib,tsutilswere listed independenciesbut not imported anywhere insrc/,tests/, or the rollup config.tslibcorrectly stays as a transitive (viacustom-card-helpersandrollup-plugin-typescript2); the other three drop fromnode_modulesentirely. Companion to theserialize-javascriptsecurity bump that landed in 3.6.1. - Markercluster init-race workaround documented. The
requestAnimationFrame+ try/catch in_setupResizeObservernow carries a doc-block explicitly warning future contributors not to "simplify" it. The pattern works around a framework limitation inleaflet.markercluster(no lifecycle hook for "cluster tree ready"); replacing it with a synchronous call re-triggers the_topClusterLevel._boundsundefined crash from #110 on the resize path. - Tests: 440 → 455. New
tests/fetch-abort.test.tspins theAbortController/AbortSignalcontract the error-handler branches depend on, the abort-previous-on-supersession pattern, andwireAbortLifecycle+createFetchTileintegration via minimal layer stubs (consistent with the project's "stub Leaflet, test the helpers" convention).
Code review pass
Three deferred items from a code review pass are tracked in docs/todo.md: TypeScript module augmentation for Leaflet (3.8 health pass), Web Worker for the DWD pixel filter (only after profiling shows main-thread spikes), and WindGridFetcher cancellation via consumer reference-counting (pair with 3.7 layer-control).
Upgrade notes
No config changes. Drop-in patch over 3.6.1. HACS users with auto-update will see this as a routine update.
Full Changelog: v3.6.1...v3.6.2