From fc83c9757ccd04040d2596cd825293b17ee21a34 Mon Sep 17 00:00:00 2001 From: Paolo Stivanin Date: Sun, 11 Oct 2026 13:38:25 -0400 Subject: [PATCH] Add map entities when home data arrives, not only at setup --- .../roborock_custom_map/image.py | 54 ++++++++++++++----- .../roborock_custom_map/select.py | 47 +++++++++++----- 2 files changed, 76 insertions(+), 25 deletions(-) diff --git a/custom_components/roborock_custom_map/image.py b/custom_components/roborock_custom_map/image.py index 80354fe..255b6b6 100644 --- a/custom_components/roborock_custom_map/image.py +++ b/custom_components/roborock_custom_map/image.py @@ -68,19 +68,47 @@ async def async_setup_entry( async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up Roborock image platform.""" - async_add_entities( - RoborockMap( - config_entry, - map_unique_id(coord.duid_slug, map_info.map_flag, map_info.name), - coord, - coord.properties_api.home, - map_info.map_flag, - map_info.name, - ) - for coord in config_entry.runtime_data - if coord.properties_api.home is not None - for map_info in (coord.properties_api.home.home_map_info or {}).values() - ) + added: set[tuple[str, int]] = set() + + @callback + def _async_add_new_maps() -> None: + """Add an entity for every map that has appeared since the last check. + + Home data is not guaranteed to be populated by the time this platform + is set up: a device that is busy when Home Assistant starts makes the + Roborock coordinator skip `discover_home()`, so `home_map_info` is + still empty here and that device silently ends up with no map entity + until the config entry is reloaded by hand. Re-checking on every + coordinator update picks those maps up as soon as they arrive, and as + a bonus also catches maps created in the Roborock app while Home + Assistant is running. + """ + entities = [] + for coord in config_entry.runtime_data: + if (home := coord.properties_api.home) is None: + continue + for map_info in (home.home_map_info or {}).values(): + key = (coord.duid_slug, map_info.map_flag) + if key in added: + continue + added.add(key) + entities.append( + RoborockMap( + config_entry, + map_unique_id(coord.duid_slug, map_info.map_flag, map_info.name), + coord, + home, + map_info.map_flag, + map_info.name, + ) + ) + if entities: + async_add_entities(entities) + + _async_add_new_maps() + + for coord in config_entry.runtime_data: + config_entry.async_on_unload(coord.async_add_listener(_async_add_new_maps)) class RoborockMap(RoborockCoordinatedEntityV1, ImageEntity): diff --git a/custom_components/roborock_custom_map/select.py b/custom_components/roborock_custom_map/select.py index 8143b09..4516085 100644 --- a/custom_components/roborock_custom_map/select.py +++ b/custom_components/roborock_custom_map/select.py @@ -33,18 +33,41 @@ async def async_setup_entry( async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up rotation Select entities (one per map).""" - async_add_entities( - RoborockMapRotationSelect( - config_entry=config_entry, - unique_id=f"{coord.duid_slug}_map_rotation_{map_info.map_flag}", - coordinator=coord, - map_flag=map_info.map_flag, - map_name=map_info.name, - ) - for coord in config_entry.runtime_data - if coord.properties_api.home is not None - for map_info in (coord.properties_api.home.home_map_info or {}).values() - ) + added: set[tuple[str, int]] = set() + + @callback + def _async_add_new_maps() -> None: + """Add a select for every map that has appeared since the last check. + + Mirrors the image platform: home data may still be empty when this + runs, in which case the affected device would get no rotation select + until the config entry is reloaded by hand. See image.py for details. + """ + entities = [] + for coord in config_entry.runtime_data: + if (home := coord.properties_api.home) is None: + continue + for map_info in (home.home_map_info or {}).values(): + key = (coord.duid_slug, map_info.map_flag) + if key in added: + continue + added.add(key) + entities.append( + RoborockMapRotationSelect( + config_entry=config_entry, + unique_id=f"{coord.duid_slug}_map_rotation_{map_info.map_flag}", + coordinator=coord, + map_flag=map_info.map_flag, + map_name=map_info.name, + ) + ) + if entities: + async_add_entities(entities) + + _async_add_new_maps() + + for coord in config_entry.runtime_data: + config_entry.async_on_unload(coord.async_add_listener(_async_add_new_maps)) class RoborockMapRotationSelect(RoborockCoordinatedEntityV1, RestoreEntity, SelectEntity):