From cdb6161d3dde94c22266a99547d5652ad8946dc2 Mon Sep 17 00:00:00 2001 From: On Freund Date: Sat, 22 Aug 2020 20:15:03 +0300 Subject: [PATCH] Add risco options flow (#39154) --- homeassistant/components/risco/__init__.py | 27 ++++++++++--- homeassistant/components/risco/config_flow.py | 38 ++++++++++++++++++- homeassistant/components/risco/const.py | 2 + homeassistant/components/risco/strings.json | 10 +++++ tests/components/risco/test_config_flow.py | 27 ++++++++++++- 5 files changed, 94 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/risco/__init__.py b/homeassistant/components/risco/__init__.py index d620e2c1c68..e3e59229bf5 100644 --- a/homeassistant/components/risco/__init__.py +++ b/homeassistant/components/risco/__init__.py @@ -6,16 +6,21 @@ import logging from pyrisco import CannotConnectError, OperationError, RiscoAPI, UnauthorizedError from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_PASSWORD, CONF_PIN, CONF_USERNAME +from homeassistant.const import ( + CONF_PASSWORD, + CONF_PIN, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers.aiohttp_client import async_get_clientsession from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import DATA_COORDINATOR, DOMAIN +from .const import DATA_COORDINATOR, DEFAULT_SCAN_INTERVAL, DOMAIN PLATFORMS = ["alarm_control_panel"] - +UNDO_UPDATE_LISTENER = "undo_update_listener" _LOGGER = logging.getLogger(__name__) @@ -38,11 +43,15 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): _LOGGER.exception("Failed to login to Risco cloud") return False - coordinator = RiscoDataUpdateCoordinator(hass, risco) + scan_interval = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL) + coordinator = RiscoDataUpdateCoordinator(hass, risco, scan_interval) await coordinator.async_refresh() + undo_listener = entry.add_update_listener(_update_listener) + hass.data[DOMAIN][entry.entry_id] = { DATA_COORDINATOR: coordinator, + UNDO_UPDATE_LISTENER: undo_listener, } for component in PLATFORMS: @@ -65,18 +74,24 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry): ) if unload_ok: + hass.data[DOMAIN][entry.entry_id][UNDO_UPDATE_LISTENER]() hass.data[DOMAIN].pop(entry.entry_id) return unload_ok +async def _update_listener(hass: HomeAssistant, entry: ConfigEntry): + """Handle options update.""" + await hass.config_entries.async_reload(entry.entry_id) + + class RiscoDataUpdateCoordinator(DataUpdateCoordinator): """Class to manage fetching risco data.""" - def __init__(self, hass, risco): + def __init__(self, hass, risco, scan_interval): """Initialize global risco data updater.""" self.risco = risco - interval = timedelta(seconds=30) + interval = timedelta(seconds=scan_interval) super().__init__( hass, _LOGGER, name=DOMAIN, update_interval=interval, ) diff --git a/homeassistant/components/risco/config_flow.py b/homeassistant/components/risco/config_flow.py index 43fb75343cb..af2df0ca577 100644 --- a/homeassistant/components/risco/config_flow.py +++ b/homeassistant/components/risco/config_flow.py @@ -5,10 +5,15 @@ from pyrisco import CannotConnectError, RiscoAPI, UnauthorizedError import voluptuous as vol from homeassistant import config_entries, core -from homeassistant.const import CONF_PASSWORD, CONF_PIN, CONF_USERNAME +from homeassistant.const import ( + CONF_PASSWORD, + CONF_PIN, + CONF_SCAN_INTERVAL, + CONF_USERNAME, +) from homeassistant.helpers.aiohttp_client import async_get_clientsession -from .const import DOMAIN # pylint:disable=unused-import +from .const import DEFAULT_SCAN_INTERVAL, DOMAIN # pylint:disable=unused-import _LOGGER = logging.getLogger(__name__) @@ -37,6 +42,12 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): VERSION = 1 CONNECTION_CLASS = config_entries.CONN_CLASS_CLOUD_POLL + @staticmethod + @core.callback + def async_get_options_flow(config_entry): + """Define the config flow to handle options.""" + return RiscoOptionsFlowHandler(config_entry) + async def async_step_user(self, user_input=None): """Handle the initial step.""" errors = {} @@ -59,3 +70,26 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): return self.async_show_form( step_id="user", data_schema=DATA_SCHEMA, errors=errors ) + + +class RiscoOptionsFlowHandler(config_entries.OptionsFlow): + """Handle a Risco options flow.""" + + def __init__(self, config_entry): + """Initialize.""" + self.config_entry = config_entry + + async def async_step_init(self, user_input=None): + """Manage the options.""" + if user_input is not None: + return self.async_create_entry( + title="", data={CONF_SCAN_INTERVAL: user_input[CONF_SCAN_INTERVAL]} + ) + + current = self.config_entry.options.get( + CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL + ) + + options = vol.Schema({vol.Required(CONF_SCAN_INTERVAL, default=current): int}) + + return self.async_show_form(step_id="init", data_schema=options) diff --git a/homeassistant/components/risco/const.py b/homeassistant/components/risco/const.py index 7fa85227fe1..0beb3b491db 100644 --- a/homeassistant/components/risco/const.py +++ b/homeassistant/components/risco/const.py @@ -3,3 +3,5 @@ DOMAIN = "risco" DATA_COORDINATOR = "risco" + +DEFAULT_SCAN_INTERVAL = 30 diff --git a/homeassistant/components/risco/strings.json b/homeassistant/components/risco/strings.json index a2ce75a9d74..839f4d67251 100644 --- a/homeassistant/components/risco/strings.json +++ b/homeassistant/components/risco/strings.json @@ -17,5 +17,15 @@ "abort": { "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" } + }, + "options": { + "step": { + "init": { + "title": "Configure options", + "data": { + "scan_interval": "How often to poll Risco (in seconds)" + } + } + } } } \ No newline at end of file diff --git a/tests/components/risco/test_config_flow.py b/tests/components/risco/test_config_flow.py index 259f5dfe15d..a3540fd1b1e 100644 --- a/tests/components/risco/test_config_flow.py +++ b/tests/components/risco/test_config_flow.py @@ -1,5 +1,5 @@ """Test the Risco config flow.""" -from homeassistant import config_entries +from homeassistant import config_entries, data_entry_flow from homeassistant.components.risco.config_flow import ( CannotConnectError, UnauthorizedError, @@ -114,7 +114,6 @@ async def test_form_already_exists(hass): ) 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_USER} @@ -126,3 +125,27 @@ async def test_form_already_exists(hass): assert result2["type"] == "abort" assert result2["reason"] == "already_configured" + + +async def test_options_flow(hass): + """Test options flow.""" + conf = {"scan_interval": 10} + + entry = MockConfigEntry( + domain=DOMAIN, unique_id=TEST_DATA["username"], data=TEST_DATA, + ) + + entry.add_to_hass(hass) + + with patch("homeassistant.components.risco.async_setup_entry", return_value=True): + result = await hass.config_entries.options.async_init(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=conf, + ) + + assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY + assert entry.options == conf