CAP Alerts: an event-driven approach to severe weather and hazard alerts (v0.7.0)

Hi all :waving_hand:

I’ve been working on a custom integration and companion Lovelace card that take a different approach to severe weather alerts, and I’d love feedback from people running HA in regions with active weather.

The problem

If you use Home Assistant for severe weather notifications (NWS, MeteoAlarm, ECCC), you’ve probably run into the same structural limits that motivated this effort. The maintainers of the existing integrations do excellent work, but they’re all fighting the same constraints in the HA state machine:

  • The 16 KB attribute limit. The recorder won’t store a state attribute payload larger than ~16 KB. When a big storm rolls in with detailed multipolygon geometry and long-form text, that data can get dropped before it’s persisted.
  • The single-sensor bottleneck. Packing several concurrent alerts into one sensor’s attributes means a complex regional outbreak has to share one payload, which compounds the size problem above and makes per-alert automations awkward.
  • Lifecycle continuity. When a provider upgrades a watch to a warning (or cancels it), it’s hard to track that as one evolving event without churning state history or spawning duplicate entities.

The experiment: cap_alerts

Instead of cramming everything into sensor attributes, cap_alerts uses an event-driven model that creates exactly one entity per active alert, spawned and removed as alerts come and go. Alert data is modeled on CAP (Common Alerting Protocol) field names, so the same shape works across providers.

The goal here is NOT to replace the existing integrations. I’m aiming to field-test an architectural pattern and see whether it holds up across providers and regions. If it does, I’d like to write it up as a proposal that could make life easier for all weather integration maintainers.

How it works

  • Externalized payloads. Heavy data like GeoJSON polygons and long descriptions is held in a bounded in-memory cache and served over a lightweight HTTP endpoint the integration registers, rather than stuffed into state attributes. This sidesteps the 16 KB limit and avoids hammering the recorder (and your SD card) with large writes.
  • Lifecycle-aware identity. Each alert gets a stable ID hashed from its event identity rather than the message URL (for NWS that’s the VTEC event tuple, for ECCC a language-independent key). That keeps one entity (and its state history) intact across the New → Update → Cancelled/Expired lifecycle, instead of churning a new entity on every revision.
  • Normalized severity. Severity is mapped to canonical CAP tiers (extreme, severe, moderate, minor) across providers, so a single automation can react to “anything severe or above” regardless of source.
  • Real-time ingestion where the provider offers it. ECCC alerts arrive over NAAD’s TCP streaming feed as they’re issued, rather than on a poll cycle. Polling is retained as reconnect backfill and a periodic safety resync.

Seven providers as of 0.6.0: NWS (US), ECCC (Canada), MeteoAlarm (EUMETNET / Europe), WMO severe-weather feeds for the ~100 national services without a provider of their own, GDACS (worldwide disasters), BBK (Germany’s civil-protection channels, the backend of the NINA app) and AU (NSW RFS, Queensland, WA and Tasmania under one provider).

New in 0.6.0: Germany and Australia

Two providers landed in 0.6.0, both for places where the existing HA path is about to run out or never existed.

