diff --git a/homeassistant/components/cloud/alexa_config.py b/homeassistant/components/cloud/alexa_config.py index 43ef0ee62da..c14b4d7a4e7 100644 --- a/homeassistant/components/cloud/alexa_config.py +++ b/homeassistant/components/cloud/alexa_config.py @@ -15,9 +15,14 @@ from homeassistant.components.alexa import ( errors as alexa_errors, state_report as alexa_state_report, ) -from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_BAD_REQUEST +from homeassistant.const import ( + CLOUD_NEVER_EXPOSED_ENTITIES, + ENTITY_CATEGORY_CONFIG, + ENTITY_CATEGORY_DIAGNOSTIC, + HTTP_BAD_REQUEST, +) from homeassistant.core import HomeAssistant, callback, split_entity_id -from homeassistant.helpers import entity_registry, start +from homeassistant.helpers import entity_registry as er, start from homeassistant.helpers.event import async_call_later from homeassistant.setup import async_setup_component from homeassistant.util.dt import utcnow @@ -110,7 +115,7 @@ class AlexaConfig(alexa_config.AbstractConfig): self._prefs.async_listen_updates(self._async_prefs_updated) self.hass.bus.async_listen( - entity_registry.EVENT_ENTITY_REGISTRY_UPDATED, + er.EVENT_ENTITY_REGISTRY_UPDATED, self._handle_entity_registry_updated, ) @@ -128,13 +133,23 @@ class AlexaConfig(alexa_config.AbstractConfig): if entity_expose is not None: return entity_expose + entity_registry = er.async_get(self.hass) + registry_entry = entity_registry.async_get(entity_id) + if registry_entry: + auxiliary_entity = registry_entry.entity_category in ( + ENTITY_CATEGORY_CONFIG, + ENTITY_CATEGORY_DIAGNOSTIC, + ) + else: + auxiliary_entity = False + default_expose = self._prefs.alexa_default_expose # Backwards compat if default_expose is None: - return True + return not auxiliary_entity - return split_entity_id(entity_id)[0] in default_expose + return not auxiliary_entity and split_entity_id(entity_id)[0] in default_expose @callback def async_invalidate_access_token(self): @@ -340,7 +355,7 @@ class AlexaConfig(alexa_config.AbstractConfig): elif action == "remove": to_remove.append(entity_id) elif action == "update" and bool( - set(event.data["changes"]) & entity_registry.ENTITY_DESCRIBING_ATTRIBUTES + set(event.data["changes"]) & er.ENTITY_DESCRIBING_ATTRIBUTES ): to_update.append(entity_id) if "old_entity_id" in event.data: diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index f1783771f2f..bfb6510fcda 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -7,9 +7,14 @@ 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.const import ( + CLOUD_NEVER_EXPOSED_ENTITIES, + ENTITY_CATEGORY_CONFIG, + ENTITY_CATEGORY_DIAGNOSTIC, + HTTP_OK, +) from homeassistant.core import CoreState, split_entity_id -from homeassistant.helpers import entity_registry, start +from homeassistant.helpers import entity_registry as er, start from homeassistant.setup import async_setup_component from .const import ( @@ -104,7 +109,7 @@ class CloudGoogleConfig(AbstractConfig): self._prefs.async_listen_updates(self._async_prefs_updated) self.hass.bus.async_listen( - entity_registry.EVENT_ENTITY_REGISTRY_UPDATED, + er.EVENT_ENTITY_REGISTRY_UPDATED, self._handle_entity_registry_updated, ) @@ -126,13 +131,23 @@ class CloudGoogleConfig(AbstractConfig): if entity_expose is not None: return entity_expose + entity_registry = er.async_get(self.hass) + registry_entry = entity_registry.async_get(entity_id) + if registry_entry: + auxiliary_entity = registry_entry.entity_category in ( + ENTITY_CATEGORY_CONFIG, + ENTITY_CATEGORY_DIAGNOSTIC, + ) + else: + auxiliary_entity = False + default_expose = self._prefs.google_default_expose # Backwards compat if default_expose is None: - return True + return not auxiliary_entity - return split_entity_id(entity_id)[0] in default_expose + return not auxiliary_entity and split_entity_id(entity_id)[0] in default_expose @property def agent_user_id(self): @@ -215,7 +230,7 @@ class CloudGoogleConfig(AbstractConfig): # Only consider entity registry updates if info relevant for Google has changed if event.data["action"] == "update" and not bool( - set(event.data["changes"]) & entity_registry.ENTITY_DESCRIBING_ATTRIBUTES + set(event.data["changes"]) & er.ENTITY_DESCRIBING_ATTRIBUTES ): return diff --git a/tests/components/cloud/test_alexa_config.py b/tests/components/cloud/test_alexa_config.py index 60ef992dafb..9b0075db09d 100644 --- a/tests/components/cloud/test_alexa_config.py +++ b/tests/components/cloud/test_alexa_config.py @@ -8,7 +8,7 @@ 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 -from tests.common import async_fire_time_changed +from tests.common import async_fire_time_changed, mock_registry @pytest.fixture() @@ -19,6 +19,23 @@ def cloud_stub(): async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs, cloud_stub): """Test Alexa config should expose using prefs.""" + entity_registry = mock_registry(hass) + + entity_entry1 = entity_registry.async_get_or_create( + "switch", + "test", + "switch_config_id", + suggested_object_id="config_switch", + entity_category="config", + ) + entity_entry2 = entity_registry.async_get_or_create( + "switch", + "test", + "switch_diagnostic_id", + suggested_object_id="diagnostic_switch", + entity_category="diagnostic", + ) + entity_conf = {"should_expose": False} await cloud_prefs.async_update( alexa_entity_configs={"light.kitchen": entity_conf}, @@ -31,11 +48,20 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs, cloud_stub): await conf.async_initialize() assert not conf.should_expose("light.kitchen") + assert not conf.should_expose(entity_entry1.entity_id) + assert not conf.should_expose(entity_entry2.entity_id) + entity_conf["should_expose"] = True assert conf.should_expose("light.kitchen") + # config and diagnostic entities should not be exposed + assert not conf.should_expose(entity_entry1.entity_id) + assert not conf.should_expose(entity_entry2.entity_id) entity_conf["should_expose"] = None assert conf.should_expose("light.kitchen") + # config and diagnostic entities should not be exposed + assert not conf.should_expose(entity_entry1.entity_id) + assert not conf.should_expose(entity_entry2.entity_id) assert "alexa" not in hass.config.components await cloud_prefs.async_update( diff --git a/tests/components/cloud/test_google_config.py b/tests/components/cloud/test_google_config.py index a80ccaccd6c..61d93b5bc85 100644 --- a/tests/components/cloud/test_google_config.py +++ b/tests/components/cloud/test_google_config.py @@ -11,7 +11,7 @@ from homeassistant.core import CoreState, State from homeassistant.helpers.entity_registry import EVENT_ENTITY_REGISTRY_UPDATED from homeassistant.util.dt import utcnow -from tests.common import async_fire_time_changed +from tests.common import async_fire_time_changed, mock_registry @pytest.fixture @@ -215,8 +215,25 @@ async def test_sync_google_on_home_assistant_start(hass, mock_cloud_login, cloud assert len(mock_sync.mock_calls) == 1 -async def test_google_config_expose_entity_prefs(mock_conf, cloud_prefs): +async def test_google_config_expose_entity_prefs(hass, mock_conf, cloud_prefs): """Test Google config should expose using prefs.""" + entity_registry = mock_registry(hass) + + entity_entry1 = entity_registry.async_get_or_create( + "switch", + "test", + "switch_config_id", + suggested_object_id="config_switch", + entity_category="config", + ) + entity_entry2 = entity_registry.async_get_or_create( + "switch", + "test", + "switch_diagnostic_id", + suggested_object_id="diagnostic_switch", + entity_category="diagnostic", + ) + entity_conf = {"should_expose": False} await cloud_prefs.async_update( google_entity_configs={"light.kitchen": entity_conf}, @@ -224,13 +241,24 @@ async def test_google_config_expose_entity_prefs(mock_conf, cloud_prefs): ) state = State("light.kitchen", "on") + state_config = State(entity_entry1.entity_id, "on") + state_diagnostic = State(entity_entry2.entity_id, "on") assert not mock_conf.should_expose(state) + assert not mock_conf.should_expose(state_config) + assert not mock_conf.should_expose(state_diagnostic) + entity_conf["should_expose"] = True assert mock_conf.should_expose(state) + # config and diagnostic entities should not be exposed + assert not mock_conf.should_expose(state_config) + assert not mock_conf.should_expose(state_diagnostic) entity_conf["should_expose"] = None assert mock_conf.should_expose(state) + # config and diagnostic entities should not be exposed + assert not mock_conf.should_expose(state_config) + assert not mock_conf.should_expose(state_diagnostic) await cloud_prefs.async_update( google_default_expose=["sensor"],