Motion blinds add interface and wait_for_push options (#50067)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
174eaefe61
commit
9bd2115a20
7 changed files with 300 additions and 33 deletions
|
@ -3,7 +3,7 @@ from datetime import timedelta
|
|||
import logging
|
||||
from socket import timeout
|
||||
|
||||
from motionblinds import MotionMulticast, ParseException
|
||||
from motionblinds import AsyncMotionMulticast, ParseException
|
||||
|
||||
from homeassistant import config_entries, core
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST, EVENT_HOMEASSISTANT_STOP
|
||||
|
@ -13,6 +13,10 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
|||
|
||||
from .const import (
|
||||
ATTR_AVAILABLE,
|
||||
CONF_INTERFACE,
|
||||
CONF_WAIT_FOR_PUSH,
|
||||
DEFAULT_INTERFACE,
|
||||
DEFAULT_WAIT_FOR_PUSH,
|
||||
DOMAIN,
|
||||
KEY_COORDINATOR,
|
||||
KEY_GATEWAY,
|
||||
|
@ -34,7 +38,7 @@ class DataUpdateCoordinatorMotionBlinds(DataUpdateCoordinator):
|
|||
self,
|
||||
hass,
|
||||
logger,
|
||||
gateway,
|
||||
coordinator_info,
|
||||
*,
|
||||
name,
|
||||
update_interval=None,
|
||||
|
@ -49,7 +53,8 @@ class DataUpdateCoordinatorMotionBlinds(DataUpdateCoordinator):
|
|||
update_interval=update_interval,
|
||||
)
|
||||
|
||||
self._gateway = gateway
|
||||
self._gateway = coordinator_info[KEY_GATEWAY]
|
||||
self._wait_for_push = coordinator_info[CONF_WAIT_FOR_PUSH]
|
||||
|
||||
def update_gateway(self):
|
||||
"""Call all updates using one async_add_executor_job."""
|
||||
|
@ -66,7 +71,10 @@ class DataUpdateCoordinatorMotionBlinds(DataUpdateCoordinator):
|
|||
|
||||
for blind in self._gateway.device_list.values():
|
||||
try:
|
||||
blind.Update()
|
||||
if self._wait_for_push:
|
||||
blind.Update()
|
||||
else:
|
||||
blind.Update_trigger()
|
||||
except (timeout, ParseException):
|
||||
# let the error be logged and handled by the motionblinds library
|
||||
data[blind.mac] = {ATTR_AVAILABLE: False}
|
||||
|
@ -95,13 +103,17 @@ async def async_setup_entry(
|
|||
hass.data.setdefault(DOMAIN, {})
|
||||
host = entry.data[CONF_HOST]
|
||||
key = entry.data[CONF_API_KEY]
|
||||
multicast_interface = entry.data.get(CONF_INTERFACE, DEFAULT_INTERFACE)
|
||||
wait_for_push = entry.options.get(CONF_WAIT_FOR_PUSH, DEFAULT_WAIT_FOR_PUSH)
|
||||
|
||||
entry.async_on_unload(entry.add_update_listener(update_listener))
|
||||
|
||||
# Create multicast Listener
|
||||
if KEY_MULTICAST_LISTENER not in hass.data[DOMAIN]:
|
||||
multicast = MotionMulticast()
|
||||
multicast = AsyncMotionMulticast(interface=multicast_interface)
|
||||
hass.data[DOMAIN][KEY_MULTICAST_LISTENER] = multicast
|
||||
# start listening for local pushes (only once)
|
||||
await hass.async_add_executor_job(multicast.Start_listen)
|
||||
await multicast.Start_listen()
|
||||
|
||||
# register stop callback to shutdown listening for local pushes
|
||||
def stop_motion_multicast(event):
|
||||
|
@ -117,11 +129,15 @@ async def async_setup_entry(
|
|||
if not await connect_gateway_class.async_connect_gateway(host, key):
|
||||
raise ConfigEntryNotReady
|
||||
motion_gateway = connect_gateway_class.gateway_device
|
||||
coordinator_info = {
|
||||
KEY_GATEWAY: motion_gateway,
|
||||
CONF_WAIT_FOR_PUSH: wait_for_push,
|
||||
}
|
||||
|
||||
coordinator = DataUpdateCoordinatorMotionBlinds(
|
||||
hass,
|
||||
_LOGGER,
|
||||
motion_gateway,
|
||||
coordinator_info,
|
||||
# Name of the data. For logging purposes.
|
||||
name=entry.title,
|
||||
# Polling interval. Will only be polled if there are subscribers.
|
||||
|
@ -172,6 +188,13 @@ async def async_unload_entry(
|
|||
# No motion gateways left, stop Motion multicast
|
||||
_LOGGER.debug("Shutting down Motion Listener")
|
||||
multicast = hass.data[DOMAIN].pop(KEY_MULTICAST_LISTENER)
|
||||
await hass.async_add_executor_job(multicast.Stop_listen)
|
||||
multicast.Stop_listen()
|
||||
|
||||
return unload_ok
|
||||
|
||||
|
||||
async def update_listener(
|
||||
hass: core.HomeAssistant, config_entry: config_entries.ConfigEntry
|
||||
) -> None:
|
||||
"""Handle options update."""
|
||||
await hass.config_entries.async_reload(config_entry.entry_id)
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
"""Config flow to configure Motion Blinds using their WLAN API."""
|
||||
from motionblinds import MotionDiscovery
|
||||
from socket import gaierror
|
||||
|
||||
from motionblinds import AsyncMotionMulticast, MotionDiscovery
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant.components import network
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST
|
||||
from homeassistant.core import callback
|
||||
|
||||
from .const import DEFAULT_GATEWAY_NAME, DOMAIN
|
||||
from .const import (
|
||||
CONF_INTERFACE,
|
||||
CONF_WAIT_FOR_PUSH,
|
||||
DEFAULT_GATEWAY_NAME,
|
||||
DEFAULT_INTERFACE,
|
||||
DEFAULT_WAIT_FOR_PUSH,
|
||||
DOMAIN,
|
||||
)
|
||||
from .gateway import ConnectMotionGateway
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema(
|
||||
|
@ -14,11 +25,34 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
}
|
||||
)
|
||||
|
||||
CONFIG_SETTINGS = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_API_KEY): vol.All(str, vol.Length(min=16, max=16)),
|
||||
}
|
||||
)
|
||||
|
||||
class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
"""Options for the component."""
|
||||
|
||||
def __init__(self, config_entry: config_entries.ConfigEntry) -> None:
|
||||
"""Init object."""
|
||||
self.config_entry = config_entry
|
||||
|
||||
async def async_step_init(self, user_input=None):
|
||||
"""Manage the options."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
return self.async_create_entry(title="", data=user_input)
|
||||
|
||||
settings_schema = vol.Schema(
|
||||
{
|
||||
vol.Optional(
|
||||
CONF_WAIT_FOR_PUSH,
|
||||
default=self.config_entry.options.get(
|
||||
CONF_WAIT_FOR_PUSH, DEFAULT_WAIT_FOR_PUSH
|
||||
),
|
||||
): bool,
|
||||
}
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="init", data_schema=settings_schema, errors=errors
|
||||
)
|
||||
|
||||
|
||||
class MotionBlindsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
|
@ -30,6 +64,13 @@ class MotionBlindsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
"""Initialize the Motion Blinds flow."""
|
||||
self._host = None
|
||||
self._ips = []
|
||||
self._config_settings = None
|
||||
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(config_entry) -> OptionsFlowHandler:
|
||||
"""Get the options flow."""
|
||||
return OptionsFlowHandler(config_entry)
|
||||
|
||||
async def async_step_user(self, user_input=None):
|
||||
"""Handle a flow initialized by the user."""
|
||||
|
@ -70,8 +111,24 @@ class MotionBlindsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
async def async_step_connect(self, user_input=None):
|
||||
"""Connect to the Motion Gateway."""
|
||||
errors = {}
|
||||
if user_input is not None:
|
||||
key = user_input[CONF_API_KEY]
|
||||
multicast_interface = user_input[CONF_INTERFACE]
|
||||
|
||||
# check socket interface
|
||||
if multicast_interface != DEFAULT_INTERFACE:
|
||||
motion_multicast = AsyncMotionMulticast(interface=multicast_interface)
|
||||
try:
|
||||
await motion_multicast.Start_listen()
|
||||
motion_multicast.Stop_listen()
|
||||
except gaierror:
|
||||
errors[CONF_INTERFACE] = "invalid_interface"
|
||||
return self.async_show_form(
|
||||
step_id="connect",
|
||||
data_schema=self._config_settings,
|
||||
errors=errors,
|
||||
)
|
||||
|
||||
connect_gateway_class = ConnectMotionGateway(self.hass, multicast=None)
|
||||
if not await connect_gateway_class.async_connect_gateway(self._host, key):
|
||||
|
@ -85,7 +142,45 @@ class MotionBlindsFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
|
|||
|
||||
return self.async_create_entry(
|
||||
title=DEFAULT_GATEWAY_NAME,
|
||||
data={CONF_HOST: self._host, CONF_API_KEY: key},
|
||||
data={
|
||||
CONF_HOST: self._host,
|
||||
CONF_API_KEY: key,
|
||||
CONF_INTERFACE: multicast_interface,
|
||||
},
|
||||
)
|
||||
|
||||
return self.async_show_form(step_id="connect", data_schema=CONFIG_SETTINGS)
|
||||
(interfaces, default_interface) = await self.async_get_interfaces()
|
||||
|
||||
self._config_settings = vol.Schema(
|
||||
{
|
||||
vol.Required(CONF_API_KEY): vol.All(str, vol.Length(min=16, max=16)),
|
||||
vol.Optional(CONF_INTERFACE, default=default_interface): vol.In(
|
||||
interfaces
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
return self.async_show_form(
|
||||
step_id="connect", data_schema=self._config_settings, errors=errors
|
||||
)
|
||||
|
||||
async def async_get_interfaces(self):
|
||||
"""Get list of interface to use."""
|
||||
interfaces = [DEFAULT_INTERFACE]
|
||||
enabled_interfaces = []
|
||||
default_interface = DEFAULT_INTERFACE
|
||||
|
||||
adapters = await network.async_get_adapters(self.hass)
|
||||
for adapter in adapters:
|
||||
if ipv4s := adapter["ipv4"]:
|
||||
ip4 = ipv4s[0]["address"]
|
||||
interfaces.append(ip4)
|
||||
if adapter["enabled"]:
|
||||
enabled_interfaces.append(ip4)
|
||||
if adapter["default"]:
|
||||
default_interface = ip4
|
||||
|
||||
if len(enabled_interfaces) == 1:
|
||||
default_interface = enabled_interfaces[0]
|
||||
|
||||
return (interfaces, default_interface)
|
||||
|
|
|
@ -5,6 +5,11 @@ DEFAULT_GATEWAY_NAME = "Motion Blinds Gateway"
|
|||
|
||||
PLATFORMS = ["cover", "sensor"]
|
||||
|
||||
CONF_WAIT_FOR_PUSH = "wait_for_push"
|
||||
CONF_INTERFACE = "interface"
|
||||
DEFAULT_WAIT_FOR_PUSH = False
|
||||
DEFAULT_INTERFACE = "any"
|
||||
|
||||
KEY_GATEWAY = "gateway"
|
||||
KEY_COORDINATOR = "coordinator"
|
||||
KEY_MULTICAST_LISTENER = "multicast_listener"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"config_flow": true,
|
||||
"documentation": "https://www.home-assistant.io/integrations/motion_blinds",
|
||||
"requirements": ["motionblinds==0.5.7"],
|
||||
"dependencies": ["network"],
|
||||
"codeowners": ["@starkillerOG"],
|
||||
"iot_class": "local_push"
|
||||
}
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
"title": "Motion Blinds",
|
||||
"description": "You will need the 16 character API Key, see https://www.home-assistant.io/integrations/motion_blinds/#retrieving-the-key for instructions",
|
||||
"data": {
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]"
|
||||
"api_key": "[%key:common::config_flow::data::api_key%]",
|
||||
"interface": "The network interface to use"
|
||||
}
|
||||
},
|
||||
"select": {
|
||||
|
@ -24,13 +25,25 @@
|
|||
}
|
||||
},
|
||||
"error": {
|
||||
"discovery_error": "Failed to discover a Motion Gateway"
|
||||
"discovery_error": "Failed to discover a Motion Gateway",
|
||||
"invalid_interface": "Invalid network interface"
|
||||
},
|
||||
"abort": {
|
||||
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
|
||||
"already_in_progress": "[%key:common::config_flow::abort::already_in_progress%]",
|
||||
"connection_error": "[%key:common::config_flow::error::cannot_connect%]"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Motion Blinds",
|
||||
"description": "Specify optional settings",
|
||||
"data": {
|
||||
"wait_for_push": "Wait for multicast push on update"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,13 +6,15 @@
|
|||
"connection_error": "Failed to connect"
|
||||
},
|
||||
"error": {
|
||||
"discovery_error": "Failed to discover a Motion Gateway"
|
||||
"discovery_error": "Failed to discover a Motion Gateway",
|
||||
"invalid_interface": "Invalid network interface"
|
||||
},
|
||||
"flow_title": "Motion Blinds",
|
||||
"step": {
|
||||
"connect": {
|
||||
"data": {
|
||||
"api_key": "API Key"
|
||||
"api_key": "API Key",
|
||||
"interface": "The network interface to use"
|
||||
},
|
||||
"description": "You will need the 16 character API Key, see https://www.home-assistant.io/integrations/motion_blinds/#retrieving-the-key for instructions",
|
||||
"title": "Motion Blinds"
|
||||
|
@ -33,5 +35,16 @@
|
|||
"title": "Motion Blinds"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"init": {
|
||||
"title": "Motion Blinds",
|
||||
"description": "Specify optional settings",
|
||||
"data": {
|
||||
"wait_for_push": "Wait for multicast push on update"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,13 +4,16 @@ from unittest.mock import Mock, patch
|
|||
|
||||
import pytest
|
||||
|
||||
from homeassistant import config_entries
|
||||
from homeassistant import config_entries, data_entry_flow
|
||||
from homeassistant.components.motion_blinds import const
|
||||
from homeassistant.components.motion_blinds.config_flow import DEFAULT_GATEWAY_NAME
|
||||
from homeassistant.components.motion_blinds.const import DOMAIN
|
||||
from homeassistant.const import CONF_API_KEY, CONF_HOST
|
||||
|
||||
from tests.common import MockConfigEntry
|
||||
|
||||
TEST_HOST = "1.2.3.4"
|
||||
TEST_HOST2 = "5.6.7.8"
|
||||
TEST_HOST_HA = "9.10.11.12"
|
||||
TEST_API_KEY = "12ab345c-d67e-8f"
|
||||
TEST_MAC = "ab:cd:ef:gh"
|
||||
TEST_MAC2 = "ij:kl:mn:op"
|
||||
|
@ -56,9 +59,13 @@ TEST_DISCOVERY_2 = {
|
|||
},
|
||||
}
|
||||
|
||||
TEST_INTERFACES = [
|
||||
{"enabled": True, "default": True, "ipv4": [{"address": TEST_HOST_HA}]}
|
||||
]
|
||||
|
||||
|
||||
@pytest.fixture(name="motion_blinds_connect", autouse=True)
|
||||
def motion_blinds_connect_fixture():
|
||||
def motion_blinds_connect_fixture(mock_get_source_ip):
|
||||
"""Mock motion blinds connection and entry setup."""
|
||||
with patch(
|
||||
"homeassistant.components.motion_blinds.gateway.MotionGateway.GetDeviceList",
|
||||
|
@ -72,6 +79,15 @@ def motion_blinds_connect_fixture():
|
|||
), patch(
|
||||
"homeassistant.components.motion_blinds.config_flow.MotionDiscovery.discover",
|
||||
return_value=TEST_DISCOVERY_1,
|
||||
), patch(
|
||||
"homeassistant.components.motion_blinds.config_flow.AsyncMotionMulticast.Start_listen",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.motion_blinds.config_flow.AsyncMotionMulticast.Stop_listen",
|
||||
return_value=True,
|
||||
), patch(
|
||||
"homeassistant.components.motion_blinds.config_flow.network.async_get_adapters",
|
||||
return_value=TEST_INTERFACES,
|
||||
), patch(
|
||||
"homeassistant.components.motion_blinds.async_setup_entry", return_value=True
|
||||
):
|
||||
|
@ -81,7 +97,7 @@ def motion_blinds_connect_fixture():
|
|||
async def test_config_flow_manual_host_success(hass):
|
||||
"""Successful flow manually initialized by the user."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
|
@ -95,7 +111,7 @@ async def test_config_flow_manual_host_success(hass):
|
|||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] is None
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
|
@ -107,13 +123,14 @@ async def test_config_flow_manual_host_success(hass):
|
|||
assert result["data"] == {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_API_KEY: TEST_API_KEY,
|
||||
const.CONF_INTERFACE: TEST_HOST_HA,
|
||||
}
|
||||
|
||||
|
||||
async def test_config_flow_discovery_1_success(hass):
|
||||
"""Successful flow with 1 gateway discovered."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
|
@ -127,7 +144,7 @@ async def test_config_flow_discovery_1_success(hass):
|
|||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] is None
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
|
@ -139,13 +156,14 @@ async def test_config_flow_discovery_1_success(hass):
|
|||
assert result["data"] == {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_API_KEY: TEST_API_KEY,
|
||||
const.CONF_INTERFACE: TEST_HOST_HA,
|
||||
}
|
||||
|
||||
|
||||
async def test_config_flow_discovery_2_success(hass):
|
||||
"""Successful flow with 2 gateway discovered."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
|
@ -176,7 +194,7 @@ async def test_config_flow_discovery_2_success(hass):
|
|||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] is None
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
|
@ -188,13 +206,14 @@ async def test_config_flow_discovery_2_success(hass):
|
|||
assert result["data"] == {
|
||||
CONF_HOST: TEST_HOST2,
|
||||
CONF_API_KEY: TEST_API_KEY,
|
||||
const.CONF_INTERFACE: TEST_HOST_HA,
|
||||
}
|
||||
|
||||
|
||||
async def test_config_flow_connection_error(hass):
|
||||
"""Failed flow manually initialized by the user with connection timeout."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
|
@ -208,7 +227,7 @@ async def test_config_flow_connection_error(hass):
|
|||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] is None
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.motion_blinds.gateway.MotionGateway.GetDeviceList",
|
||||
|
@ -226,7 +245,7 @@ async def test_config_flow_connection_error(hass):
|
|||
async def test_config_flow_discovery_fail(hass):
|
||||
"""Failed flow with no gateways discovered."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
|
@ -245,3 +264,101 @@ async def test_config_flow_discovery_fail(hass):
|
|||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {"base": "discovery_error"}
|
||||
|
||||
|
||||
async def test_config_flow_interface(hass):
|
||||
"""Successful flow manually initialized by the user with interface specified."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_HOST: TEST_HOST},
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_API_KEY: TEST_API_KEY, const.CONF_INTERFACE: TEST_HOST_HA},
|
||||
)
|
||||
|
||||
assert result["type"] == "create_entry"
|
||||
assert result["title"] == DEFAULT_GATEWAY_NAME
|
||||
assert result["data"] == {
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_API_KEY: TEST_API_KEY,
|
||||
const.CONF_INTERFACE: TEST_HOST_HA,
|
||||
}
|
||||
|
||||
|
||||
async def test_config_flow_invalid_interface(hass):
|
||||
"""Failed flow manually initialized by the user with invalid interface."""
|
||||
result = await hass.config_entries.flow.async_init(
|
||||
const.DOMAIN, context={"source": config_entries.SOURCE_USER}
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "user"
|
||||
assert result["errors"] == {}
|
||||
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_HOST: TEST_HOST},
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] == {}
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.motion_blinds.config_flow.AsyncMotionMulticast.Start_listen",
|
||||
side_effect=socket.gaierror,
|
||||
):
|
||||
result = await hass.config_entries.flow.async_configure(
|
||||
result["flow_id"],
|
||||
{CONF_API_KEY: TEST_API_KEY, const.CONF_INTERFACE: TEST_HOST_HA},
|
||||
)
|
||||
|
||||
assert result["type"] == "form"
|
||||
assert result["step_id"] == "connect"
|
||||
assert result["errors"] == {const.CONF_INTERFACE: "invalid_interface"}
|
||||
|
||||
|
||||
async def test_options_flow(hass):
|
||||
"""Test specifying non default settings using options flow."""
|
||||
config_entry = MockConfigEntry(
|
||||
domain=const.DOMAIN,
|
||||
unique_id=TEST_MAC,
|
||||
data={
|
||||
CONF_HOST: TEST_HOST,
|
||||
CONF_API_KEY: TEST_API_KEY,
|
||||
},
|
||||
title=DEFAULT_GATEWAY_NAME,
|
||||
)
|
||||
config_entry.add_to_hass(hass)
|
||||
|
||||
assert await hass.config_entries.async_setup(config_entry.entry_id)
|
||||
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"] == "init"
|
||||
|
||||
result = await hass.config_entries.options.async_configure(
|
||||
result["flow_id"],
|
||||
user_input={const.CONF_WAIT_FOR_PUSH: False},
|
||||
)
|
||||
|
||||
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
|
||||
assert config_entry.options == {
|
||||
const.CONF_WAIT_FOR_PUSH: False,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue