From ba93a033a55fc26a6d9a45ccc18183e08bd82211 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 13 Apr 2021 09:31:41 -0700 Subject: [PATCH] Cloud to set up Alexa conditionally (#49136) --- .../components/cloud/alexa_config.py | 10 ++++++ homeassistant/components/cloud/client.py | 1 + homeassistant/components/cloud/manifest.json | 4 +-- tests/components/cloud/test_alexa_config.py | 32 ++++++++++++++----- 4 files changed, 37 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/cloud/alexa_config.py b/homeassistant/components/cloud/alexa_config.py index 138b2db0b8c..393bfdfc2cd 100644 --- a/homeassistant/components/cloud/alexa_config.py +++ b/homeassistant/components/cloud/alexa_config.py @@ -9,6 +9,7 @@ import async_timeout from hass_nabucasa import Cloud, cloud_api from homeassistant.components.alexa import ( + DOMAIN as ALEXA_DOMAIN, config as alexa_config, entities as alexa_entities, errors as alexa_errors, @@ -18,6 +19,7 @@ from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_BAD_REQUEST from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers import entity_registry from homeassistant.helpers.event import async_call_later +from homeassistant.setup import async_setup_component from homeassistant.util.dt import utcnow from .const import CONF_ENTITY_CONFIG, CONF_FILTER, PREF_SHOULD_EXPOSE, RequireRelink @@ -103,6 +105,11 @@ class AlexaConfig(alexa_config.AbstractConfig): """Return an identifier for the user that represents this config.""" return self._cloud_user + async def async_initialize(self): + """Initialize the Alexa config.""" + if self.enabled and ALEXA_DOMAIN not in self.hass.config.components: + await async_setup_component(self.hass, ALEXA_DOMAIN, {}) + def should_expose(self, entity_id): """If an entity should be exposed.""" if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES: @@ -160,6 +167,9 @@ class AlexaConfig(alexa_config.AbstractConfig): async def _async_prefs_updated(self, prefs): """Handle updated preferences.""" + if ALEXA_DOMAIN not in self.hass.config.components and self.enabled: + await async_setup_component(self.hass, ALEXA_DOMAIN, {}) + if self.should_report_state != self.is_reporting_states: if self.should_report_state: await self.async_enable_proactive_mode() diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index f451a4faddb..6c09169ef34 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -90,6 +90,7 @@ class CloudClient(Interface): self._alexa_config = alexa_config.AlexaConfig( self._hass, self.alexa_user_config, cloud_user, self._prefs, self.cloud ) + await self._alexa_config.async_initialize() return self._alexa_config diff --git a/homeassistant/components/cloud/manifest.json b/homeassistant/components/cloud/manifest.json index 08bccf5eb65..e51451be397 100644 --- a/homeassistant/components/cloud/manifest.json +++ b/homeassistant/components/cloud/manifest.json @@ -3,7 +3,7 @@ "name": "Home Assistant Cloud", "documentation": "https://www.home-assistant.io/integrations/cloud", "requirements": ["hass-nabucasa==0.43.0"], - "dependencies": ["http", "webhook", "alexa"], - "after_dependencies": ["google_assistant"], + "dependencies": ["http", "webhook"], + "after_dependencies": ["google_assistant", "alexa"], "codeowners": ["@home-assistant/cloud"] } diff --git a/tests/components/cloud/test_alexa_config.py b/tests/components/cloud/test_alexa_config.py index 8e104f641b2..83c2a5aa2d1 100644 --- a/tests/components/cloud/test_alexa_config.py +++ b/tests/components/cloud/test_alexa_config.py @@ -2,6 +2,8 @@ import contextlib from unittest.mock import AsyncMock, Mock, patch +import pytest + from homeassistant.components.cloud import ALEXA_SCHEMA, alexa_config from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED from homeassistant.util.dt import utcnow @@ -9,15 +11,22 @@ from homeassistant.util.dt import utcnow from tests.common import async_fire_time_changed -async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs): +@pytest.fixture() +def cloud_stub(): + """Stub the cloud.""" + return Mock(is_logged_in=True, subscription_expired=False) + + +async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs, cloud_stub): """Test Alexa config should expose using prefs.""" entity_conf = {"should_expose": False} await cloud_prefs.async_update( alexa_entity_configs={"light.kitchen": entity_conf}, alexa_default_expose=["light"], + alexa_enabled=True, ) conf = alexa_config.AlexaConfig( - hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) assert not conf.should_expose("light.kitchen") @@ -27,16 +36,19 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs): entity_conf["should_expose"] = None assert conf.should_expose("light.kitchen") + assert "alexa" not in hass.config.components await cloud_prefs.async_update( alexa_default_expose=["sensor"], ) + await hass.async_block_till_done() + assert "alexa" in hass.config.components assert not conf.should_expose("light.kitchen") -async def test_alexa_config_report_state(hass, cloud_prefs): +async def test_alexa_config_report_state(hass, cloud_prefs, cloud_stub): """Test Alexa config should expose using prefs.""" conf = alexa_config.AlexaConfig( - hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub ) assert cloud_prefs.alexa_report_state is False @@ -117,9 +129,11 @@ def patch_sync_helper(): yield to_update, to_remove -async def test_alexa_update_expose_trigger_sync(hass, cloud_prefs): +async def test_alexa_update_expose_trigger_sync(hass, cloud_prefs, cloud_stub): """Test Alexa config responds to updating exposed entities.""" - alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None) + alexa_config.AlexaConfig( + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub + ) with patch_sync_helper() as (to_update, to_remove): await cloud_prefs.async_update_alexa_entity_config( @@ -202,9 +216,11 @@ async def test_alexa_entity_registry_sync(hass, mock_cloud_login, cloud_prefs): assert to_remove == [] -async def test_alexa_update_report_state(hass, cloud_prefs): +async def test_alexa_update_report_state(hass, cloud_prefs, cloud_stub): """Test Alexa config responds to reporting state.""" - alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None) + alexa_config.AlexaConfig( + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, cloud_stub + ) with patch( "homeassistant.components.cloud.alexa_config.AlexaConfig.async_sync_entities",