fix(config_flow): let the update listener own reload decisions - #77
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Clears a deprecation that becomes a hard error in HA 2026.12, taking every reconfigure flow with it.
The problem
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, andasync_update_reload_and_abortat 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
OptionsFlowManager→async_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_abortinstead ofasync_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_updatednow owns every reload decision. It already had this shape for the streaming toggle; it gains the case the flow used to cover:scan_interval,timeoutlanguage,exclude_marine,geocode_prefixesThe 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_abortappears nowhere inconfig_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