Add options flow to RainMachine (#42241)

* Add options flow to RainMachine

* Linting
This commit is contained in:
Aaron Bach 2020-10-28 15:52:42 -06:00 committed by GitHub
parent aef80263cd
commit e61e8fafee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 16 deletions

View File

@ -83,10 +83,21 @@ async def async_setup(hass, config):
async def async_setup_entry(hass, config_entry):
"""Set up RainMachine as config entry."""
entry_updates = {}
if not config_entry.unique_id:
hass.config_entries.async_update_entry(
config_entry, unique_id=config_entry.data[CONF_IP_ADDRESS]
)
# If the config entry doesn't already have a unique ID, set one:
entry_updates["unique_id"] = config_entry.data[CONF_IP_ADDRESS]
if CONF_ZONE_RUN_TIME in config_entry.data:
# If a zone run time exists in the config entry's data, pop it and move it to
# options:
data = {**config_entry.data}
entry_updates["data"] = data
entry_updates["options"] = {
**config_entry.options,
CONF_ZONE_RUN_TIME: data.pop(CONF_ZONE_RUN_TIME),
}
if entry_updates:
hass.config_entries.async_update_entry(config_entry, **entry_updates)
_verify_domain_control = verify_domain_control(hass, DOMAIN)
@ -107,12 +118,7 @@ async def async_setup_entry(hass, config_entry):
# regenmaschine can load multiple controllers at once, but we only grab the one
# we loaded above:
controller = next(iter(client.controllers.values()))
rainmachine = RainMachine(
hass,
controller,
config_entry.data.get(CONF_ZONE_RUN_TIME, DEFAULT_ZONE_RUN),
)
rainmachine = RainMachine(hass, config_entry, controller)
# Update the data object, which at this point (prior to any sensors registering
# "interest" in the API), will focus on grabbing the latest program and zone data:
@ -207,6 +213,8 @@ async def async_setup_entry(hass, config_entry):
]:
hass.services.async_register(DOMAIN, service, method, schema=schema)
config_entry.add_update_listener(async_reload_entry)
return True
@ -224,15 +232,20 @@ async def async_unload_entry(hass, config_entry):
return True
async def async_reload_entry(hass, config_entry):
"""Handle an options update."""
await hass.config_entries.async_reload(config_entry.entry_id)
class RainMachine:
"""Define a generic RainMachine object."""
def __init__(self, hass, controller, default_zone_runtime):
def __init__(self, hass, config_entry, controller):
"""Initialize."""
self._async_cancel_time_interval_listener = None
self.config_entry = config_entry
self.controller = controller
self.data = {}
self.default_zone_runtime = default_zone_runtime
self.device_mac = controller.mac
self.hass = hass

View File

@ -5,7 +5,8 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_PORT, CONF_SSL
from homeassistant.helpers import aiohttp_client
from homeassistant.core import callback
from homeassistant.helpers import aiohttp_client, config_validation as cv
from .const import ( # pylint: disable=unused-import
CONF_ZONE_RUN_TIME,
@ -39,6 +40,12 @@ class RainMachineFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
errors=errors if errors else {},
)
@staticmethod
@callback
def async_get_options_flow(config_entry):
"""Define the config flow to handle options."""
return RainMachineOptionsFlowHandler(config_entry)
async def async_step_user(self, user_input=None):
"""Handle the start of the config flow."""
if not user_input:
@ -75,3 +82,28 @@ class RainMachineFlowHandler(config_entries.ConfigFlow, domain=DOMAIN):
),
},
)
class RainMachineOptionsFlowHandler(config_entries.OptionsFlow):
"""Handle a RainMachine 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=user_input)
return self.async_show_form(
step_id="init",
data_schema=vol.Schema(
{
vol.Optional(
CONF_ZONE_RUN_TIME,
default=self.config_entry.options.get(CONF_ZONE_RUN_TIME),
): cv.positive_int
}
),
)

View File

@ -16,5 +16,15 @@
"abort": {
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
}
},
"options": {
"step": {
"init": {
"title": "Configure RainMachine",
"data": {
"zone_run_time": "Default zone run time (in seconds)"
}
}
}
}
}

View File

@ -11,6 +11,7 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
from . import RainMachineEntity
from .const import (
CONF_ZONE_RUN_TIME,
DATA_CLIENT,
DATA_PROGRAMS,
DATA_ZONES,
@ -268,7 +269,8 @@ class RainMachineZone(RainMachineSwitch):
"""Turn the zone on."""
await self._async_run_switch_coroutine(
self.rainmachine.controller.zones.start(
self._rainmachine_entity_id, self.rainmachine.default_zone_runtime
self._rainmachine_entity_id,
self.rainmachine.config_entry.options[CONF_ZONE_RUN_TIME],
)
)

View File

@ -4,9 +4,7 @@
"already_configured": "Device is already configured"
},
"error": {
"identifier_exists": "Account is already configured",
"invalid_auth": "Invalid authentication",
"invalid_credentials": "Invalid credentials"
"invalid_auth": "Invalid authentication"
},
"step": {
"user": {
@ -18,5 +16,15 @@
"title": "Fill in your information"
}
}
},
"options": {
"step": {
"init": {
"data": {
"zone_run_time": "Default zone run time (in seconds)"
},
"title": "Configure RainMachine"
}
}
}
}

View File

@ -51,6 +51,39 @@ async def test_invalid_password(hass):
assert result["errors"] == {CONF_PASSWORD: "invalid_auth"}
async def test_options_flow(hass):
"""Test config flow options."""
conf = {
CONF_IP_ADDRESS: "192.168.1.100",
CONF_PASSWORD: "password",
CONF_PORT: 8080,
CONF_SSL: True,
}
config_entry = MockConfigEntry(
domain=DOMAIN,
unique_id="abcde12345",
data=conf,
options={CONF_ZONE_RUN_TIME: 900},
)
config_entry.add_to_hass(hass)
with patch(
"homeassistant.components.rainmachine.async_setup_entry", return_value=True
):
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={CONF_ZONE_RUN_TIME: 600}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert config_entry.options == {CONF_ZONE_RUN_TIME: 600}
async def test_show_form(hass):
"""Test that the form is served with no input."""
flow = config_flow.RainMachineFlowHandler()