mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Allow HomeKit to be configured in include mode from the UI (#41662)
This commit is contained in:
parent
f2a2cfc52e
commit
c5ae801bcb
@ -6,7 +6,7 @@ import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.config_entries import SOURCE_IMPORT
|
||||
from homeassistant.const import CONF_NAME, CONF_PORT
|
||||
from homeassistant.const import CONF_DOMAINS, CONF_ENTITIES, CONF_NAME, CONF_PORT
|
||||
from homeassistant.core import callback, split_entity_id
|
||||
import homeassistant.helpers.config_validation as cv
|
||||
from homeassistant.helpers.entityfilter import (
|
||||
@ -32,7 +32,12 @@ from .const import DOMAIN # pylint:disable=unused-import
|
||||
from .util import find_next_available_port
|
||||
|
||||
CONF_CAMERA_COPY = "camera_copy"
|
||||
CONF_DOMAINS = "domains"
|
||||
CONF_INCLUDE_EXCLUDE_MODE = "include_exclude_mode"
|
||||
|
||||
MODE_INCLUDE = "include"
|
||||
MODE_EXCLUDE = "exclude"
|
||||
|
||||
INCLUDE_EXCLUDE_MODES = [MODE_EXCLUDE, MODE_INCLUDE]
|
||||
|
||||
SUPPORTED_DOMAINS = [
|
||||
"alarm_control_panel",
|
||||
@ -64,6 +69,7 @@ DEFAULT_DOMAINS = [
|
||||
"climate",
|
||||
"cover",
|
||||
"humidifier",
|
||||
"fan",
|
||||
"light",
|
||||
"lock",
|
||||
"media_player",
|
||||
@ -210,7 +216,9 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Choose advanced options."""
|
||||
if user_input is not None:
|
||||
self.homekit_options.update(user_input)
|
||||
del self.homekit_options[CONF_INCLUDE_DOMAINS]
|
||||
for key in (CONF_DOMAINS, CONF_ENTITIES):
|
||||
if key in self.homekit_options:
|
||||
del self.homekit_options[key]
|
||||
return self.async_create_entry(title="", data=self.homekit_options)
|
||||
|
||||
schema_base = {}
|
||||
@ -275,46 +283,78 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
)
|
||||
return self.async_show_form(step_id="cameras", data_schema=data_schema)
|
||||
|
||||
async def async_step_exclude(self, user_input=None):
|
||||
"""Choose entities to exclude from the domain."""
|
||||
async def async_step_include_exclude(self, user_input=None):
|
||||
"""Choose entities to include or exclude from the domain."""
|
||||
if user_input is not None:
|
||||
self.homekit_options[CONF_FILTER] = {
|
||||
CONF_INCLUDE_DOMAINS: self.homekit_options[CONF_INCLUDE_DOMAINS],
|
||||
CONF_EXCLUDE_DOMAINS: self.homekit_options.get(
|
||||
CONF_EXCLUDE_DOMAINS, []
|
||||
),
|
||||
CONF_INCLUDE_ENTITIES: self.homekit_options.get(
|
||||
CONF_INCLUDE_ENTITIES, []
|
||||
),
|
||||
CONF_EXCLUDE_ENTITIES: user_input[CONF_EXCLUDE_ENTITIES],
|
||||
entity_filter = {
|
||||
CONF_INCLUDE_DOMAINS: [],
|
||||
CONF_EXCLUDE_DOMAINS: [],
|
||||
CONF_INCLUDE_ENTITIES: [],
|
||||
CONF_EXCLUDE_ENTITIES: [],
|
||||
}
|
||||
for entity_id in user_input[CONF_EXCLUDE_ENTITIES]:
|
||||
if entity_id in self.included_cameras:
|
||||
self.included_cameras.remove(entity_id)
|
||||
|
||||
if user_input[CONF_INCLUDE_EXCLUDE_MODE] == MODE_INCLUDE:
|
||||
entity_filter[CONF_INCLUDE_ENTITIES] = user_input[CONF_ENTITIES]
|
||||
# Include all of the domain if there are no entities
|
||||
# explicitly included as the user selected the domain
|
||||
domains_with_entities_selected = _domains_set_from_entities(
|
||||
user_input[CONF_ENTITIES]
|
||||
)
|
||||
entity_filter[CONF_INCLUDE_DOMAINS] = [
|
||||
domain
|
||||
for domain in self.homekit_options[CONF_DOMAINS]
|
||||
if domain not in domains_with_entities_selected
|
||||
]
|
||||
|
||||
for entity_id in list(self.included_cameras):
|
||||
if entity_id not in user_input[CONF_ENTITIES]:
|
||||
self.included_cameras.remove(entity_id)
|
||||
else:
|
||||
entity_filter[CONF_INCLUDE_DOMAINS] = self.homekit_options[CONF_DOMAINS]
|
||||
entity_filter[CONF_EXCLUDE_ENTITIES] = user_input[CONF_ENTITIES]
|
||||
for entity_id in user_input[CONF_ENTITIES]:
|
||||
if entity_id in self.included_cameras:
|
||||
self.included_cameras.remove(entity_id)
|
||||
|
||||
self.homekit_options[CONF_FILTER] = entity_filter
|
||||
|
||||
if self.included_cameras:
|
||||
return await self.async_step_cameras()
|
||||
|
||||
return await self.async_step_advanced()
|
||||
|
||||
entity_filter = self.homekit_options.get(CONF_FILTER, {})
|
||||
all_supported_entities = await self.hass.async_add_executor_job(
|
||||
_get_entities_matching_domains,
|
||||
self.hass,
|
||||
self.homekit_options[CONF_INCLUDE_DOMAINS],
|
||||
self.homekit_options[CONF_DOMAINS],
|
||||
)
|
||||
self.included_cameras = {
|
||||
entity_id
|
||||
for entity_id in all_supported_entities
|
||||
if entity_id.startswith("camera.")
|
||||
}
|
||||
|
||||
entities = entity_filter.get(CONF_INCLUDE_ENTITIES, [])
|
||||
if entities:
|
||||
include_exclude_mode = MODE_INCLUDE
|
||||
else:
|
||||
include_exclude_mode = MODE_EXCLUDE
|
||||
entities = entity_filter.get(CONF_EXCLUDE_ENTITIES, [])
|
||||
|
||||
data_schema = vol.Schema(
|
||||
{
|
||||
vol.Required(
|
||||
CONF_INCLUDE_EXCLUDE_MODE,
|
||||
default=include_exclude_mode,
|
||||
): vol.In(INCLUDE_EXCLUDE_MODES),
|
||||
vol.Optional(
|
||||
CONF_EXCLUDE_ENTITIES,
|
||||
default=entity_filter.get(CONF_EXCLUDE_ENTITIES, []),
|
||||
CONF_ENTITIES,
|
||||
default=entities,
|
||||
): cv.multi_select(all_supported_entities),
|
||||
}
|
||||
)
|
||||
return self.async_show_form(step_id="exclude", data_schema=data_schema)
|
||||
return self.async_show_form(step_id="include_exclude", data_schema=data_schema)
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Handle options flow."""
|
||||
@ -323,16 +363,21 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
|
||||
if user_input is not None:
|
||||
self.homekit_options.update(user_input)
|
||||
return await self.async_step_exclude()
|
||||
return await self.async_step_include_exclude()
|
||||
|
||||
self.homekit_options = dict(self.config_entry.options)
|
||||
entity_filter = self.homekit_options.get(CONF_FILTER, {})
|
||||
|
||||
domains = entity_filter.get(CONF_INCLUDE_DOMAINS, [])
|
||||
include_entities = entity_filter.get(CONF_INCLUDE_ENTITIES)
|
||||
if include_entities:
|
||||
domains.extend(_domains_set_from_entities(include_entities))
|
||||
|
||||
data_schema = vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_INCLUDE_DOMAINS,
|
||||
default=entity_filter.get(CONF_INCLUDE_DOMAINS, []),
|
||||
CONF_DOMAINS,
|
||||
default=domains,
|
||||
): cv.multi_select(SUPPORTED_DOMAINS)
|
||||
}
|
||||
)
|
||||
@ -349,3 +394,11 @@ def _get_entities_matching_domains(hass, domains):
|
||||
]
|
||||
entity_ids.sort()
|
||||
return entity_ids
|
||||
|
||||
|
||||
def _domains_set_from_entities(entity_ids):
|
||||
"""Build a set of domains for the given entity ids."""
|
||||
domains = set()
|
||||
for entity_id in entity_ids:
|
||||
domains.add(split_entity_id(entity_id)[0])
|
||||
return domains
|
||||
|
@ -10,15 +10,16 @@
|
||||
"data": {
|
||||
"include_domains": "[%key:component::homekit::config::step::user::data::include_domains%]"
|
||||
},
|
||||
"description": "Entities in the \u201cDomains to include\u201d will be bridged to HomeKit. You will be able to select which entities to exclude from this list on the next screen.",
|
||||
"description": "Entities in the \u201cDomains to include\u201d will be bridged to HomeKit. You will be able to select which entities to include or exclude from this list on the next screen.",
|
||||
"title": "Select domains to bridge."
|
||||
},
|
||||
"exclude": {
|
||||
"include_exclude": {
|
||||
"data": {
|
||||
"exclude_entities": "Entities to exclude"
|
||||
"mode": "Mode",
|
||||
"entities": "Entities"
|
||||
},
|
||||
"description": "Choose the entities that you do NOT want to be bridged.",
|
||||
"title": "Exclude entities in selected domains from bridge"
|
||||
"description": "Choose the entities to be bridged. In include mode, all entities in the domain will be bridged unless specific entities are selected. In exclude mode, all entities in the domain will be bridged except for the excluded entities.",
|
||||
"title": "Select entities to be bridged"
|
||||
},
|
||||
"cameras": {
|
||||
"data": {
|
||||
|
@ -1,32 +1,25 @@
|
||||
{
|
||||
"config": {
|
||||
"abort": {
|
||||
"port_name_in_use": "A bridge with the same name or port is already configured."
|
||||
},
|
||||
"step": {
|
||||
"pairing": {
|
||||
"description": "As soon as the {name} bridge is ready, pairing will be available in \u201cNotifications\u201d as \u201cHomeKit Bridge Setup\u201d.",
|
||||
"title": "Pair HomeKit Bridge"
|
||||
},
|
||||
"user": {
|
||||
"data": {
|
||||
"auto_start": "Autostart (disable if using Z-Wave or other delayed start system)",
|
||||
"include_domains": "Domains to include"
|
||||
},
|
||||
"description": "A HomeKit Bridge will allow you to access your Home Assistant entities in HomeKit. HomeKit Bridges are limited to 150 accessories per instance including the bridge itself. If you wish to bridge more than the maximum number of accessories, it is recommended that you use multiple HomeKit bridges for different domains. Detailed entity configuration is only available via YAML for the primary bridge.",
|
||||
"title": "Activate HomeKit Bridge"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "HomeKit Bridge",
|
||||
"options": {
|
||||
"step": {
|
||||
"advanced": {
|
||||
"yaml": {
|
||||
"title": "Adjust HomeKit Bridge Options",
|
||||
"description": "This entry is controlled via YAML"
|
||||
},
|
||||
"init": {
|
||||
"data": {
|
||||
"auto_start": "Autostart (disable if using Z-Wave or other delayed start system)",
|
||||
"safe_mode": "Safe Mode (enable only if pairing fails)"
|
||||
"include_domains": "[%key:component::homekit::config::step::user::data::include_domains%]"
|
||||
},
|
||||
"description": "These settings only need to be adjusted if the HomeKit bridge is not functional.",
|
||||
"title": "Advanced Configuration"
|
||||
"description": "Entities in the \u201cDomains to include\u201d will be bridged to HomeKit. You will be able to select which entities to include or exclude from this list on the next screen.",
|
||||
"title": "Select domains to bridge."
|
||||
},
|
||||
"include_exclude": {
|
||||
"data": {
|
||||
"mode": "Mode",
|
||||
"entities": "Entities"
|
||||
},
|
||||
"description": "Choose the entities to be bridged. In include mode, all entities in the domain will be bridged unless specific entities are selected. In exclude mode, all entities in the domain will be bridged except for the excluded entities.",
|
||||
"title": "Select entities to be bridged"
|
||||
},
|
||||
"cameras": {
|
||||
"data": {
|
||||
@ -35,25 +28,33 @@
|
||||
"description": "Check all cameras that support native H.264 streams. If the camera does not output a H.264 stream, the system will transcode the video to H.264 for HomeKit. Transcoding requires a performant CPU and is unlikely to work on single board computers.",
|
||||
"title": "Select camera video codec."
|
||||
},
|
||||
"exclude": {
|
||||
"advanced": {
|
||||
"data": {
|
||||
"exclude_entities": "Entities to exclude"
|
||||
"auto_start": "[%key:component::homekit::config::step::user::data::auto_start%]",
|
||||
"safe_mode": "Safe Mode (enable only if pairing fails)"
|
||||
},
|
||||
"description": "Choose the entities that you do NOT want to be bridged.",
|
||||
"title": "Exclude entities in selected domains from bridge"
|
||||
},
|
||||
"init": {
|
||||
"data": {
|
||||
"include_domains": "Domains to include"
|
||||
},
|
||||
"description": "Entities in the \u201cDomains to include\u201d will be bridged to HomeKit. You will be able to select which entities to exclude from this list on the next screen.",
|
||||
"title": "Select domains to bridge."
|
||||
},
|
||||
"yaml": {
|
||||
"description": "This entry is controlled via YAML",
|
||||
"title": "Adjust HomeKit Bridge Options"
|
||||
"description": "These settings only need to be adjusted if the HomeKit bridge is not functional.",
|
||||
"title": "Advanced Configuration"
|
||||
}
|
||||
}
|
||||
},
|
||||
"title": "HomeKit Bridge"
|
||||
}
|
||||
"config": {
|
||||
"step": {
|
||||
"user": {
|
||||
"data": {
|
||||
"auto_start": "Autostart (disable if using Z-Wave or other delayed start system)",
|
||||
"include_domains": "Domains to include"
|
||||
},
|
||||
"description": "A HomeKit Bridge will allow you to access your Home Assistant entities in HomeKit. HomeKit Bridges are limited to 150 accessories per instance including the bridge itself. If you wish to bridge more than the maximum number of accessories, it is recommended that you use multiple HomeKit bridges for different domains. Detailed entity configuration is only available via YAML for the primary bridge.",
|
||||
"title": "Activate HomeKit Bridge"
|
||||
},
|
||||
"pairing": {
|
||||
"title": "Pair HomeKit Bridge",
|
||||
"description": "As soon as the {name} bridge is ready, pairing will be available in \u201cNotifications\u201d as \u201cHomeKit Bridge Setup\u201d."
|
||||
}
|
||||
},
|
||||
"abort": {
|
||||
"port_name_in_use": "A bridge with the same name or port is already configured."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -123,8 +123,8 @@ async def test_import(hass):
|
||||
assert len(mock_setup_entry.mock_calls) == 2
|
||||
|
||||
|
||||
async def test_options_flow_advanced(hass):
|
||||
"""Test config flow options."""
|
||||
async def test_options_flow_exclude_mode_advanced(hass):
|
||||
"""Test config flow options in exclude mode with advanced options."""
|
||||
|
||||
config_entry = _mock_config_entry_with_options_populated()
|
||||
config_entry.add_to_hass(hass)
|
||||
@ -141,15 +141,15 @@ async def test_options_flow_advanced(hass):
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"include_domains": ["fan", "vacuum", "climate", "humidifier"]},
|
||||
user_input={"domains": ["fan", "vacuum", "climate", "humidifier"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "exclude"
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"exclude_entities": ["climate.old"]},
|
||||
user_input={"entities": ["climate.old"], "include_exclude_mode": "exclude"},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "advanced"
|
||||
@ -173,8 +173,8 @@ async def test_options_flow_advanced(hass):
|
||||
}
|
||||
|
||||
|
||||
async def test_options_flow_basic(hass):
|
||||
"""Test config flow options."""
|
||||
async def test_options_flow_exclude_mode_basic(hass):
|
||||
"""Test config flow options in exclude mode."""
|
||||
|
||||
config_entry = _mock_config_entry_with_options_populated()
|
||||
config_entry.add_to_hass(hass)
|
||||
@ -191,15 +191,15 @@ async def test_options_flow_basic(hass):
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"include_domains": ["fan", "vacuum", "climate"]},
|
||||
user_input={"domains": ["fan", "vacuum", "climate"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "exclude"
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"exclude_entities": ["climate.old"]},
|
||||
user_input={"entities": ["climate.old"], "include_exclude_mode": "exclude"},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "advanced"
|
||||
@ -223,8 +223,60 @@ async def test_options_flow_basic(hass):
|
||||
}
|
||||
|
||||
|
||||
async def test_options_flow_with_cameras(hass):
|
||||
"""Test config flow options."""
|
||||
async def test_options_flow_include_mode_basic(hass):
|
||||
"""Test config flow options in include mode."""
|
||||
|
||||
config_entry = _mock_config_entry_with_options_populated()
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
hass.states.async_set("climate.old", "off")
|
||||
hass.states.async_set("climate.new", "off")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
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"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"domains": ["fan", "vacuum", "climate"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"entities": ["climate.new"], "include_exclude_mode": "include"},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "advanced"
|
||||
|
||||
with patch("homeassistant.components.homekit.async_setup_entry", return_value=True):
|
||||
result3 = await hass.config_entries.options.async_configure(
|
||||
result2["flow_id"],
|
||||
user_input={"safe_mode": True},
|
||||
)
|
||||
|
||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert config_entry.options == {
|
||||
"auto_start": False,
|
||||
"filter": {
|
||||
"exclude_domains": [],
|
||||
"exclude_entities": [],
|
||||
"include_domains": ["fan", "vacuum"],
|
||||
"include_entities": ["climate.new"],
|
||||
},
|
||||
"safe_mode": True,
|
||||
}
|
||||
|
||||
|
||||
async def test_options_flow_exclude_mode_with_cameras(hass):
|
||||
"""Test config flow options in exclude mode with cameras."""
|
||||
|
||||
config_entry = _mock_config_entry_with_options_populated()
|
||||
config_entry.add_to_hass(hass)
|
||||
@ -245,15 +297,18 @@ async def test_options_flow_with_cameras(hass):
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"include_domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
user_input={"domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "exclude"
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"exclude_entities": ["climate.old", "camera.excluded"]},
|
||||
user_input={
|
||||
"entities": ["climate.old", "camera.excluded"],
|
||||
"include_exclude_mode": "exclude",
|
||||
},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "cameras"
|
||||
@ -296,15 +351,138 @@ async def test_options_flow_with_cameras(hass):
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"include_domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
user_input={"domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "exclude"
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"exclude_entities": ["climate.old", "camera.excluded"]},
|
||||
user_input={
|
||||
"entities": ["climate.old", "camera.excluded"],
|
||||
"include_exclude_mode": "exclude",
|
||||
},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "cameras"
|
||||
|
||||
result3 = await hass.config_entries.options.async_configure(
|
||||
result2["flow_id"],
|
||||
user_input={"camera_copy": []},
|
||||
)
|
||||
|
||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result3["step_id"] == "advanced"
|
||||
|
||||
with patch("homeassistant.components.homekit.async_setup_entry", return_value=True):
|
||||
result4 = await hass.config_entries.options.async_configure(
|
||||
result3["flow_id"],
|
||||
user_input={"safe_mode": True},
|
||||
)
|
||||
|
||||
assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert config_entry.options == {
|
||||
"auto_start": False,
|
||||
"filter": {
|
||||
"exclude_domains": [],
|
||||
"exclude_entities": ["climate.old", "camera.excluded"],
|
||||
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
||||
"include_entities": [],
|
||||
},
|
||||
"entity_config": {"camera.native_h264": {}},
|
||||
"safe_mode": True,
|
||||
}
|
||||
|
||||
|
||||
async def test_options_flow_include_mode_with_cameras(hass):
|
||||
"""Test config flow options in include mode with cameras."""
|
||||
|
||||
config_entry = _mock_config_entry_with_options_populated()
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
hass.states.async_set("climate.old", "off")
|
||||
hass.states.async_set("camera.native_h264", "off")
|
||||
hass.states.async_set("camera.transcode_h264", "off")
|
||||
hass.states.async_set("camera.excluded", "off")
|
||||
|
||||
await hass.async_block_till_done()
|
||||
|
||||
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"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
"entities": ["camera.native_h264", "camera.transcode_h264"],
|
||||
"include_exclude_mode": "include",
|
||||
},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "cameras"
|
||||
|
||||
result3 = await hass.config_entries.options.async_configure(
|
||||
result2["flow_id"],
|
||||
user_input={"camera_copy": ["camera.native_h264"]},
|
||||
)
|
||||
|
||||
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result3["step_id"] == "advanced"
|
||||
|
||||
with patch("homeassistant.components.homekit.async_setup_entry", return_value=True):
|
||||
result4 = await hass.config_entries.options.async_configure(
|
||||
result3["flow_id"],
|
||||
user_input={"safe_mode": True},
|
||||
)
|
||||
|
||||
assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert config_entry.options == {
|
||||
"auto_start": False,
|
||||
"filter": {
|
||||
"exclude_domains": [],
|
||||
"exclude_entities": [],
|
||||
"include_domains": ["fan", "vacuum", "climate"],
|
||||
"include_entities": ["camera.native_h264", "camera.transcode_h264"],
|
||||
},
|
||||
"entity_config": {"camera.native_h264": {"video_codec": "copy"}},
|
||||
"safe_mode": True,
|
||||
}
|
||||
|
||||
# Now run though again and verify we can turn off copy
|
||||
|
||||
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"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={"domains": ["fan", "vacuum", "climate", "camera"]},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result["step_id"] == "include_exclude"
|
||||
|
||||
result2 = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={
|
||||
"entities": ["climate.old", "camera.excluded"],
|
||||
"include_exclude_mode": "exclude",
|
||||
},
|
||||
)
|
||||
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
||||
assert result2["step_id"] == "cameras"
|
||||
|
Loading…
x
Reference in New Issue
Block a user