Add TotalConnect options flow to auto-bypass low battery (#62458)

* rebase

* use bypass option in async_setup_entry

* add test for options flow

* default to False for AUTO_BYPASS

* fix bypass defaults
pull/72493/head
Austin Mroczek 2022-05-25 01:49:53 -07:00 committed by GitHub
parent 53fb581bff
commit 5b896b315e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 4 deletions

View File

@ -17,7 +17,7 @@ from homeassistant.exceptions import ConfigEntryAuthFailed
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import CONF_USERCODES, DOMAIN
from .const import AUTO_BYPASS, CONF_USERCODES, DOMAIN
PLATFORMS = [Platform.ALARM_CONTROL_PANEL, Platform.BINARY_SENSOR]
@ -31,6 +31,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
conf = entry.data
username = conf[CONF_USERNAME]
password = conf[CONF_PASSWORD]
bypass = entry.options.get(AUTO_BYPASS, False)
if CONF_USERCODES not in conf:
# should only happen for those who used UI before we added usercodes
@ -41,7 +42,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
try:
client = await hass.async_add_executor_job(
TotalConnectClient, username, password, usercodes
TotalConnectClient, username, password, usercodes, bypass
)
except AuthenticationError as exception:
raise ConfigEntryAuthFailed(
@ -54,6 +55,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = coordinator
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(update_listener))
return True
@ -66,6 +70,14 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
return unload_ok
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Update listener."""
bypass = entry.options.get(AUTO_BYPASS, False)
client = hass.data[DOMAIN][entry.entry_id].client
for location_id in client.locations:
client.locations[location_id].auto_bypass_low_battery = bypass
class TotalConnectDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to fetch data from TotalConnect."""

View File

@ -5,8 +5,9 @@ import voluptuous as vol
from homeassistant import config_entries
from homeassistant.const import CONF_LOCATION, CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import callback
from .const import CONF_USERCODES, DOMAIN
from .const import AUTO_BYPASS, CONF_USERCODES, DOMAIN
PASSWORD_DATA_SCHEMA = vol.Schema({vol.Required(CONF_PASSWORD): str})
@ -162,3 +163,34 @@ class TotalConnectConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
)
return self.async_abort(reason="reauth_successful")
@staticmethod
@callback
def async_get_options_flow(config_entry):
"""Get options flow."""
return TotalConnectOptionsFlowHandler(config_entry)
class TotalConnectOptionsFlowHandler(config_entries.OptionsFlow):
"""TotalConnect options flow handler."""
def __init__(self, config_entry):
"""Initialize options flow."""
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.Required(
AUTO_BYPASS,
default=self.config_entry.options.get(AUTO_BYPASS, False),
): bool
}
),
)

View File

@ -2,6 +2,8 @@
DOMAIN = "totalconnect"
CONF_USERCODES = "usercodes"
CONF_LOCATION = "location"
AUTO_BYPASS = "auto_bypass_low_battery"
# Most TotalConnect alarms will work passing '-1' as usercode
DEFAULT_USERCODE = "-1"

View File

@ -28,5 +28,16 @@
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]",
"no_locations": "No locations are available for this user, check TotalConnect settings"
}
},
"options": {
"step": {
"init": {
"title": "TotalConnect Options",
"description": "Automatically bypass zones the moment they report a low battery.",
"data": {
"auto_bypass_low_battery": "Auto bypass low battery"
}
}
}
}
}

View File

@ -4,9 +4,14 @@ from unittest.mock import patch
from total_connect_client.exceptions import AuthenticationError
from homeassistant import data_entry_flow
from homeassistant.components.totalconnect.const import CONF_USERCODES, DOMAIN
from homeassistant.components.totalconnect.const import (
AUTO_BYPASS,
CONF_USERCODES,
DOMAIN,
)
from homeassistant.config_entries import SOURCE_REAUTH, SOURCE_USER
from homeassistant.const import CONF_PASSWORD
from homeassistant.core import HomeAssistant
from .common import (
CONFIG_DATA,
@ -190,3 +195,42 @@ async def test_no_locations(hass):
await hass.async_block_till_done()
assert mock_request.call_count == 1
async def test_options_flow(hass: HomeAssistant):
"""Test config flow options."""
config_entry = MockConfigEntry(
domain=DOMAIN,
data=CONFIG_DATA,
unique_id=USERNAME,
)
config_entry.add_to_hass(hass)
responses = [
RESPONSE_AUTHENTICATE,
RESPONSE_PARTITION_DETAILS,
RESPONSE_GET_ZONE_DETAILS_SUCCESS,
RESPONSE_DISARMED,
RESPONSE_DISARMED,
RESPONSE_DISARMED,
]
with patch(TOTALCONNECT_REQUEST, side_effect=responses):
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={AUTO_BYPASS: True}
)
assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY
assert config_entry.options == {AUTO_BYPASS: True}
await hass.async_block_till_done()
assert await hass.config_entries.async_unload(config_entry.entry_id)
await hass.async_block_till_done()