Germany. The card’s adapter over the core nina integration reads attributes that HA 2026.11 removes (home-assistant/core#161882). BBK’s own API is CAP 1.2 as JSON, public and unauthenticated, and it carries what no other HA path has: MoWaS, KATWARN, BIWAPP and the LHP flood portal, alongside the DWD relay. Setup takes a district, a GPS point or a device tracker. If you’re on NINA today, this is the move before 2026.11.

Australia. NSW RFS, Queensland Fire Department, DFES Emergency WA and TasALERT all publish the same EDXL-DE envelope carrying CAP-AU, so it’s one provider with one entry per state. Severity comes from the Australian Warning System tier, not from CAP <severity>, which is uniform on every feed. Most alerts on NSW and QLD are a marker, not a polygon (44 of 99 and 53 of 73 when I profiled them), so markers ship as points and the card draws them and filters by radius. That needs weather_alerts_card 3.5.0 or later. Victoria is GeoJSON and will be its own provider, SA, NT and ACT publish no CAP at all.

The companion card

I also maintain weather_alerts_card, which consumes this entity model natively: severity-driven theming and badges for phase transitions.

Here’s what that looks like in practice; several concurrent placeholder alerts in a single card:

weather_alerts_card showing multiple concurrent severe weather alerts with severity and event-driven theming

Two color themes side by side (left to right: normalized severity tiers, NWS event colors) in the default and compact layouts.

It also puts those externalized payloads to work. Because the full GeoJSON is served from the integration’s cache instead of being truncated at the attribute limit, the card can draw the complete affected area over a map basemap in the alert’s detail panel. This is a real ECCC severe thunderstorm watch for southern Saskatchewan, 112 municipal polygons in one alert, about 40 KB of geometry on its own, well past what a state attribute could hold:

An ECCC severe thunderstorm watch drawn as 112 municipal outlines over a map basemap in the card's detail panel

The basemap comes from Home Assistant’s own map tile proxy (core 2026.9 and later), so no third party sees the alert’s extent. Adaptive svg above, change your theme to see the inverse light/dark example.

Looking for testers and feedback

Before I write up anything formal, I want to make sure the model survives contact with reality. I can’t honestly evaluate every condition and region with the attention they deserve; frankly, I need help testing this approach.

Install: add https://github.com/seevee/cap_alerts to HACS as a custom repository (category Integration), then Add Integration → CAP Alerts.

Links:

If you’re somewhere with active weather, I’d love for you to run this alongside your current setup and compare. Feedback on edge cases, dropped or duplicated alerts, and UI quirks would all be hugely appreciated. Thanks!

3 Likes

Just stumbled upon this because I've been trying to get things working for multiple alerts, thanks so much! Installing now to test!

I don't know what any of this entails, but any chance of getting Pirate Weather added as it's my provider of choice?

1 Like

Seemed to be working the other day, but got another alert tonight and it's not showing any alerts, even though there's an ongoing one.

1 Like

You're most welcome, thanks for testing it out!

Quick clarification: Pirate Weather support lives in the card, rather than cap_alerts (which doesn't have a PW provider). I probably won't add one, either. In the US, PW's alerts come straight from NWS, which cap_alerts already ingests directly (same with WMO for global alerts), but PW flattens them, dropping the VTEC, zone, and lifecycle details present in the raw feed. Pointing cap_alerts at NWS gives you the highest-fidelity alert data.

As for the alert that didn't show, that's separate. How did you set up cap_alerts: NWS - by zone, GPS coordinates or device tracker? If by zone, mind sharing the code? And does the missing alert appear at https://api.weather.gov/alerts/active?point=YOUR_LAT,YOUR_LON ?

Also - feel free to open a new issue at github for this; I'm more likely to be watching that for updates when I'm actively fixing bugs.

Understood - thanks for the clarification!

I set it up by zone, NJZ008. I don't have answers to the other questions as it was a one-off thing I think, but I'll keep an eye on it should it happen again.

Thanks again for all the hard work!

1 Like

cap_alerts v0.2.0 is out

v0.2.0 shipped on 30 July, the first feature release since 0.1.1. It’s also the first one I promoted on the strength of reports from other people’s installs rather than my own testing.

:link: Release v0.2.0 · seevee/cap_alerts · GitHub

ECCC alerts now arrive in real time

Canadian alerts are ingested over NAAD’s TCP streaming feed the moment they’re issued, instead of waiting up to five minutes for the next poll. The NAADS user guide names streaming as the intended channel for automated systems running around the clock.

It’s on by default for ECCC entries. GeoRSS polling is kept as startup and reconnect backfill, plus a 30-minute safety resync, with a heartbeat watchdog and exponential backoff. Reconnect backfills are floored at the old poll cadence, so a flapping socket can’t generate more traffic than plain polling did. A new diagnostic entity, binary_sensor.cap_alerts_eccc_real_time_stream, reports whether the socket is up. If you’d rather not stream, turning it off falls back to the old behaviour.

The sanctioned Canadian feed is dropping live alerts

While migrating ECCC to alertready.ca ahead of the legacy endpoint’s retirement, live soaking showed that host persistently omitting in-effect Actual/Public alerts that were present on the legacy Pelmorex host at the same moment. One of them was at severity=Extreme.

This isn’t propagation lag. Individual alerts stayed missing across hours of consecutive samples, and the set of missing alerts changed from one minute to the next.

I’ve had a sampler running since the release, and every sample so far has shown a gap. Dozens of distinct alerts are absent, mostly severe thunderstorm and heat or air quality warnings. Some of the missing ones are alerts that have ended, so affected users would miss the all-clear as well as the alert itself. It’s reported upstream and acknowledged, with no fix yet.

The mitigation is in 0.2.0. The default auto feed source now fetches both hosts and unions their entries by CAP OID, so neither host’s gaps can hide an alert from you. If you’re in Canada and running this, you’re already covered, and there’s nothing you need to do.

Also in this release

  • Ended alerts no longer linger. ECCC publishes one <info> block per area group, each with its own status. The provider was reading the wrong block and never saw the termination signal, so alerts hung around until their expiry time. Entities now clear when the alert actually ends.
  • Truncated feed downloads no longer lose a poll’s alerts. The ~7 MB chunked feed arrives without a Content-Length, so an early-terminated stream produced a partial body that failed to parse at a random offset. Incomplete documents are now detected and retried.
  • Device-tracker location for every provider. ECCC, MeteoAlarm and WMO gained the GPS-tracker mode NWS already had. MeteoAlarm also gets a fully mobile mode: a tracker for polygon narrowing plus a country-source entity, so crossing a border re-resolves which national feed to query.
  • MeteoFrance entity churn is fixed. It embeds the issue timestamp in its CAP identifier, so every re-issue of a warning was minting a new entity and orphaning a stale one.
  • A refresh button. button.cap_alerts_<provider>_refresh, diagnostic, forces an off-cycle fetch on any provider.
  • Opt-in marine filter and typed multi-scheme geocodes (geocodes["EMMA_ID"], ["NUTS3"], ["WARNCELLID"] and so on) for feeds that mix coding schemes across countries.

:warning: One breaking change

MeteoAlarm area codes have moved. EMMA_ID values were previously written into geocode_same, an NWS-scheme field they never belonged in. They now live under geocodes["EMMA_ID"]. If you have templates or card config reading geocode_same on MeteoAlarm entities, they need updating. NWS and ECCC entities are unaffected.

Otherwise no reconfiguration is required. Existing entries pick up streaming, the auto feed source and the fixes on restart, and the marine filter stays off unless you turn it on. New options are under Settings → Devices & Services → CAP Alerts → Configure.

@OvalZyre

Your missing NWS alert back in June never got a resolution, and I want to be straight that nothing in this release specifically targets an NWS-side gap. The coverage problem above is Canadian, and I have no evidence of an equivalent one on the NWS feed.

Two things should make the next occurrence easier to pin down, though. The refresh button lets you force an off-cycle fetch as soon as you notice something missing. If the alert shows up right after a manual refresh, that’s a very different bug from one where it never appears at all, and knowing which would tell me where to look. The truncated-download fix is also a plausible candidate for your symptom, since it produced polls that silently returned nothing usable, though I can’t confirm that’s what you hit.

Still looking for testers

The ask is the same as the original post, but I can be more specific about where it would help most. Canada is the obvious one, since the streaming work and the union fix were built for that specific case. Europe is the other, because the next release is a MeteoAlarm-focused pass and this is the point where your edge cases can still shape it. And if the WMO feed is your only coverage, that path gets the least live exercise of the four (though will also be getting some attention in the next release).

Bugs are better on GitHub than in the thread, since I watch issues much more reliably when I’m actively fixing things:

Thanks to everyone who’s been running this. The reports coming back are what made the 0.2.0 promotion decision possible.

Thanks so much. I don’t believe I’ve had the issue since, and recently I’ve had multiple (upwards of 3 or 4) alerts at once and seemingly haven’t had anything missing. I’ll still keep an eye out, but all seems well.

1 Like

cap_alerts v0.3.1 is out

0.3.0 shipped on 5 August, and 0.3.1 followed within the half hour with an icon fix I didn’t want to sit on, so 0.3.1 is the one to install. This is the MeteoAlarm pass I promised at the end of the 0.2.0 post, and it was shaped almost entirely by reports from people on the tracker.

:link: Release v0.3.1 · seevee/cap_alerts · GitHub

A multi-day French warning is one entity now

MeteoFrance publishes one bulletin per calendar day. A four-day heat episode therefore arrived as four entities, each one minted at midnight and orphaning the one before it, so anything pointing at that sensor.cap_alert_* broke every night. Consecutive days now merge into a single episode keyed without the day component, and the ID survives midnight from here on.

In region-picker mode the bulletin is also exploded per department, so area_desc narrows from the bulletin’s full list (16 to 83 departments, depending on the day) to the one department your entity actually covers.

@Cyberdr3am reported this in July and then soaked the fix against a live episode to confirm it. There’s a breaking change attached to it, at the bottom of this post.

Icons no longer depend on which language you read alerts in

Per-alert icons were classified by matching keywords against the alert’s event text, which is free text in whatever language the feed publishes. Tuulivaroitus maa-alueille matched nothing, so a Finnish reader got mdi:alert on every warning. My first attempt at this read the alert’s English sibling block instead, which doesn’t work either: on FMI’s fi/sv/en documents the block you get is Swedish, and some alerts carry no English block at all.

MeteoAlarm alerts are now classified on awareness_type, the EUMETNET hazard code. It’s language-independent and required on every alert, so the icon is the same whether you read the alert in Finnish, Greek or English. The code table is pinned to the MeteoAlarm CAP Profile v2.0 §2.2.17 rather than to the third-party lists floating around, which disagree with the wire on where flooding sits.

Measured across 1705 live alerts in DE/ES/FI/NO/SE under a Finnish locale, fallback icons went from 29 to zero. Two corrections nobody had reported fell out of the same sweep: Swedish “Near gale” alerts carrying 7; coastalevent were drawing the wind icon instead of waves, and a Norwegian “Heavy rainshowers” carrying 13; rain-flood was drawing plain rain. Both are cases where the text matched and was still wrong — the argument for letting the code take precedence rather than just fill gaps.

Thanks to @vhtkrk, whose raw attribute dump is what showed the English-sibling approach was insufficient, and to @MF-142 for the original report on Chinese alerts.

Language selection reaches your language

There are two separate language axes here and 0.3.x fixed both. The UI now ships a Simplified Chinese translation for the config and options flows. Separately, alert content is now selected by matching your Home Assistant locale against each CAP <info> block’s declared language, instead of taking whichever block came first in the document.

Two matching bugs came out of that work. Norwegian alerts always fell back to English because MeteoAlarm tags them no while HA’s locales are nb and nn, and bare primary subtags like de weren’t matching de-DE. Both are fixed, and the fallback chain is now exact tag, then primary subtag, then English, then first block.

Region picker fixes

Three of them, all MeteoAlarm. An area that publishes several geocodes only offered the first one, so some regions were unselectable. Feeds that repeat their region tree once per language offered you every region two or three times over. And the picker was combining distinct Finnish warning regions into one entry, reported by @vhtkrk back in July.

An escape hatch for feeds with no geometry

Some WMO sources publish no per-alert polygons at all, which leaves country-wide as the only usable location mode. For China’s CMA feed that means one entry producing a couple hundred entities, enough to visibly destabilize the frontend while it populates.

There’s now an opt-in Area codes (prefix match) option under Configure, on every provider. Give it comma-separated prefixes and an alert is kept when any area code it publishes starts with one of them. Codes are hierarchical, so 13 is Hebei and 1307 is Zhangjiakou; on that Chinese feed it takes a country-wide entry from roughly 234 alerts to 28. Prefer the leading digits over pasting a full code, since code lengths vary within a scheme. Empty by default, so nothing changes unless you set it.

Also in this release

  • Point and circle geometry. CAP <circle> elements are parsed, and a zero-radius circle is published as a point. That’s how CAP-AU feeds like NSW RFS mark an incident location.
  • Polygons that validate. The GeoJSON coming out of the geometry endpoint was emitting unclosed linear rings, which violates RFC 7946 and can upset strict consumers. Rings are closed now, and there’s a live conformance check running against real feeds to keep it that way.
  • High-volume sources fit inside the poll timeout. Feeds that require fetching hundreds of CAP bodies were exceeding the timeout and returning nothing for the cycle.
  • Green MeteoFrance markers stay out. MeteoFrance publishes no-warning markers for quiet departments; those were becoming entities.
  • Fewer needless reloads. The options update listener now decides when a reload is actually required, instead of tearing the entry down on every save.

Under the hood, the provider-specific rules that had accumulated across the model, the normalizer and the individual providers now live in one declarative table. No behavior change, but it’s why the FMI work in the next release was a table entry rather than a second copy of the France logic.

:warning: One breaking change

MeteoFrance alert entity IDs are recreated once on upgrade. That’s the cost of the episode fix above: the new IDs no longer carry a day component, so they can’t match the old ones. Dashboard cards and automations referencing a sensor.cap_alert_* entity for a French warning need repointing, and the old entities hang around as unavailable until you remove them. It’s a one-time break — and midnight stops breaking them after this.

No other provider is affected, and nothing to do on NWS, ECCC, WMO or any non-French MeteoAlarm service.

What’s next

0.4.0 is in alpha now. It carries the same midnight merge for Finland (FMI splits on window edges rather than calendar days, so it needed its own rule), an active/upcoming split on the count sensor, and an answer to @jackwarden-eng’s question about telling an early cancellation apart from a plain expiry: the removal event now says why an alert went away instead of just that it did. Same upgrade note applies as above for Finnish alerts.

Still looking for testers

Europe is where the help would go furthest right now. This release was shaped by France and Finland because that’s who reported, and MeteoAlarm has around 37 member services with real differences between them. If you’re on a national feed nobody has exercised yet, running this alongside your current setup and telling me what looks wrong is exactly the thing that turns into a fix. The WMO path still gets the least live exercise of the four providers.

Bugs are better on GitHub than in the thread, since I watch issues much more reliably when I’m actively fixing things: Issues · seevee/cap_alerts

Thanks again to everyone who reported something this cycle. Nearly every line above started as somebody else’s bug report.

cap_alerts v0.4.0 is out

0.4.0 shipped on 21 August. It’s the biggest release since this thread opened: one new provider, one breaking attribute change, and a fix for alerts silently losing their attributes in history.

:link: Release v0.4.0 · seevee/cap_alerts · GitHub

GDACS is the first non-weather provider

The Global Disaster Alert and Coordination System, run jointly by the UN and the European Commission. Seven event types: earthquake, tropical cyclone, flood, volcano, drought, wildfire and tsunami. Scope is worldwide or a GPS point, same as the other providers, and the options flow filters by event type.

This is the provider that makes the model a CAP model rather than a weather model. The entity shape, the severity tiers and the lifecycle events all carry over unchanged, which is roughly the thing the original post set out to test.

One default differs from the other providers. The alert-level floor starts at Orange rather than “everything the feed offers”. When I measured it on 8 August, Green was 327 events worldwide and 280 of those were wildfires, so a global entry would have minted an entity for every one. Orange left 7. Drop the floor if you want the tail, just know that a cold fetch at Green takes about 17 s of the 30 s poll timeout.

Alerts stop losing their attributes in history

The recorder discards a state’s entire attribute set once it serializes past 16,384 bytes. It stores {} and logs a line. One live ECCC air quality warning serialized to 19,080 bytes, so this wasn’t theoretical, it was happening on Canadian installs.

0.4.0 measures the same payload the recorder measures and trims only when it doesn’t fit. The order is strict: alternate-language text goes first, then the primary description, and the instruction last, since that’s the protective-action text you actually need. The whole of one field’s expendable text goes before the next field gives up a byte.

With the duplicate geocodes (see the breaking change below) gone, the worst alert in a 443-alert sweep across every provider serializes to 13,919 bytes. Nothing needs trimming today. The bound is there for the one that will.

Alert endings say why

cap_alerts_incident_removed now carries a removal_reason when the source published one. @jackwarden-eng asked for this back in July. An ECCC watch upgraded to a warning used to end exactly the way an all-clear ends, so an automation paying per message couldn’t tell that the successor’s incident_created was already carrying the news.

Four more fixes in the same area, two of them from the same reporter:

  • one missed poll no longer reads as a cancellation
  • incident_removed fires once per ending, not once per poll while the ended alert stays in the feed
  • an ECCC alert ended early reports cancel, not expired
  • an alert with no expires needs a real exit signal before it’s dropped

docs/events.md has the table of how phase and removal_reason combine.

NWS re-issues collapse into one entity

Non-VTEC products like air quality advisories re-transmit every hour or two with a fresh identifier and no references. Each transmission was minting a new entity, 5 for one Denver advisory when I looked on 6 August. Nationally, 23 of 65 active non-VTEC alerts were surplus re-issues that day. They collapse onto one entity now and the latest transmission wins.

The rest

Change What you’ll notice
Count sensor splits on onset active and upcoming attributes alongside the total. @vhtkrk’s request from the 0.3.0 alpha feedback.
Diagnostics download Settings → Devices & Services → CAP Alerts → ⋮ → Download diagnostics. Scope, endpoints, update health, filters and the convention row in effect. Location and credentials are redacted, so it’s safe to attach to an issue.
One entry per scope Setting up a duplicate aborts instead of quietly polling the same feed twice. Pre-existing duplicates get a warning naming both entries.
Scope validated at setup A scope that doesn’t resolve is rejected on the form instead of creating an entry that fails its first refresh.
FMI window merge Finnish warnings split at a window edge come through as one episode. The Finnish counterpart to the French fix in 0.3.1.

:warning: One breaking change

geocode_ugc, geocode_same, geocode_clc and geocode_sgc are gone. Every code they carried is in the geocodes container, keyed by scheme. Publishing both put the same codes on the wire twice, 5,510 bytes on one live ECCC alert that was already over the recorder ceiling above.

If you template on the old keys, it’s state_attr('sensor.x', 'geocodes').UGC now. Versioned scheme names collapse to a stable key too, so ECCC’s layer:EC-MSC-SMC:1.1:CLC publishes as plain CLC and your key survives the next version bump. weather_alerts_card users need to do nothing, the card already reads the container.

Two smaller one-time effects, same shape as the MeteoFrance note in 0.3.1. FMI alert entity IDs are recreated once on upgrade, because the merged IDs no longer carry the window. NWS non-VTEC alerts, air quality and the like, are re-minted once as the re-issues collapse. Repoint anything referencing those sensor.cap_alert_* entities and remove the unavailable leftovers. No config migration and no re-setup otherwise.

What’s next

Canada. The legacy Pelmorex NAAD host retires around late September, and it’s the host the 0.2.0 union fix leans on when streaming is off. Already on main: a repair that flags the entries exposed, and a recovery path that pulls anything missed during socket downtime straight from the surviving NAAD repository, using the references the heartbeats already carry. Also landed since the tag: NWS GPS mode is validated against /points/ at setup, GPS fields prefill from your home location, and every config menu has a back button.

Still looking for testers

Same ask as before, with one addition. If you set up GDACS, I’d like to know whether the Orange default is the right call and how a GPS scope behaves for you. It’s the path with the least live exercise now, and the first one where “alert” doesn’t mean weather. Canada matters again for the reasons above. Europe is still where reports have turned into fixes fastest.

Bugs are better on GitHub than in the thread, since I watch issues much more reliably when I’m actively fixing things: Issues · seevee/cap_alerts

Thanks to everyone who reported something this cycle.

v0.5.0 is out - NAAD sunset release

Released on 14 September: rss.naad-adna.pelmorex.com retires around late September, and it’s the host the 0.2.0 union fix leans on when streaming is off. Everything else is what the alphas carried since 0.4.1, which slipped out on 23 August with GDACS device-tracker mode.

:link: Release v0.5.0 · seevee/cap_alerts · GitHub

Nothing in the integration changed between rc.1 and the tag, only the version number. The rc soaked on my instance from 5 September without a cap_alerts traceback.

If you stream ECCC, the sunset is a no-op

Streaming has been the default for ECCC entries since 0.2.0. The retiring host never supported streaming, so alerts keep arriving the same way they do today. Most Canadian installs are in this group and can stop reading here.

The two configurations exposed get a repair

With streaming off, you poll the GeoRSS index. After the sunset that’s rss.alertready.ca alone, and that host has never carried every live alert. My host-gap probe has sampled it since 30 July, and every sample has shown gaps. Pinning the feed source to pelmorex is worse, every fetch fails once the host is gone.

Both cases now raise a repair in Settings → Repairs, one per entry. Submit applies the fix, streaming back on or feed source back to auto. If polling is deliberate, Ignore it. There’s no sunset detection, the recommendation is already correct today.

Streaming now recovers after disconnect

Socket downtime was streaming’s one blind spot. Over 7.5 days I measured 6 reconnects, 32.7 s offline in total, and one missed alert. Every NAAD heartbeat lists the last ten alerts, and cap.alertready.ca serves any of them by reference for 48 hours. The entry now fetches whatever it hasn’t seen after a reconnect, so a gap no longer depends on the index that has the gaps.

Polling got cheaper too. The alertready host honors ETags since 25 August, so an unchanged feed costs a header exchange instead of a ~6 MB download.

Thunderstorm warnings now match on the storm polygon

ECCC’s Convective Alert Modernization went live on 11 August. Severe thunderstorm and tornado warnings now carry a forecaster-drawn threat polygon alongside the legacy zone polygons. GPS and tracker mode were still matching on the zones, so you got warnings for storms nowhere near you. @jackwarden-eng reported it with a captured body, and both of their alert IDs reproduced against 216 live convective bodies.

The threat polygon is the location test now, and the entity publishes that geometry. Province mode is unchanged.

Endings fire once, and name the successor

ECCC publishes every update twice, English-first and then bilingual under a fresh identifier. An area group ending across that pair fired incident_removed twice on streaming. The store follows CAP identifier lineage now, so that’s one removal.

incident_removed with removal_reason: superseded also carries superseded_by, the successor’s CAP identifier. It matches the identifier attribute on the successor entity, so an automation can hand off from one to the other. Expect it absent more often than present though. Of 27 transitions I measured, 18 named a document NAAD never published. docs/events.md has the details.

The rest

Change What you’ll notice
GPS fields prefill Lat/lon default to your HA home location.
NWS GPS validated at setup A point outside the NWS domain is rejected on the form, not on the first poll.
Back on every menu Every config menu has a back option now.
English as the alternate On multi-language WMO and MeteoAlarm bodies, the alternate <info> block prefers English.
GDACS tracker mode Shipped in 0.4.1. A tracker with no location makes the entry unavailable rather than silently going worldwide.

Upgrading

HACS, restart, done. No config migration and no entity IDs change. If a repair shows up after restart, read it before dismissing it.

What’s next

GDACS geometry. A single GDACS entry can fill the shared geometry cache and evict other providers’ polygons with it. The flood shapes it does keep are country outlines rather than the flooded area. Three issues are already open on that. I’ll post here when the Pelmorex host actually goes dark.

Still looking for testers

Canada, more than ever. If a repair appears on your ECCC entry, I’d like to know what you had set and why, especially if you chose polling on purpose. Tracker users in Canada, what’s left of the convective season is the first live exercise the threat-polygon match gets outside my instance. GDACS and Europe, same ask as last time.

Bugs are better on GitHub than in the thread, and a diagnostics download attached carries the version and the filters in effect: Issues · seevee/cap_alerts

Thanks to everyone who reported something this cycle.

v0.5.1 is out - GDACS geometry

Released on 18 September. Four GDACS geometry fixes and nothing else. Weather providers are untouched except for the polygon store, which every entry shares.

:link: Release v0.5.1 · seevee/cap_alerts · GitHub

The rc soaked on my instance from 15 September.

Floods draw footprint only

Every GDACS flood file carries two layers, the flooded area and the outline of the affected country. The class filter kept both, so a flood in Connecticut spanned Hawaii to Maine on the card and GPS mode matched every scope in the United States. The footprint wins now. The outline only ships when it’s the only layer there is.

Geometry fetches stop flickering

gdacs.org served the same 2.4 MB file in 5 s one minute and 16 s the next, and the shared 10 s timeout lost 7 of 28 fetches across four runs on 6 September. Each loss shipped the alert with no polygon and purged the stored one, so flood shapes blinked poll to poll. Geometry fetches get 25 s of their own now, plus a deadline inside the poll timeout so one slow file can’t fail the whole entry. A fetch that still loses ships the last good shape instead of nothing, with one warning per poll saying how many alerts are carrying one.

The polygon store is budgeted per entry

The 5 MB cap was global. One worldwide GDACS entry held 4.3 MB of it and evicted other entries’ polygons on every poll, so a WMO alert with six good polygons drew nothing and the geometry endpoint answered 404 while the alert was live. Each entry evicts only its own now. The first eviction logs at warning, and the diagnostics download reports stored refs, bytes, and how many active alerts lost theirs.

Upgrading

HACS, restart, done. No config migration and no entity IDs change. The README is reorganized for HACS users, the dev material moved to CONTRIBUTING.

What’s next

The Pelmorex NAAD host is still due to go dark late this month. I’ll post here when it does. 0.6.0 is provider work: Germany’s NINA feeds and Australia’s CAP-AU are the two on the milestone, and both need testers who live there.

Still looking for testers

GDACS with a Green floor and a tracker, that’s the combination the deadline protects and I can only exercise it from one place. If you run more than one provider on the same instance, the eviction warning should never appear in your log. Tell me if it does, with a diagnostics download attached: Issues · seevee/cap_alerts

Anyone in Germany or Australia willing to watch a feed for a cycle?

v0.6.0 is out - Germany and Australia

Released on 1 October: two new providers and three identity fixes for the Australian feeds. The biggest change since 0.2.0, so it sat on rc.1 for a week.

:link: Release v0.6.0 · seevee/cap_alerts · GitHub

Inside the integration the only change since rc.1 is one manifest line, hassfest started rejecting the defusedxml pin this morning. The rc soaked on my instance from 24 September with ten entries polling and no cap_alerts traceback.

Germany: BBK / NINA, before HA 2026.11 takes the nina attributes away

The card’s adapter over the core nina integration reads attributes that HA 2026.11 removes. BBK’s own API is CAP 1.2 as JSON, public and unauthenticated. It carries what no other HA path has: MoWaS, KATWARN, BIWAPP and the LHP flood portal, alongside the DWD relay. So this is the GDACS pattern, the integration ingests the source and the card stays a passthrough.

Setup takes a district (Regionalschlüssel, widened to Kreis level), a GPS point or a device tracker. The language option includes de-LS, the easy-read register MoWaS publishes beside plain German. No channel selector and no severity option, on purpose. The DWD channel is the same Warnstufe 3 to 5 set MeteoAlarm Germany already relays, so running both means seeing those twice.

Australia: four states under one provider

NSW RFS, Queensland Fire Department, DFES Emergency WA and TasALERT publish the same CAP-AU profile, so it’s one provider with one entry per state. Victoria is GeoJSON and will be its own provider. SA, NT and ACT publish no CAP at all.

Severity comes from the Australian Warning System tier, not CAP <severity>, which is uniform on every feed. Emergency Warning, Watch and Act and Advice map to extreme, severe and moderate. A minimum alert level option hides the informational tiers.

There’s no GPS or tracker mode for Australia. Most NSW and QLD alerts are a marker, not a polygon, so a point-in-polygon test would drop most of a feed. Markers ship as points and the card’s radius filter is the intended consumer. That needs weather_alerts_card 3.5.0, on 3.4.0 a point alert draws as a 0x0 box.

Re-issued warnings update their entity instead of spawning one

Three of the four feeds mint a fresh CAP identifier on every update. Queensland re-minted 36 of 74 ids in 46 hours, one fire ran through twelve, and each one was a new entity. NSW and TAS now key on the incident number plus the product code (TAS publishes a Bushfire Advice and a Smoke Alert for the same fire). Queensland warnings key on the area description. WA ids were already stable.

Over the first 58 hours on the rc the dev box saw zero removed-and-recreated pairs.

The rest

Change What you’ll notice
WMO mirror watch SWIC’s mirror can silently stop following a source. 14 of 93 were a week behind on 19 September. The feed probe now files an issue when one stalls, there’s nothing the integration can do at runtime.
Hostile XML A body defusedxml refuses is “not a CAP document” now instead of an uncaught exception. Found by new property tests over the parsers.
Icons BBK all-clears and three more event needles classify.

Known gaps

WA hazmat warnings carry no warning-system tier, so a minimum alert level above All hides them. 0.6.1. One wide ECCC frost advisory in French overflowed the recorder’s 16 KB attribute limit on my instance, the entity was fine, history skipped two writes. Pre-dates 0.6.0, also 0.6.1.

Upgrading

HACS, restart, done. 0.5.1 users see no config migration and no entity ID changes. If you ran a 0.6.0 alpha, the NSW, TAS and QLD entities re-create once. AU point alerts need card 3.5.0 or later.

What’s next

The two 0.6.1 items above. Then the neutral-layer extraction, so other integrations can publish into the same entity model without carrying a config flow. Victoria is the next Australian state once someone with a stake asks for it.

Still looking for testers

Germany and Australia, obviously. Australia most of all, the fire season is starting. I haven’t seen a Watch and Act or Emergency Warning alert through the provider yet, only Advice and below. If you’re in QLD or WA and one lands near you, I’d like to know the entity did what the notes say. Germany, MoWaS traffic is rare by nature, so KATWARN and the DWD relay are what you’ll see first.

Bugs are better on GitHub than in the thread, and a diagnostics download attached carries the version and the filters in effect: Issues · seevee/cap_alerts

Thanks to everyone who reported something this cycle.

This looks amazing. I’m currently just using a very crude Claude designed NWS a “polling” setup, and would much rather have something thoroughly thought out by a human. I live in a very low extreme weather area. What’s a good method to test this for my entire dashboard system to make sure it’s actually working?

1 Like

@hoffsta Thanks, glad it looks useful! Quiet weather is the normal case, so the trick is to borrow someone else’s.

Assuming you’ve got a quiet entry for your own location: add a second NWS entry pointed somewhere that has alerts right now. Pick a colored spot on alerts.weather.gov and use its zone ID or a lat,lon inside it. Within one poll you should see a sensor per alert, the count sensor go up, and incident_created fire on the event bus. The Refresh button skips the wait.

For the dashboard (if you’re using weather_alerts_card), list both entries under the card’s devices:. That exercises the real render path, and deleting the test entry later leaves your home config untouched.

Automations work the same way. Listen for incident_created and filter on entry_id once you only want home.

Would love to hear more about what your current setup drives - are you using a dashboard card or notifications?

Thanks! This is helpful. I’m using a jailbroken Amazon Echo Show 8 running kiosk satellite for a kitchen interface. I had Claude build an entire custom UI. So far it has a weather page with current conditions and forecast, a timers page, a media player, and a pop up alerts framework. Just getting started but it’s an amazing device, and Kiosk Satellite is simply out of this world. If you haven’t seen it yet, I highly recommend checking it out for Android based interfaces.


1 Like

@hoffsta Nice build! I hadn’t seen Kiosk Satellite before, I’ll take a look.

For the pop-ups, listen for incident_created instead of polling. The payload has event, severity and area_desc, and severity is normalized to extreme / severe / moderate / minor / unknown, so the pop-up style can key off it directly. incident_removed carries the same incident_id, which is your dismiss.

It doesn’t carry entity_id yet, the event fires before the entity is registered. Filed as #249. Until then the full text lives on the alert entity, which shows up on the device in the same poll.

From the photos it looks like a page of its own rather than Lovelace cards. If so, open a websocket to HA with the kiosk’s token and send subscribe_events with event_type: incident_created. If it’s a dashboard, hass.connection.subscribeEvents does the same with no auth to manage. Which flavor are you running?

EDIT: #249 is merged. incident_created now carries entity_id, and fires after the entity has written its state, so the pop-up can read description and instruction straight off that entity in the same run. Ships in 0.6.1, not in a release yet.

v0.6.1 is out - events across a restart

Released on 5 October. Six fixes, most of them on the event bus. Nothing new to configure.

:link: Release v0.6.1 · seevee/cap_alerts · GitHub

The rc soaked on my instance from 3 October.

A restart no longer re-fires every alert

Restarting Home Assistant used to fire incident_created for every alert the integration already knew about, so a notification automation announced the whole list again. A restart re-validates the alerts it knew now. It waits for a real fetch before deciding what’s gone, on ECCC streaming the old grace ran out in about a minute. And it doesn’t re-announce an ending the feed still publishes.

incident_created carries entity_id

The event fired before the alert’s entity existed, so entity_id was never in it. It fires once the entity has written its state now, and a popup automation can read the entity straight from the event. @hoffsta, this is the gap I flagged for your kiosk.

Change What you’ll notice
Payload budget on wide alerts A 291-area ECCC frost advisory overflowed the recorder limit and lost its attributes in history. Geocodes stay on the entity but out of the recorder, and the area list is cut before the text.
WA hazmat warnings They carry no alert level, so they sat below the minimum-level floor. They rank by CAP severity now.
HA 2026.4 and 2026.5 The repairs platform failed to import below 2026.6. It loads on the declared floor of 2026.4.3 now, and CI tests that floor.

Upgrading

HACS, restart, done. No config migration and no entity IDs change.

What’s next

0.7.0 marks alert entities with an incident device class, ships an “incident became severe” trigger for the automation editor, and restores alert content after a restart.

Still looking for testers

If you automate on incident_created or incident_removed, restart HA with alerts active and tell me what fires: Issues · seevee/cap_alerts

1 Like

Would Tsunami CAP Alerts be a suitable provider addition? I know of two feeds described at this URL: U.S. Tsunami Warning Centers. Tsunami Warnings eventually make it to GDACS but only after the risk exceeds some threshhold, I think, not while waiting for more information for locations remote from an earthquake.

1 Like

@galentx Yes! The M7.6 off Panama this afternoon is the case for it. PTWC put out four threat bulletins, and neither GDACS nor the NWS API carried anything on the tsunami side.

The CAP and Atom URLs on that page hold one message each, whatever the center sent last. An aftershock statement had overwritten the whole Panama sequence by 20:34Z. The per-product files underneath do work, so it’s buildable. Filed as #298, behind 0.7.0.

That was a rather quick bit of sleuthing on your part. Glad you found a path to a more robust source.