Start from cached capabilities when the device is offline at setup#439
Open
st03psn wants to merge 3 commits into
Open
Start from cached capabilities when the device is offline at setup#439st03psn wants to merge 3 commits into
st03psn wants to merge 3 commits into
Conversation
Previously async_setup_entry raised ConfigEntryNotReady whenever the device could not be reached during setup (authenticate/get_capabilities/ first refresh). For a device that is intentionally powered off part of the time (e.g. a seasonal/portable split), a normal HA restart while the device is off surfaces the "needs attention / Failed to authenticate" banner even though the device is merely offline. Cache the device capabilities in config_entry.data on the first successful get_capabilities(). If the device is unreachable at a later (re)setup and a cache exists, build the entities from the cached capabilities and start with entities unavailable (device.online is False), reconnecting in the background, instead of raising ConfigEntryNotReady. A cold start with no cache still raises ConfigEntryNotReady, since entities cannot be built without capabilities. Enum values in the capabilities dict are converted to their names so the cache is JSON-serializable for config_entry.data. The cache is only written when changed to avoid triggering the update listener reload loop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n offline start When the entry starts from cached capabilities while the device is offline, authenticate() fails before msmart stores the token/key on the LAN connection. The coordinator's refresh() then calls the device's lazy authenticate() with no credentials, so a V3 device can never re-establish its session on its own once it comes back — the entities stay unavailable until a manual reload re-runs async_setup_entry. Pass the token/key to the coordinator and (re)authenticate in _async_update_data when the device has no stored credentials, so polling recovers automatically once the device is reachable again. The branch is skipped once authenticated (device.token is set), so the online path is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a boolean option (default off) to the options flow so the offline-tolerant startup is opt-in. When disabled, setup keeps the standard ConfigEntryNotReady behavior; when enabled, an unreachable device with cached capabilities starts unavailable instead of showing a setup error. Capabilities are still cached unconditionally so the option works immediately once enabled. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Add an opt-in "Allow offline startup" option so a device that is intentionally powered off (e.g. a seasonal/portable PortaSplit) no longer surfaces the "Failed to authenticate with device." needs-attention banner on an HA restart. When enabled, the entities start
unavailableand reconnect in the background — the normal "device offline" UX. The option defaults to off, so existing installs keep the currentConfigEntryNotReadybehavior unchanged.Fixes #438.
Problem
async_setup_entryraisesConfigEntryNotReadywhenever the device is unreachable during setup (inauthenticate(),get_capabilities(), or the coordinator's first refresh). A disconnect after setup is already handled viadevice.online; the banner only appears when setup re-runs while the device is off, because capabilities are queried live and there is nothing to build entities from.Approach
allow_offline_startup(boolean, default off) in the options flow. When off, setup behaves exactly as before. All of the behavior below is gated on it.config_entry.data(cached_capabilities) on the first successfulget_capabilities()— done unconditionally (cheap, and makes the option work immediately once enabled). Enum values are converted to their names so the cache is JSON-serializable; written only when changed to avoid triggering the update-listener reload loop.override_capabilities(cached, merge=False), and usecoordinator.async_refresh()(which does not raise) instead ofasync_config_entry_first_refresh(). Entities startunavailablebecausedevice.onlineis False.authenticate()failed before msmart stored the token/key on the LAN connection, so the coordinator'srefresh()(which lazily callsauthenticate()with no credentials) could never re-establish the session — entities would stay unavailable until a manual reload. The coordinator now receives the token/key and re-authenticates in_async_update_datawhile the device has no stored credentials, so polling recovers automatically once the device is reachable again. The branch is skipped once authenticated (device.tokenis set), leaving the online path unchanged.ConfigEntryNotReady— entities cannot be built without capabilities.Behavior (with the option enabled)
setup_retry+ bannerloaded, entitiesunavailablesetup_retry+ bannerConfigEntryNotReady)ConfigEntryNotReady)Testing
Verified end-to-end on a live HA OS instance (core-2026.6.4, msmart-ng 2026.7.0) with a real V3 PortaSplit, option enabled:
loaded;config_entry.data.cached_capabilitieswritten once, with enum names (COOL,FAN_ONLY,CUSTOM_FAN_SPEED, …) — JSON-serializable, matching the live device caps.loaded,climate.*and sensorsunavailable, no banner, log showsCould not authenticate with device ID …, starting from cached capabilities: Connect failed.availableon their own within one update interval (confirmed via the logbookunavailable → offtransition with no intervening setup).ConfigEntryNotReady(correct fallback).Also verified against
msmart-ng==2026.7.0thatcapabilities_dict()→ name conversion →override_capabilities(..., merge=False)round-trips cleanly (the raw enum dict is rejected byoverride_capabilities, which is why the name conversion is needed), and that a failedauthenticate()leavesdevice.token/device.keyunset (the reason the coordinator must re-authenticate).