Skip to content

fix(config_flow): let the update listener own reload decisions - #77

Merged
seevee merged 1 commit into
mainfrom
fix/config-entry-listener-deprecation
Aug 4, 2026
Merged

fix(config_flow): let the update listener own reload decisions#77
seevee merged 1 commit into
mainfrom
fix/config-entry-listener-deprecation

Conversation

@seevee

@seevee seevee commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Clears a deprecation that becomes a hard error in HA 2026.12, taking every reconfigure flow with it.

The problem

Detected that custom integration 'cap_alerts' has an update listener and should use it
for scheduling a reload. This will stop working in Home Assistant 2026.12.0

Deprecated in 2026.6: pairing a config-entry update listener with a reloading config-flow method, because the entry "reload[s] twice and/or create[s] a race condition". It becomes an error in 2026.12.

We do exactly that pairing — one listener in __init__.py, and async_update_reload_and_abort at 15 call sites, i.e. every reconfigure step in all four providers. Today that means a warning plus a double reload on each reconfigure. On 2026.12 it means changing an NWS zone, an ECCC province, a WMO source, a MeteoAlarm region, or the new area-code mode fails outright.

The options flow is unaffected either way — it goes through OptionsFlowManagerasync_update_entry → the listener, never the deprecated methods.

The fix

Of the three sanctioned migrations, keep the listener and drop the flow's reload (async_update_and_abort instead of async_update_reload_and_abort).

Removing the listener — the other obvious option — would mean reloading on any entry update. A reload tears down and re-establishes the ECCC NAAD stream socket, which is far too much to pay for nudging a scan interval. That in-place path is the whole reason the listener exists.

So _async_entry_updated now owns every reload decision. It already had this shape for the streaming toggle; it gains the case the flow used to cover:

Change Result
Entry data (provider, location, source, filter mode) reload
Streaming toggle reload
scan_interval, timeout applied in place
language, exclude_marine, geocode_prefixes applied in place

The split is by when a value is read: consumed once at construction → rebuild; re-read per poll in _apply → no rebuild.

Data changes are detected by comparing against a snapshot taken when the coordinator was built (entry_data_changed). The whole mapping is compared rather than named keys, so a data key added later cannot silently skip the reload.

Renamed from _async_options_updated, since it is no longer only about options.

Testing

12 new tests: every reconfigure shape reloads (including a provider switch and a filter-mode change that only removes a key), options changes do not, the streaming toggle still does, and a data change that coincides with a streaming change schedules exactly one reload.

Plus a static assertion that async_update_reload_and_abort appears nowhere in config_flow.py — reintroducing one call would break every reconfigure on 2026.12, and that failure surfaces only in a UI flow, which nothing else in the suite exercises.

671 tests pass; ruff, ruff format, and mypy clean.

Verification caveat: deployed to a dev instance, which loads clean with no errors. That confirms startup health but is not proof the warning is gone — the deprecation only fires during a reconfigure, and I have not driven one through the UI since deploying. The static test is what pins the behaviour.

Assisted-by: Claude:claude-opus-5

Home Assistant deprecated pairing a config-entry update listener with a
reloading config-flow method in 2026.6, because the entry reloads twice
and the two paths can race. It becomes an error in 2026.12. We do exactly
that pairing: one listener registered in __init__, and
async_update_reload_and_abort at all 15 reconfigure call sites across the
four providers. Every reconfigure logs the warning today and would fail
outright on 2026.12 — changing an NWS zone, an ECCC province, a WMO
source, a MeteoAlarm region, or the new area-code mode.

Of the three sanctioned migrations, keep the listener and drop the flow's
reload. Removing the listener instead would mean reloading for any entry
update, and a reload tears down and re-establishes the ECCC NAAD stream
socket — far too much to pay for nudging a scan interval, which is the
reason the in-place path exists at all.

So the flow now calls async_update_and_abort, which updates without
reloading, and _async_entry_updated decides. It already had this shape
for the streaming toggle; it gains the case the flow used to cover, by
comparing entry data against the snapshot the coordinator was built from.
The whole mapping is compared rather than named keys, so a data key added
later cannot silently skip the reload.

The split is by when a value is read: anything consumed once at
construction — provider, location, source id, stream wiring — needs the
rebuild, while anything re-read per poll in _apply, such as
exclude_marine and geocode_prefixes, does not. Renamed from
_async_options_updated, since it is no longer only about options.

A test asserts async_update_reload_and_abort appears nowhere in
config_flow.py. Reintroducing one call would break every reconfigure flow
on 2026.12, and the failure would show up in a UI flow rather than in
anything the rest of the suite exercises.

Ref: https://developers.home-assistant.io/blog/2026/05/07/config-entry-listener-together-with-reloading-methods/

Assisted-by: Claude:claude-opus-5
@seevee
seevee merged commit 220ffcc into main Aug 4, 2026
5 checks passed
@seevee
seevee deleted the fix/config-entry-listener-deprecation branch August 4, 2026 04:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant