Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 41 additions & 13 deletions custom_components/roborock_custom_map/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,47 @@ async def async_setup_entry(
async_add_entities: AddConfigEntryEntitiesCallback,
) -> None:
"""Set up Roborock image platform."""
async_add_entities(
RoborockMap(
config_entry,
f"{coord.duid_slug}_custom_map_{map_info.name or f'Map {map_info.map_flag}'}",
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,
f"{coord.duid_slug}_custom_map_{map_info.name or f'Map {map_info.map_flag}'}",
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):
Expand Down
49 changes: 36 additions & 13 deletions custom_components/roborock_custom_map/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from homeassistant.components.select import SelectEntity
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
from homeassistant.helpers.restore_state import RestoreEntity
Expand All @@ -29,18 +29,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):
Expand Down