From c9eca4033669133ed8e01135f2b963be062f3acb Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 3 May 2022 11:47:13 -0500 Subject: [PATCH] Allow hidden entities to be selected in homekit include mode (#71250) --- .../components/homekit/config_flow.py | 10 ++++--- tests/components/homekit/test_config_flow.py | 28 +++++++++++-------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/homeassistant/components/homekit/config_flow.py b/homeassistant/components/homekit/config_flow.py index b7a00bc3ade..5f142fdb0fe 100644 --- a/homeassistant/components/homekit/config_flow.py +++ b/homeassistant/components/homekit/config_flow.py @@ -467,7 +467,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): entity_filter = self.hk_options.get(CONF_FILTER, {}) entities = entity_filter.get(CONF_INCLUDE_ENTITIES, []) all_supported_entities = _async_get_matching_entities( - self.hass, domains, include_entity_category=True + self.hass, domains, include_entity_category=True, include_hidden=True ) # In accessory mode we can only have one default_value = next( @@ -508,7 +508,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow): entities = entity_filter.get(CONF_INCLUDE_ENTITIES, []) all_supported_entities = _async_get_matching_entities( - self.hass, domains, include_entity_category=True + self.hass, domains, include_entity_category=True, include_hidden=True ) if not entities: entities = entity_filter.get(CONF_EXCLUDE_ENTITIES, []) @@ -646,12 +646,13 @@ def _exclude_by_entity_registry( ent_reg: entity_registry.EntityRegistry, entity_id: str, include_entity_category: bool, + include_hidden: bool, ) -> bool: """Filter out hidden entities and ones with entity category (unless specified).""" return bool( (entry := ent_reg.async_get(entity_id)) and ( - entry.hidden_by is not None + (not include_hidden and entry.hidden_by is not None) or (not include_entity_category and entry.entity_category is not None) ) ) @@ -661,6 +662,7 @@ def _async_get_matching_entities( hass: HomeAssistant, domains: list[str] | None = None, include_entity_category: bool = False, + include_hidden: bool = False, ) -> dict[str, str]: """Fetch all entities or entities in the given domains.""" ent_reg = entity_registry.async_get(hass) @@ -671,7 +673,7 @@ def _async_get_matching_entities( key=lambda item: item.entity_id, ) if not _exclude_by_entity_registry( - ent_reg, state.entity_id, include_entity_category + ent_reg, state.entity_id, include_entity_category, include_hidden ) } diff --git a/tests/components/homekit/test_config_flow.py b/tests/components/homekit/test_config_flow.py index 42ce6779528..ce0bed0ff52 100644 --- a/tests/components/homekit/test_config_flow.py +++ b/tests/components/homekit/test_config_flow.py @@ -1504,7 +1504,7 @@ async def test_options_flow_exclude_mode_skips_hidden_entities( @patch(f"{PATH_HOMEKIT}.async_port_is_available", return_value=True) -async def test_options_flow_include_mode_skips_hidden_entities( +async def test_options_flow_include_mode_allows_hidden_entities( port_mock, hass, mock_get_source_ip, hk_driver, mock_async_zeroconf, entity_reg ): """Ensure include mode does not offer hidden entities.""" @@ -1558,24 +1558,28 @@ async def test_options_flow_include_mode_skips_hidden_entities( assert _get_schema_default(result2["data_schema"].schema, "entities") == [] # sonos_hidden_switch.entity_id is a hidden entity - # so it should not be selectable since it will always be excluded - with pytest.raises(voluptuous.error.MultipleInvalid): - await hass.config_entries.options.async_configure( - result2["flow_id"], - user_input={"entities": [sonos_hidden_switch.entity_id]}, - ) - - result4 = await hass.config_entries.options.async_configure( + # we allow it to be selected in include mode only + result3 = await hass.config_entries.options.async_configure( result2["flow_id"], - user_input={"entities": ["media_player.tv", "switch.other"]}, + user_input={ + "entities": [ + sonos_hidden_switch.entity_id, + "media_player.tv", + "switch.other", + ] + }, ) - assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY assert config_entry.options == { "mode": "bridge", "filter": { "exclude_domains": [], "exclude_entities": [], "include_domains": [], - "include_entities": ["media_player.tv", "switch.other"], + "include_entities": [ + sonos_hidden_switch.entity_id, + "media_player.tv", + "switch.other", + ], }, }