Ensure selected entity is pre-selected in homekit options flow (#63628)
* Ensure selected entity is pre-selected in homekit options flow - We recently adjusted the flow to exclude entities that had been deleted from breaking the UI validation. We need to include single entities in the set of all supported entities since accessory mode has no domain filter * tweak * Additional fixes * small tweak to speed up building the set * merged fixed version for test branch
This commit is contained in:
parent
0b67d7fb28
commit
9dd09f66e2
2 changed files with 65 additions and 13 deletions
|
@ -447,15 +447,25 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||||
return await self.async_step_advanced()
|
return await self.async_step_advanced()
|
||||||
|
|
||||||
entity_filter = self.hk_options.get(CONF_FILTER, {})
|
entity_filter = self.hk_options.get(CONF_FILTER, {})
|
||||||
|
entities = entity_filter.get(CONF_INCLUDE_ENTITIES, [])
|
||||||
|
|
||||||
all_supported_entities = _async_get_matching_entities(
|
all_supported_entities = _async_get_matching_entities(
|
||||||
self.hass,
|
self.hass,
|
||||||
domains=self.hk_options[CONF_DOMAINS],
|
domains=self.hk_options[CONF_DOMAINS],
|
||||||
)
|
)
|
||||||
|
|
||||||
data_schema = {}
|
data_schema = {}
|
||||||
|
# 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
|
entity_schema = vol.In
|
||||||
entities = entity_filter.get(CONF_INCLUDE_ENTITIES, [])
|
entities_schema_required = vol.Required
|
||||||
if self.hk_options[CONF_HOMEKIT_MODE] != HOMEKIT_MODE_ACCESSORY:
|
else:
|
||||||
|
# Bridge mode
|
||||||
|
entities_schema_required = vol.Optional
|
||||||
include_exclude_mode = MODE_INCLUDE
|
include_exclude_mode = MODE_INCLUDE
|
||||||
if not entities:
|
if not entities:
|
||||||
include_exclude_mode = MODE_EXCLUDE
|
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.Required(CONF_INCLUDE_EXCLUDE_MODE, default=include_exclude_mode)
|
||||||
] = vol.In(INCLUDE_EXCLUDE_MODES)
|
] = vol.In(INCLUDE_EXCLUDE_MODES)
|
||||||
entity_schema = cv.multi_select
|
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[
|
data_schema[
|
||||||
vol.Optional(CONF_ENTITIES, default=valid_entities)
|
entities_schema_required(CONF_ENTITIES, default=default_value)
|
||||||
] = entity_schema(all_supported_entities)
|
] = entity_schema(all_supported_entities)
|
||||||
|
|
||||||
return self.async_show_form(
|
return self.async_show_form(
|
||||||
|
|
|
@ -7,6 +7,8 @@ from homeassistant.config_entries import SOURCE_IGNORE, SOURCE_IMPORT
|
||||||
from homeassistant.const import CONF_NAME, CONF_PORT
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||||
from homeassistant.setup import async_setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from .util import PATH_HOMEKIT, async_init_entry
|
||||||
|
|
||||||
from tests.common import MockConfigEntry
|
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
|
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."""
|
"""Test config flow options in include mode with a single accessory."""
|
||||||
|
|
||||||
config_entry = _mock_config_entry_with_options_populated()
|
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.tv", "off")
|
||||||
hass.states.async_set("media_player.sonos", "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["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result2["step_id"] == "include_exclude"
|
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(
|
result3 = await hass.config_entries.options.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue