mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 01:37:08 +00:00
Fix homekit options not being prefilled (#45926)
* Fix homekit options not being prefilled When changing homekit options, the existing ones were not being prefilled on the form. * hide camera screen if no cameras
This commit is contained in:
parent
d1b7d25a5d
commit
374aa3aee1
@ -91,7 +91,8 @@ DEFAULT_DOMAINS = [
|
|||||||
|
|
||||||
DOMAINS_PREFER_ACCESSORY_MODE = ["camera", "media_player"]
|
DOMAINS_PREFER_ACCESSORY_MODE = ["camera", "media_player"]
|
||||||
|
|
||||||
CAMERA_ENTITY_PREFIX = "camera."
|
CAMERA_DOMAIN = "camera"
|
||||||
|
CAMERA_ENTITY_PREFIX = f"{CAMERA_DOMAIN}."
|
||||||
|
|
||||||
_EMPTY_ENTITY_FILTER = {
|
_EMPTY_ENTITY_FILTER = {
|
||||||
CONF_INCLUDE_DOMAINS: [],
|
CONF_INCLUDE_DOMAINS: [],
|
||||||
@ -356,15 +357,26 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
if domain not in domains_with_entities_selected
|
if domain not in domains_with_entities_selected
|
||||||
]
|
]
|
||||||
|
|
||||||
for entity_id in list(self.included_cameras):
|
self.included_cameras = {
|
||||||
if entity_id not in entities:
|
entity_id
|
||||||
self.included_cameras.remove(entity_id)
|
for entity_id in entities
|
||||||
|
if entity_id.startswith(CAMERA_ENTITY_PREFIX)
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
entity_filter[CONF_INCLUDE_DOMAINS] = self.hk_options[CONF_DOMAINS]
|
entity_filter[CONF_INCLUDE_DOMAINS] = self.hk_options[CONF_DOMAINS]
|
||||||
entity_filter[CONF_EXCLUDE_ENTITIES] = entities
|
entity_filter[CONF_EXCLUDE_ENTITIES] = entities
|
||||||
for entity_id in entities:
|
if CAMERA_DOMAIN in entity_filter[CONF_INCLUDE_DOMAINS]:
|
||||||
if entity_id in self.included_cameras:
|
camera_entities = _async_get_matching_entities(
|
||||||
self.included_cameras.remove(entity_id)
|
self.hass,
|
||||||
|
domains=[CAMERA_DOMAIN],
|
||||||
|
)
|
||||||
|
self.included_cameras = {
|
||||||
|
entity_id
|
||||||
|
for entity_id in camera_entities
|
||||||
|
if entity_id not in entities
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
self.included_cameras = set()
|
||||||
|
|
||||||
self.hk_options[CONF_FILTER] = entity_filter
|
self.hk_options[CONF_FILTER] = entity_filter
|
||||||
|
|
||||||
@ -378,11 +390,6 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
self.hass,
|
self.hass,
|
||||||
domains=self.hk_options[CONF_DOMAINS],
|
domains=self.hk_options[CONF_DOMAINS],
|
||||||
)
|
)
|
||||||
self.included_cameras = {
|
|
||||||
entity_id
|
|
||||||
for entity_id in all_supported_entities
|
|
||||||
if entity_id.startswith(CAMERA_ENTITY_PREFIX)
|
|
||||||
}
|
|
||||||
|
|
||||||
data_schema = {}
|
data_schema = {}
|
||||||
entities = entity_filter.get(CONF_INCLUDE_ENTITIES, [])
|
entities = entity_filter.get(CONF_INCLUDE_ENTITIES, [])
|
||||||
@ -416,10 +423,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
self.hk_options.update(user_input)
|
self.hk_options.update(user_input)
|
||||||
return await self.async_step_include_exclude()
|
return await self.async_step_include_exclude()
|
||||||
|
|
||||||
hk_options = dict(self.config_entry.options)
|
self.hk_options = dict(self.config_entry.options)
|
||||||
entity_filter = hk_options.get(CONF_FILTER, {})
|
entity_filter = self.hk_options.get(CONF_FILTER, {})
|
||||||
|
homekit_mode = self.hk_options.get(CONF_HOMEKIT_MODE, DEFAULT_HOMEKIT_MODE)
|
||||||
homekit_mode = hk_options.get(CONF_HOMEKIT_MODE, DEFAULT_HOMEKIT_MODE)
|
|
||||||
domains = entity_filter.get(CONF_INCLUDE_DOMAINS, [])
|
domains = entity_filter.get(CONF_INCLUDE_DOMAINS, [])
|
||||||
include_entities = entity_filter.get(CONF_INCLUDE_ENTITIES)
|
include_entities = entity_filter.get(CONF_INCLUDE_ENTITIES)
|
||||||
if include_entities:
|
if include_entities:
|
||||||
|
@ -492,6 +492,18 @@ async def test_options_flow_include_mode_with_cameras(hass):
|
|||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
|
assert result["data_schema"]({}) == {
|
||||||
|
"domains": ["fan", "vacuum", "climate", "camera"],
|
||||||
|
"mode": "bridge",
|
||||||
|
}
|
||||||
|
schema = result["data_schema"].schema
|
||||||
|
assert _get_schema_default(schema, "domains") == [
|
||||||
|
"fan",
|
||||||
|
"vacuum",
|
||||||
|
"climate",
|
||||||
|
"camera",
|
||||||
|
]
|
||||||
|
assert _get_schema_default(schema, "mode") == "bridge"
|
||||||
|
|
||||||
result = await hass.config_entries.options.async_configure(
|
result = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -500,6 +512,16 @@ async def test_options_flow_include_mode_with_cameras(hass):
|
|||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "include_exclude"
|
assert result["step_id"] == "include_exclude"
|
||||||
|
assert result["data_schema"]({}) == {
|
||||||
|
"entities": ["camera.native_h264", "camera.transcode_h264"],
|
||||||
|
"include_exclude_mode": "include",
|
||||||
|
}
|
||||||
|
schema = result["data_schema"].schema
|
||||||
|
assert _get_schema_default(schema, "entities") == [
|
||||||
|
"camera.native_h264",
|
||||||
|
"camera.transcode_h264",
|
||||||
|
]
|
||||||
|
assert _get_schema_default(schema, "include_exclude_mode") == "include"
|
||||||
|
|
||||||
result2 = await hass.config_entries.options.async_configure(
|
result2 = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -510,6 +532,9 @@ async def test_options_flow_include_mode_with_cameras(hass):
|
|||||||
)
|
)
|
||||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result2["step_id"] == "cameras"
|
assert result2["step_id"] == "cameras"
|
||||||
|
assert result2["data_schema"]({}) == {"camera_copy": ["camera.native_h264"]}
|
||||||
|
schema = result2["data_schema"].schema
|
||||||
|
assert _get_schema_default(schema, "camera_copy") == ["camera.native_h264"]
|
||||||
|
|
||||||
result3 = await hass.config_entries.options.async_configure(
|
result3 = await hass.config_entries.options.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
@ -519,14 +544,14 @@ async def test_options_flow_include_mode_with_cameras(hass):
|
|||||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||||
assert config_entry.options == {
|
assert config_entry.options == {
|
||||||
"auto_start": True,
|
"auto_start": True,
|
||||||
"mode": "bridge",
|
"entity_config": {"camera.native_h264": {}},
|
||||||
"filter": {
|
"filter": {
|
||||||
"exclude_domains": [],
|
"exclude_domains": [],
|
||||||
"exclude_entities": ["climate.old", "camera.excluded"],
|
"exclude_entities": ["climate.old", "camera.excluded"],
|
||||||
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
||||||
"include_entities": [],
|
"include_entities": [],
|
||||||
},
|
},
|
||||||
"entity_config": {},
|
"mode": "bridge",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -586,6 +611,17 @@ async def test_options_flow_include_mode_basic_accessory(hass):
|
|||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
|
assert result["data_schema"]({}) == {
|
||||||
|
"domains": [
|
||||||
|
"fan",
|
||||||
|
"humidifier",
|
||||||
|
"vacuum",
|
||||||
|
"media_player",
|
||||||
|
"climate",
|
||||||
|
"alarm_control_panel",
|
||||||
|
],
|
||||||
|
"mode": "bridge",
|
||||||
|
}
|
||||||
|
|
||||||
result2 = await hass.config_entries.options.async_configure(
|
result2 = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -594,6 +630,7 @@ async def test_options_flow_include_mode_basic_accessory(hass):
|
|||||||
|
|
||||||
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") == []
|
||||||
|
|
||||||
result3 = await hass.config_entries.options.async_configure(
|
result3 = await hass.config_entries.options.async_configure(
|
||||||
result2["flow_id"],
|
result2["flow_id"],
|
||||||
@ -612,7 +649,7 @@ async def test_options_flow_include_mode_basic_accessory(hass):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async def test_converting_bridge_to_accessory_mode(hass):
|
async def test_converting_bridge_to_accessory_mode(hass, hk_driver):
|
||||||
"""Test we can convert a bridge to accessory mode."""
|
"""Test we can convert a bridge to accessory mode."""
|
||||||
await setup.async_setup_component(hass, "persistent_notification", {})
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
||||||
result = await hass.config_entries.flow.async_init(
|
result = await hass.config_entries.flow.async_init(
|
||||||
@ -639,12 +676,12 @@ async def test_converting_bridge_to_accessory_mode(hass):
|
|||||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result3["step_id"] == "pairing"
|
assert result3["step_id"] == "pairing"
|
||||||
|
|
||||||
|
# We need to actually setup the config entry or the data
|
||||||
|
# will not get migrated to options
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.homekit.async_setup", return_value=True
|
"homeassistant.components.homekit.HomeKit.async_start",
|
||||||
) as mock_setup, patch(
|
|
||||||
"homeassistant.components.homekit.async_setup_entry",
|
|
||||||
return_value=True,
|
return_value=True,
|
||||||
) as mock_setup_entry:
|
) as mock_async_start:
|
||||||
result4 = await hass.config_entries.flow.async_configure(
|
result4 = await hass.config_entries.flow.async_configure(
|
||||||
result3["flow_id"],
|
result3["flow_id"],
|
||||||
{},
|
{},
|
||||||
@ -665,8 +702,7 @@ async def test_converting_bridge_to_accessory_mode(hass):
|
|||||||
"name": bridge_name,
|
"name": bridge_name,
|
||||||
"port": 12345,
|
"port": 12345,
|
||||||
}
|
}
|
||||||
assert len(mock_setup.mock_calls) == 1
|
assert len(mock_async_start.mock_calls) == 1
|
||||||
assert len(mock_setup_entry.mock_calls) == 1
|
|
||||||
|
|
||||||
config_entry = result4["result"]
|
config_entry = result4["result"]
|
||||||
|
|
||||||
@ -681,6 +717,9 @@ async def test_converting_bridge_to_accessory_mode(hass):
|
|||||||
|
|
||||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||||
assert result["step_id"] == "init"
|
assert result["step_id"] == "init"
|
||||||
|
schema = result["data_schema"].schema
|
||||||
|
assert _get_schema_default(schema, "mode") == "bridge"
|
||||||
|
assert _get_schema_default(schema, "domains") == ["light"]
|
||||||
|
|
||||||
result = await hass.config_entries.options.async_configure(
|
result = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
@ -714,3 +753,11 @@ async def test_converting_bridge_to_accessory_mode(hass):
|
|||||||
"include_entities": ["camera.tv"],
|
"include_entities": ["camera.tv"],
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _get_schema_default(schema, key_name):
|
||||||
|
"""Iterate schema to find a key."""
|
||||||
|
for schema_key in schema:
|
||||||
|
if schema_key == key_name:
|
||||||
|
return schema_key.default()
|
||||||
|
raise KeyError(f"{key_name} not found in schema")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user