diff --git a/homeassistant/components/alexa/logbook.py b/homeassistant/components/alexa/logbook.py index efc188a7f8b..153c7b7d61a 100644 --- a/homeassistant/components/alexa/logbook.py +++ b/homeassistant/components/alexa/logbook.py @@ -17,10 +17,10 @@ def async_describe_events(hass, async_describe_event): if entity_id: state = hass.states.get(entity_id) name = state.name if state else entity_id - message = f"send command {data['request']['namespace']}/{data['request']['name']} for {name}" + message = f"sent command {data['request']['namespace']}/{data['request']['name']} for {name}" else: message = ( - f"send command {data['request']['namespace']}/{data['request']['name']}" + f"sent command {data['request']['namespace']}/{data['request']['name']}" ) return {"name": "Amazon Alexa", "message": message, "entity_id": entity_id} diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index 62ca1b15a71..41f62c32c39 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -5,10 +5,12 @@ import logging from hass_nabucasa import Cloud, cloud_api from hass_nabucasa.google_report_state import ErrorResponse +from homeassistant.components.google_assistant.const import DOMAIN as GOOGLE_DOMAIN from homeassistant.components.google_assistant.helpers import AbstractConfig from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_OK from homeassistant.core import CoreState, split_entity_id from homeassistant.helpers import entity_registry +from homeassistant.setup import async_setup_component from .const import ( CONF_ENTITY_CONFIG, @@ -84,6 +86,9 @@ class CloudGoogleConfig(AbstractConfig): """Perform async initialization of config.""" await super().async_initialize() + if self.enabled and GOOGLE_DOMAIN not in self.hass.config.components: + await async_setup_component(self.hass, GOOGLE_DOMAIN, {}) + # Remove old/wrong user agent ids remove_agent_user_ids = [] for agent_user_id in self._store.agent_user_ids: @@ -164,6 +169,9 @@ class CloudGoogleConfig(AbstractConfig): async def _async_prefs_updated(self, prefs): """Handle updated preferences.""" + if self.enabled and GOOGLE_DOMAIN not in self.hass.config.components: + await async_setup_component(self.hass, GOOGLE_DOMAIN, {}) + if self.should_report_state != self.is_reporting_state: if self.should_report_state: self.async_enable_report_state() diff --git a/homeassistant/components/google_assistant/__init__.py b/homeassistant/components/google_assistant/__init__.py index 7793ed4d659..13516783233 100644 --- a/homeassistant/components/google_assistant/__init__.py +++ b/homeassistant/components/google_assistant/__init__.py @@ -86,12 +86,17 @@ GOOGLE_ASSISTANT_SCHEMA = vol.All( _check_report_state, ) -CONFIG_SCHEMA = vol.Schema({DOMAIN: GOOGLE_ASSISTANT_SCHEMA}, extra=vol.ALLOW_EXTRA) +CONFIG_SCHEMA = vol.Schema( + {vol.Optional(DOMAIN): GOOGLE_ASSISTANT_SCHEMA}, extra=vol.ALLOW_EXTRA +) async def async_setup(hass: HomeAssistant, yaml_config: dict[str, Any]): """Activate Google Actions component.""" - config = yaml_config.get(DOMAIN, {}) + if DOMAIN not in yaml_config: + return True + + config = yaml_config[DOMAIN] google_config = GoogleConfig(hass, config) await google_config.async_initialize() diff --git a/homeassistant/components/google_assistant/logbook.py b/homeassistant/components/google_assistant/logbook.py new file mode 100644 index 00000000000..ef2bccd2c65 --- /dev/null +++ b/homeassistant/components/google_assistant/logbook.py @@ -0,0 +1,29 @@ +"""Describe logbook events.""" +from homeassistant.const import ATTR_ENTITY_ID +from homeassistant.core import callback + +from .const import DOMAIN, EVENT_COMMAND_RECEIVED + +COMMON_COMMAND_PREFIX = "action.devices.commands." + + +@callback +def async_describe_events(hass, async_describe_event): + """Describe logbook events.""" + + @callback + def async_describe_logbook_event(event): + """Describe a logbook event.""" + entity_id = event.data[ATTR_ENTITY_ID] + state = hass.states.get(entity_id) + name = state.name if state else entity_id + + command = event.data["execution"]["command"] + if command.startswith(COMMON_COMMAND_PREFIX): + command = command[len(COMMON_COMMAND_PREFIX) :] + + message = f"sent command {command} for {name} (via {event.data['source']})" + + return {"name": "Google Assistant", "message": message, "entity_id": entity_id} + + async_describe_event(DOMAIN, EVENT_COMMAND_RECEIVED, async_describe_logbook_event) diff --git a/tests/components/alexa/test_init.py b/tests/components/alexa/test_init.py index c0972351cce..eac4b32e5ba 100644 --- a/tests/components/alexa/test_init.py +++ b/tests/components/alexa/test_init.py @@ -51,19 +51,19 @@ async def test_humanify_alexa_event(hass): event1, event2, event3 = results assert event1["name"] == "Amazon Alexa" - assert event1["message"] == "send command Alexa.Discovery/Discover" + assert event1["message"] == "sent command Alexa.Discovery/Discover" assert event1["entity_id"] is None assert event2["name"] == "Amazon Alexa" assert ( event2["message"] - == "send command Alexa.PowerController/TurnOn for Kitchen Light" + == "sent command Alexa.PowerController/TurnOn for Kitchen Light" ) assert event2["entity_id"] == "light.kitchen" assert event3["name"] == "Amazon Alexa" assert ( event3["message"] - == "send command Alexa.PowerController/TurnOn for light.non_existing" + == "sent command Alexa.PowerController/TurnOn for light.non_existing" ) assert event3["entity_id"] == "light.non_existing" diff --git a/tests/components/cloud/test_google_config.py b/tests/components/cloud/test_google_config.py index 5f29a41c6e0..bc430347e08 100644 --- a/tests/components/cloud/test_google_config.py +++ b/tests/components/cloud/test_google_config.py @@ -225,3 +225,19 @@ def test_enabled_requires_valid_sub(hass, mock_expired_cloud_login, cloud_prefs) ) assert not config.enabled + + +async def test_setup_integration(hass, mock_conf, cloud_prefs): + """Test that we set up the integration if used.""" + mock_conf._cloud.subscription_expired = False + + assert "google_assistant" not in hass.config.components + + await mock_conf.async_initialize() + assert "google_assistant" in hass.config.components + + hass.config.components.remove("google_assistant") + + await cloud_prefs.async_update() + await hass.async_block_till_done() + assert "google_assistant" in hass.config.components diff --git a/tests/components/google_assistant/test_logbook.py b/tests/components/google_assistant/test_logbook.py new file mode 100644 index 00000000000..4f996ba038f --- /dev/null +++ b/tests/components/google_assistant/test_logbook.py @@ -0,0 +1,72 @@ +"""The tests for Google Assistant logbook.""" +from homeassistant.components import logbook +from homeassistant.components.google_assistant.const import ( + DOMAIN, + EVENT_COMMAND_RECEIVED, + SOURCE_CLOUD, + SOURCE_LOCAL, +) +from homeassistant.const import ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME +from homeassistant.setup import async_setup_component + +from tests.components.logbook.test_init import MockLazyEventPartialState + + +async def test_humanify_command_received(hass): + """Test humanifying command event.""" + hass.config.components.add("recorder") + hass.config.components.add("frontend") + hass.config.components.add("google_assistant") + assert await async_setup_component(hass, "logbook", {}) + entity_attr_cache = logbook.EntityAttributeCache(hass) + + hass.states.async_set( + "light.kitchen", "on", {ATTR_FRIENDLY_NAME: "The Kitchen Lights"} + ) + + events = list( + logbook.humanify( + hass, + [ + MockLazyEventPartialState( + EVENT_COMMAND_RECEIVED, + { + "request_id": "abcd", + ATTR_ENTITY_ID: "light.kitchen", + "execution": { + "command": "action.devices.commands.OnOff", + "params": {"on": True}, + }, + "source": SOURCE_LOCAL, + }, + ), + MockLazyEventPartialState( + EVENT_COMMAND_RECEIVED, + { + "request_id": "abcd", + ATTR_ENTITY_ID: "light.non_existing", + "execution": { + "command": "action.devices.commands.OnOff", + "params": {"on": False}, + }, + "source": SOURCE_CLOUD, + }, + ), + ], + entity_attr_cache, + {}, + ) + ) + + assert len(events) == 2 + event1, event2 = events + + assert event1["name"] == "Google Assistant" + assert event1["domain"] == DOMAIN + assert event1["message"] == "sent command OnOff for The Kitchen Lights (via local)" + assert event1["entity_id"] == "light.kitchen" + + assert event2["name"] == "Google Assistant" + assert event2["domain"] == DOMAIN + assert event2["message"] == "sent command OnOff for light.non_existing (via cloud)" + assert event2["entity_id"] == "light.non_existing"