From 51be90d87e5105486391e07fb463a0a02949c193 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 3 May 2023 18:39:27 +0200 Subject: [PATCH] Migrate cloud settings for all Alexa entities (#92413) * Migrate cloud settings for all Alexa entities * Also set settings for unknown entities --- .../components/cloud/alexa_config.py | 53 +++++++++++++------ tests/components/cloud/test_alexa_config.py | 40 +++++++++++--- 2 files changed, 70 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/cloud/alexa_config.py b/homeassistant/components/cloud/alexa_config.py index 6645c4f9f60..bfdd2e560a5 100644 --- a/homeassistant/components/cloud/alexa_config.py +++ b/homeassistant/components/cloud/alexa_config.py @@ -22,7 +22,9 @@ from homeassistant.components.alexa import ( ) from homeassistant.components.binary_sensor import BinarySensorDeviceClass from homeassistant.components.homeassistant.exposed_entities import ( + async_expose_entity, async_get_assistant_settings, + async_get_entity_settings, async_listen_entity_updates, async_should_expose, ) @@ -198,35 +200,52 @@ class CloudAlexaConfig(alexa_config.AbstractConfig): # Don't migrate if there's a YAML config return - entity_registry = er.async_get(self.hass) - - for entity_id, entry in entity_registry.entities.items(): - if CLOUD_ALEXA in entry.options: - continue - options = {"should_expose": self._should_expose_legacy(entity_id)} - entity_registry.async_update_entity_options(entity_id, CLOUD_ALEXA, options) + for state in self.hass.states.async_all(): + with suppress(HomeAssistantError): + entity_settings = async_get_entity_settings(self.hass, state.entity_id) + if CLOUD_ALEXA in entity_settings: + continue + async_expose_entity( + self.hass, + CLOUD_ALEXA, + state.entity_id, + self._should_expose_legacy(state.entity_id), + ) + for entity_id in self._prefs.alexa_entity_configs: + with suppress(HomeAssistantError): + entity_settings = async_get_entity_settings(self.hass, entity_id) + if CLOUD_ALEXA in entity_settings: + continue + async_expose_entity( + self.hass, + CLOUD_ALEXA, + entity_id, + self._should_expose_legacy(entity_id), + ) async def async_initialize(self): """Initialize the Alexa config.""" await super().async_initialize() - if self._prefs.alexa_settings_version != ALEXA_SETTINGS_VERSION: - if self._prefs.alexa_settings_version < 2: - self._migrate_alexa_entity_settings_v1() - await self._prefs.async_update( - alexa_settings_version=ALEXA_SETTINGS_VERSION + async def on_hass_started(hass): + if self._prefs.alexa_settings_version != ALEXA_SETTINGS_VERSION: + if self._prefs.alexa_settings_version < 2: + self._migrate_alexa_entity_settings_v1() + await self._prefs.async_update( + alexa_settings_version=ALEXA_SETTINGS_VERSION + ) + async_listen_entity_updates( + self.hass, CLOUD_ALEXA, self._async_exposed_entities_updated ) - async def hass_started(hass): + async def on_hass_start(hass): if self.enabled and ALEXA_DOMAIN not in self.hass.config.components: await async_setup_component(self.hass, ALEXA_DOMAIN, {}) - start.async_at_start(self.hass, hass_started) + start.async_at_start(self.hass, on_hass_start) + start.async_at_started(self.hass, on_hass_started) self._prefs.async_listen_updates(self._async_prefs_updated) - async_listen_entity_updates( - self.hass, CLOUD_ALEXA, self._async_exposed_entities_updated - ) self.hass.bus.async_listen( er.EVENT_ENTITY_REGISTRY_UPDATED, self._handle_entity_registry_updated, diff --git a/tests/components/cloud/test_alexa_config.py b/tests/components/cloud/test_alexa_config.py index 4d1f4d457df..2a4be7e1645 100644 --- a/tests/components/cloud/test_alexa_config.py +++ b/tests/components/cloud/test_alexa_config.py @@ -18,9 +18,12 @@ from homeassistant.components.homeassistant.exposed_entities import ( async_expose_entity, async_get_entity_settings, ) -from homeassistant.const import EntityCategory -from homeassistant.core import HomeAssistant -from homeassistant.exceptions import HomeAssistantError +from homeassistant.const import ( + EVENT_HOMEASSISTANT_START, + EVENT_HOMEASSISTANT_STARTED, + EntityCategory, +) +from homeassistant.core import CoreState, HomeAssistant from homeassistant.helpers import entity_registry as er from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.setup import async_setup_component @@ -368,6 +371,8 @@ async def test_alexa_update_expose_trigger_sync( hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) await conf.async_initialize() + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() with patch_sync_helper() as (to_update, to_remove): expose_entity(hass, light_entry.entity_id, True) @@ -544,8 +549,10 @@ async def test_alexa_config_migrate_expose_entity_prefs( entity_registry: er.EntityRegistry, ) -> None: """Test migrating Alexa entity config.""" + hass.state = CoreState.starting assert await async_setup_component(hass, "homeassistant", {}) + hass.states.async_set("light.state_only", "on") entity_exposed = entity_registry.async_get_or_create( "light", "test", @@ -593,6 +600,9 @@ async def test_alexa_config_migrate_expose_entity_prefs( cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS]["light.unknown"] = { PREF_SHOULD_EXPOSE: True } + cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS]["light.state_only"] = { + PREF_SHOULD_EXPOSE: False + } cloud_prefs._prefs[PREF_ALEXA_ENTITY_CONFIGS][entity_exposed.entity_id] = { PREF_SHOULD_EXPOSE: True } @@ -603,12 +613,20 @@ async def test_alexa_config_migrate_expose_entity_prefs( hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) await conf.async_initialize() + hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + await hass.async_block_till_done() + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() - with pytest.raises(HomeAssistantError): - async_get_entity_settings(hass, "light.unknown") - assert async_get_entity_settings(hass, entity_migrated.entity_id) == { + assert async_get_entity_settings(hass, "light.unknown") == { + "cloud.alexa": {"should_expose": True} + } + assert async_get_entity_settings(hass, "light.state_only") == { "cloud.alexa": {"should_expose": False} } + assert async_get_entity_settings(hass, entity_exposed.entity_id) == { + "cloud.alexa": {"should_expose": True} + } assert async_get_entity_settings(hass, entity_migrated.entity_id) == { "cloud.alexa": {"should_expose": False} } @@ -630,6 +648,7 @@ async def test_alexa_config_migrate_expose_entity_prefs_default_none( entity_registry: er.EntityRegistry, ) -> None: """Test migrating Alexa entity config.""" + hass.state = CoreState.starting assert await async_setup_component(hass, "homeassistant", {}) entity_default = entity_registry.async_get_or_create( @@ -650,6 +669,10 @@ async def test_alexa_config_migrate_expose_entity_prefs_default_none( hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) await conf.async_initialize() + hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + await hass.async_block_till_done() + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() assert async_get_entity_settings(hass, entity_default.entity_id) == { "cloud.alexa": {"should_expose": True} @@ -663,6 +686,7 @@ async def test_alexa_config_migrate_expose_entity_prefs_default( entity_registry: er.EntityRegistry, ) -> None: """Test migrating Alexa entity config.""" + hass.state = CoreState.starting assert await async_setup_component(hass, "homeassistant", {}) @@ -728,6 +752,10 @@ async def test_alexa_config_migrate_expose_entity_prefs_default( hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) await conf.async_initialize() + hass.bus.async_fire(EVENT_HOMEASSISTANT_START) + await hass.async_block_till_done() + hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await hass.async_block_till_done() assert async_get_entity_settings(hass, binary_sensor_supported.entity_id) == { "cloud.alexa": {"should_expose": True}