2020-05-01 04:05:06 +00:00
|
|
|
"""Test the HomeKit config flow."""
|
2021-01-01 21:31:56 +00:00
|
|
|
from unittest.mock import patch
|
|
|
|
|
2020-12-29 12:54:24 +00:00
|
|
|
import pytest
|
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
from homeassistant import config_entries, data_entry_flow, setup
|
|
|
|
from homeassistant.components.homekit.const import DOMAIN
|
|
|
|
from homeassistant.config_entries import SOURCE_IMPORT
|
|
|
|
from homeassistant.const import CONF_NAME, CONF_PORT
|
|
|
|
|
|
|
|
from tests.common import MockConfigEntry
|
|
|
|
|
|
|
|
|
|
|
|
def _mock_config_entry_with_options_populated():
|
|
|
|
"""Create a mock config entry with options populated."""
|
|
|
|
return MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
options={
|
|
|
|
"filter": {
|
|
|
|
"include_domains": [
|
|
|
|
"fan",
|
2020-07-02 17:53:11 +00:00
|
|
|
"humidifier",
|
2020-05-01 04:05:06 +00:00
|
|
|
"vacuum",
|
|
|
|
"media_player",
|
|
|
|
"climate",
|
|
|
|
"alarm_control_panel",
|
|
|
|
],
|
|
|
|
"exclude_entities": ["climate.front_gate"],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
async def test_setup_in_bridge_mode(hass):
|
|
|
|
"""Test we can setup a new instance in bridge mode."""
|
2020-05-01 04:05:06 +00:00
|
|
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
assert result["type"] == "form"
|
|
|
|
assert result["errors"] == {}
|
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{"mode": "bridge"},
|
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "bridge_mode"
|
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.config_flow.find_next_available_port",
|
|
|
|
return_value=12345,
|
|
|
|
):
|
2021-01-29 15:57:13 +00:00
|
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
|
|
result2["flow_id"],
|
2020-12-29 12:54:24 +00:00
|
|
|
{"include_domains": ["light"]},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
2021-01-29 15:57:13 +00:00
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result3["step_id"] == "pairing"
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.async_setup", return_value=True
|
|
|
|
) as mock_setup, patch(
|
2020-08-27 11:56:20 +00:00
|
|
|
"homeassistant.components.homekit.async_setup_entry",
|
|
|
|
return_value=True,
|
2020-05-01 04:05:06 +00:00
|
|
|
) as mock_setup_entry:
|
2021-01-29 15:57:13 +00:00
|
|
|
result4 = await hass.config_entries.flow.async_configure(
|
|
|
|
result3["flow_id"],
|
2020-08-27 11:56:20 +00:00
|
|
|
{},
|
|
|
|
)
|
2020-10-24 14:20:56 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-05-01 04:05:06 +00:00
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
assert result4["title"][:11] == "HASS Bridge"
|
|
|
|
bridge_name = (result4["title"].split(":"))[0]
|
|
|
|
assert result4["data"] == {
|
2020-05-01 04:05:06 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": ["light"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
2021-01-29 15:57:13 +00:00
|
|
|
"mode": "bridge",
|
2020-05-01 04:05:06 +00:00
|
|
|
"name": bridge_name,
|
|
|
|
"port": 12345,
|
|
|
|
}
|
|
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
async def test_setup_in_accessory_mode(hass):
|
|
|
|
"""Test we can setup a new instance in accessory."""
|
|
|
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
|
|
hass.states.async_set("camera.mine", "off")
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
assert result["type"] == "form"
|
|
|
|
assert result["errors"] == {}
|
|
|
|
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{"mode": "accessory"},
|
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "accessory_mode"
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.config_flow.find_next_available_port",
|
|
|
|
return_value=12345,
|
|
|
|
):
|
|
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
|
|
result2["flow_id"],
|
|
|
|
{"entity_id": "camera.mine"},
|
|
|
|
)
|
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result3["step_id"] == "pairing"
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.async_setup", return_value=True
|
|
|
|
) as mock_setup, patch(
|
|
|
|
"homeassistant.components.homekit.async_setup_entry",
|
|
|
|
return_value=True,
|
|
|
|
) as mock_setup_entry:
|
|
|
|
result4 = await hass.config_entries.flow.async_configure(
|
|
|
|
result3["flow_id"],
|
|
|
|
{},
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
assert result4["title"][:14] == "HASS Accessory"
|
|
|
|
bridge_name = (result4["title"].split(":"))[0]
|
|
|
|
assert result4["data"] == {
|
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": [],
|
|
|
|
"include_entities": ["camera.mine"],
|
|
|
|
},
|
|
|
|
"mode": "accessory",
|
|
|
|
"name": bridge_name,
|
|
|
|
"entity_config": {"camera.mine": {"video_codec": "copy"}},
|
|
|
|
"port": 12345,
|
|
|
|
}
|
|
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
async def test_import(hass):
|
|
|
|
"""Test we can import instance."""
|
|
|
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
|
|
|
|
|
|
entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN, data={CONF_NAME: "mock_name", CONF_PORT: 12345}
|
|
|
|
)
|
|
|
|
entry.add_to_hass(hass)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_IMPORT},
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
)
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_ABORT
|
|
|
|
assert result["reason"] == "port_name_in_use"
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.async_setup", return_value=True
|
|
|
|
) as mock_setup, patch(
|
2020-08-27 11:56:20 +00:00
|
|
|
"homeassistant.components.homekit.async_setup_entry",
|
|
|
|
return_value=True,
|
2020-05-01 04:05:06 +00:00
|
|
|
) as mock_setup_entry:
|
|
|
|
result2 = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN,
|
|
|
|
context={"source": config_entries.SOURCE_IMPORT},
|
|
|
|
data={CONF_NAME: "othername", CONF_PORT: 56789},
|
|
|
|
)
|
2020-10-24 14:20:56 +00:00
|
|
|
await hass.async_block_till_done()
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
assert result2["title"] == "othername:56789"
|
|
|
|
assert result2["data"] == {
|
|
|
|
"name": "othername",
|
|
|
|
"port": 56789,
|
|
|
|
}
|
|
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
assert len(mock_setup_entry.mock_calls) == 2
|
|
|
|
|
|
|
|
|
2020-12-29 12:54:24 +00:00
|
|
|
@pytest.mark.parametrize("auto_start", [True, False])
|
|
|
|
async def test_options_flow_exclude_mode_advanced(auto_start, hass):
|
2020-10-15 13:33:01 +00:00
|
|
|
"""Test config flow options in exclude mode with advanced options."""
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
config_entry = _mock_config_entry_with_options_populated()
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
hass.states.async_set("climate.old", "off")
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
result = await hass.config_entries.options.async_init(
|
|
|
|
config_entry.entry_id, context={"show_advanced_options": True}
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result["step_id"] == "init"
|
|
|
|
|
|
|
|
result = await hass.config_entries.options.async_configure(
|
2020-07-02 17:53:11 +00:00
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={"domains": ["fan", "vacuum", "climate", "humidifier"]},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
2020-10-15 13:33:01 +00:00
|
|
|
assert result["step_id"] == "include_exclude"
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
2020-08-27 11:56:20 +00:00
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={"entities": ["climate.old"], "include_exclude_mode": "exclude"},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
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(
|
2020-08-27 11:56:20 +00:00
|
|
|
result2["flow_id"],
|
2021-01-11 13:26:09 +00:00
|
|
|
user_input={"auto_start": auto_start},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": auto_start,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-05-01 04:05:06 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": ["climate.old"],
|
2020-07-02 17:53:11 +00:00
|
|
|
"include_domains": ["fan", "vacuum", "climate", "humidifier"],
|
2020-05-01 04:05:06 +00:00
|
|
|
"include_entities": [],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-15 13:33:01 +00:00
|
|
|
async def test_options_flow_exclude_mode_basic(hass):
|
|
|
|
"""Test config flow options in exclude mode."""
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
config_entry = _mock_config_entry_with_options_populated()
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
hass.states.async_set("climate.old", "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(
|
2020-08-27 11:56:20 +00:00
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={"domains": ["fan", "vacuum", "climate"]},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
2020-10-15 13:33:01 +00:00
|
|
|
assert result["step_id"] == "include_exclude"
|
2020-05-01 04:05:06 +00:00
|
|
|
|
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
2020-08-27 11:56:20 +00:00
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={"entities": ["climate.old"], "include_exclude_mode": "exclude"},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-05-01 04:05:06 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-05-01 04:05:06 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": ["climate.old"],
|
|
|
|
"include_domains": ["fan", "vacuum", "climate"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-15 13:33:01 +00:00
|
|
|
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"},
|
|
|
|
)
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-10-15 13:33:01 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-10-15 13:33:01 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": ["fan", "vacuum"],
|
|
|
|
"include_entities": ["climate.new"],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async def test_options_flow_exclude_mode_with_cameras(hass):
|
|
|
|
"""Test config flow options in exclude mode with cameras."""
|
2020-05-07 14:55:09 +00:00
|
|
|
|
|
|
|
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"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={"domains": ["fan", "vacuum", "climate", "camera"]},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
2020-10-15 13:33:01 +00:00
|
|
|
assert result["step_id"] == "include_exclude"
|
2020-05-07 14:55:09 +00:00
|
|
|
|
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={
|
|
|
|
"entities": ["climate.old", "camera.excluded"],
|
|
|
|
"include_exclude_mode": "exclude",
|
|
|
|
},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "cameras"
|
|
|
|
|
|
|
|
result3 = await hass.config_entries.options.async_configure(
|
2020-08-27 11:56:20 +00:00
|
|
|
result2["flow_id"],
|
|
|
|
user_input={"camera_copy": ["camera.native_h264"]},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-05-07 14:55:09 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-05-07 14:55:09 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": ["climate.old", "camera.excluded"],
|
|
|
|
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
|
|
|
"entity_config": {"camera.native_h264": {"video_codec": "copy"}},
|
|
|
|
}
|
|
|
|
|
|
|
|
# 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"],
|
2020-10-15 13:33:01 +00:00
|
|
|
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"
|
|
|
|
|
|
|
|
result3 = await hass.config_entries.options.async_configure(
|
|
|
|
result2["flow_id"],
|
2021-01-29 15:57:13 +00:00
|
|
|
user_input={"camera_copy": ["camera.native_h264"]},
|
2020-10-15 13:33:01 +00:00
|
|
|
)
|
|
|
|
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2021-01-29 15:57:13 +00:00
|
|
|
|
2020-10-15 13:33:01 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-10-15 13:33:01 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": ["climate.old", "camera.excluded"],
|
|
|
|
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
2021-01-29 15:57:13 +00:00
|
|
|
"entity_config": {"camera.native_h264": {"video_codec": "copy"}},
|
2020-10-15 13:33:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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"]},
|
|
|
|
)
|
|
|
|
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-10-15 13:33:01 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-10-15 13:33:01 +00:00
|
|
|
"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"}},
|
|
|
|
}
|
|
|
|
|
|
|
|
# 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"]},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
2020-10-15 13:33:01 +00:00
|
|
|
assert result["step_id"] == "include_exclude"
|
2020-05-07 14:55:09 +00:00
|
|
|
|
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
|
|
|
result["flow_id"],
|
2020-10-15 13:33:01 +00:00
|
|
|
user_input={
|
|
|
|
"entities": ["climate.old", "camera.excluded"],
|
|
|
|
"include_exclude_mode": "exclude",
|
|
|
|
},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "cameras"
|
|
|
|
|
|
|
|
result3 = await hass.config_entries.options.async_configure(
|
2020-08-27 11:56:20 +00:00
|
|
|
result2["flow_id"],
|
|
|
|
user_input={"camera_copy": []},
|
2020-05-07 14:55:09 +00:00
|
|
|
)
|
|
|
|
|
2021-01-11 13:26:09 +00:00
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-05-07 14:55:09 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "bridge",
|
2020-05-07 14:55:09 +00:00
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": ["climate.old", "camera.excluded"],
|
|
|
|
"include_domains": ["fan", "vacuum", "climate", "camera"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
2021-01-29 15:57:13 +00:00
|
|
|
"entity_config": {},
|
2020-05-07 14:55:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-05-01 04:05:06 +00:00
|
|
|
async def test_options_flow_blocked_when_from_yaml(hass):
|
|
|
|
"""Test config flow options."""
|
|
|
|
|
|
|
|
config_entry = MockConfigEntry(
|
|
|
|
domain=DOMAIN,
|
|
|
|
data={CONF_NAME: "mock_name", CONF_PORT: 12345},
|
|
|
|
options={
|
|
|
|
"auto_start": True,
|
|
|
|
"filter": {
|
|
|
|
"include_domains": [
|
|
|
|
"fan",
|
2020-07-02 17:53:11 +00:00
|
|
|
"humidifier",
|
2020-05-01 04:05:06 +00:00
|
|
|
"vacuum",
|
|
|
|
"media_player",
|
|
|
|
"climate",
|
|
|
|
"alarm_control_panel",
|
|
|
|
],
|
|
|
|
"exclude_entities": ["climate.front_gate"],
|
|
|
|
},
|
|
|
|
},
|
|
|
|
source=SOURCE_IMPORT,
|
|
|
|
)
|
|
|
|
config_entry.add_to_hass(hass)
|
|
|
|
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
result = await hass.config_entries.options.async_init(config_entry.entry_id)
|
|
|
|
|
|
|
|
assert result["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result["step_id"] == "yaml"
|
|
|
|
|
|
|
|
with patch("homeassistant.components.homekit.async_setup_entry", return_value=True):
|
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
2020-08-27 11:56:20 +00:00
|
|
|
result["flow_id"],
|
|
|
|
user_input={},
|
2020-05-01 04:05:06 +00:00
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-10-15 16:59:50 +00:00
|
|
|
|
|
|
|
|
|
|
|
async def test_options_flow_include_mode_basic_accessory(hass):
|
|
|
|
"""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)
|
|
|
|
|
|
|
|
hass.states.async_set("media_player.tv", "off")
|
|
|
|
hass.states.async_set("media_player.sonos", "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"
|
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
result2 = await hass.config_entries.options.async_configure(
|
2020-10-15 16:59:50 +00:00
|
|
|
result["flow_id"],
|
|
|
|
user_input={"domains": ["media_player"], "mode": "accessory"},
|
|
|
|
)
|
|
|
|
|
2021-01-29 15:57:13 +00:00
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "include_exclude"
|
|
|
|
|
|
|
|
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 == {
|
|
|
|
"auto_start": True,
|
|
|
|
"mode": "accessory",
|
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": [],
|
|
|
|
"include_entities": ["media_player.tv"],
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async def test_converting_bridge_to_accessory_mode(hass):
|
|
|
|
"""Test we can convert a bridge to accessory mode."""
|
|
|
|
await setup.async_setup_component(hass, "persistent_notification", {})
|
|
|
|
result = await hass.config_entries.flow.async_init(
|
|
|
|
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
|
|
|
)
|
|
|
|
assert result["type"] == "form"
|
|
|
|
assert result["errors"] == {}
|
|
|
|
|
|
|
|
result2 = await hass.config_entries.flow.async_configure(
|
|
|
|
result["flow_id"],
|
|
|
|
{"mode": "bridge"},
|
|
|
|
)
|
|
|
|
assert result2["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result2["step_id"] == "bridge_mode"
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.config_flow.find_next_available_port",
|
|
|
|
return_value=12345,
|
|
|
|
):
|
|
|
|
result3 = await hass.config_entries.flow.async_configure(
|
|
|
|
result2["flow_id"],
|
|
|
|
{"include_domains": ["light"]},
|
|
|
|
)
|
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_FORM
|
|
|
|
assert result3["step_id"] == "pairing"
|
|
|
|
|
|
|
|
with patch(
|
|
|
|
"homeassistant.components.homekit.async_setup", return_value=True
|
|
|
|
) as mock_setup, patch(
|
|
|
|
"homeassistant.components.homekit.async_setup_entry",
|
|
|
|
return_value=True,
|
|
|
|
) as mock_setup_entry:
|
|
|
|
result4 = await hass.config_entries.flow.async_configure(
|
|
|
|
result3["flow_id"],
|
|
|
|
{},
|
|
|
|
)
|
|
|
|
await hass.async_block_till_done()
|
|
|
|
|
|
|
|
assert result4["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
|
|
|
assert result4["title"][:11] == "HASS Bridge"
|
|
|
|
bridge_name = (result4["title"].split(":"))[0]
|
|
|
|
assert result4["data"] == {
|
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": ["light"],
|
|
|
|
"include_entities": [],
|
|
|
|
},
|
|
|
|
"mode": "bridge",
|
|
|
|
"name": bridge_name,
|
|
|
|
"port": 12345,
|
|
|
|
}
|
|
|
|
assert len(mock_setup.mock_calls) == 1
|
|
|
|
assert len(mock_setup_entry.mock_calls) == 1
|
|
|
|
|
|
|
|
config_entry = result4["result"]
|
|
|
|
|
|
|
|
hass.states.async_set("camera.tv", "off")
|
|
|
|
hass.states.async_set("camera.sonos", "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": ["camera"], "mode": "accessory"},
|
|
|
|
)
|
|
|
|
|
2020-10-15 16:59:50 +00:00
|
|
|
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"],
|
2021-01-29 15:57:13 +00:00
|
|
|
user_input={"entities": "camera.tv"},
|
2020-10-15 16:59:50 +00:00
|
|
|
)
|
2021-01-29 15:57:13 +00:00
|
|
|
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.tv"]},
|
|
|
|
)
|
|
|
|
|
|
|
|
assert result3["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
2020-10-15 16:59:50 +00:00
|
|
|
assert config_entry.options == {
|
2020-12-29 12:54:24 +00:00
|
|
|
"auto_start": True,
|
2021-01-29 15:57:13 +00:00
|
|
|
"entity_config": {"camera.tv": {"video_codec": "copy"}},
|
2020-10-15 16:59:50 +00:00
|
|
|
"mode": "accessory",
|
|
|
|
"filter": {
|
|
|
|
"exclude_domains": [],
|
|
|
|
"exclude_entities": [],
|
|
|
|
"include_domains": [],
|
2021-01-29 15:57:13 +00:00
|
|
|
"include_entities": ["camera.tv"],
|
2020-10-15 16:59:50 +00:00
|
|
|
},
|
|
|
|
}
|