diff --git a/homeassistant/components/homekit/config_flow.py b/homeassistant/components/homekit/config_flow.py index 8d2f17a3878..445b20ac548 100644 --- a/homeassistant/components/homekit/config_flow.py +++ b/homeassistant/components/homekit/config_flow.py @@ -447,15 +447,25 @@ class OptionsFlowHandler(config_entries.OptionsFlow): return await self.async_step_advanced() 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=self.hk_options[CONF_DOMAINS], ) - data_schema = {} - entity_schema = vol.In - entities = entity_filter.get(CONF_INCLUDE_ENTITIES, []) - if self.hk_options[CONF_HOMEKIT_MODE] != HOMEKIT_MODE_ACCESSORY: + # Strip out entities that no longer exist to prevent error in the UI + valid_entities = [ + entity_id for entity_id in entities if entity_id in all_supported_entities + ] + if self.hk_options[CONF_HOMEKIT_MODE] == HOMEKIT_MODE_ACCESSORY: + # In accessory mode we can only have one + default_value = valid_entities[0] if valid_entities else None + entity_schema = vol.In + entities_schema_required = vol.Required + else: + # Bridge mode + entities_schema_required = vol.Optional include_exclude_mode = MODE_INCLUDE if not entities: include_exclude_mode = MODE_EXCLUDE @@ -464,13 +474,10 @@ class OptionsFlowHandler(config_entries.OptionsFlow): vol.Required(CONF_INCLUDE_EXCLUDE_MODE, default=include_exclude_mode) ] = vol.In(INCLUDE_EXCLUDE_MODES) entity_schema = cv.multi_select + default_value = valid_entities - # Strip out entities that no longer exist to prevent error in the UI - valid_entities = [ - entity_id for entity_id in entities if entity_id in all_supported_entities - ] data_schema[ - vol.Optional(CONF_ENTITIES, default=valid_entities) + entities_schema_required(CONF_ENTITIES, default=default_value) ] = entity_schema(all_supported_entities) return self.async_show_form( diff --git a/tests/components/homekit/test_config_flow.py b/tests/components/homekit/test_config_flow.py index f076d8e00ae..d190dec04b8 100644 --- a/tests/components/homekit/test_config_flow.py +++ b/tests/components/homekit/test_config_flow.py @@ -7,6 +7,8 @@ from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_IMPORT from homeassistant.const import CONF_NAME, CONF_PORT from homeassistant.setup import async_setup_component +from .util import PATH_HOMEKIT, async_init_entry + from tests.common import MockConfigEntry @@ -1065,11 +1067,13 @@ async def test_options_flow_blocked_when_from_yaml(hass, mock_get_source_ip): assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY -async def test_options_flow_include_mode_basic_accessory(hass, mock_get_source_ip): +@patch(f"{PATH_HOMEKIT}.async_port_is_available", return_value=True) +async def test_options_flow_include_mode_basic_accessory( + port_mock, hass, mock_get_source_ip, hk_driver, mock_async_zeroconf +): """Test config flow options in include mode with a single accessory.""" - config_entry = _mock_config_entry_with_options_populated() - config_entry.add_to_hass(hass) + await async_init_entry(hass, config_entry) hass.states.async_set("media_player.tv", "off") hass.states.async_set("media_player.sonos", "off") @@ -1101,7 +1105,48 @@ async def test_options_flow_include_mode_basic_accessory(hass, mock_get_source_i assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM assert result2["step_id"] == "include_exclude" - assert _get_schema_default(result2["data_schema"].schema, "entities") == [] + assert _get_schema_default(result2["data_schema"].schema, "entities") is None + + result3 = await hass.config_entries.options.async_configure( + result2["flow_id"], + user_input={"entities": "media_player.tv"}, + ) + assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert config_entry.options == { + "mode": "accessory", + "filter": { + "exclude_domains": [], + "exclude_entities": [], + "include_domains": [], + "include_entities": ["media_player.tv"], + }, + } + + # Now we check again to make sure the single entity is still + # preselected + + result = await hass.config_entries.options.async_init( + config_entry.entry_id, context={"show_advanced_options": False} + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result["step_id"] == "init" + assert result["data_schema"]({}) == { + "domains": ["media_player"], + "mode": "accessory", + } + + result2 = await hass.config_entries.options.async_configure( + result["flow_id"], + user_input={"domains": ["media_player"], "mode": "accessory"}, + ) + + assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM + assert result2["step_id"] == "include_exclude" + assert ( + _get_schema_default(result2["data_schema"].schema, "entities") + == "media_player.tv" + ) result3 = await hass.config_entries.options.async_configure( result2["flow_id"],