Remove YAML configuration from Verisure (#50076)

pull/50113/head
Franck Nijhof 2021-05-05 09:51:05 +02:00 committed by GitHub
parent b7cd75b134
commit 26b5a067bd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 4 additions and 319 deletions

View File

@ -3,9 +3,6 @@ from __future__ import annotations
from contextlib import suppress
import os
from typing import Any
import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
@ -15,27 +12,14 @@ from homeassistant.components.camera import DOMAIN as CAMERA_DOMAIN
from homeassistant.components.lock import DOMAIN as LOCK_DOMAIN
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
CONF_EMAIL,
CONF_PASSWORD,
CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.storage import STORAGE_DIR
from .const import (
CONF_CODE_DIGITS,
CONF_DEFAULT_LOCK_CODE,
CONF_GIID,
CONF_LOCK_CODE_DIGITS,
CONF_LOCK_DEFAULT_CODE,
DEFAULT_LOCK_CODE_DIGITS,
DOMAIN,
)
from .const import DOMAIN
from .coordinator import VerisureDataUpdateCoordinator
PLATFORMS = [
@ -47,80 +31,11 @@ PLATFORMS = [
SWITCH_DOMAIN,
]
CONFIG_SCHEMA = vol.Schema(
vol.All(
cv.deprecated(DOMAIN),
{
DOMAIN: vol.Schema(
{
vol.Required(CONF_PASSWORD): cv.string,
vol.Required(CONF_USERNAME): cv.string,
vol.Optional(CONF_CODE_DIGITS): cv.positive_int,
vol.Optional(CONF_GIID): cv.string,
vol.Optional(CONF_DEFAULT_LOCK_CODE): cv.string,
},
extra=vol.ALLOW_EXTRA,
)
},
),
extra=vol.ALLOW_EXTRA,
)
async def async_setup(hass: HomeAssistant, config: dict[str, Any]) -> bool:
"""Set up the Verisure integration."""
if DOMAIN in config:
hass.async_create_task(
hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_IMPORT},
data={
CONF_EMAIL: config[DOMAIN][CONF_USERNAME],
CONF_PASSWORD: config[DOMAIN][CONF_PASSWORD],
CONF_GIID: config[DOMAIN].get(CONF_GIID),
CONF_LOCK_CODE_DIGITS: config[DOMAIN].get(CONF_CODE_DIGITS),
CONF_LOCK_DEFAULT_CODE: config[DOMAIN].get(CONF_LOCK_DEFAULT_CODE),
},
)
)
return True
CONFIG_SCHEMA = cv.deprecated(DOMAIN)
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up Verisure from a config entry."""
# Migrate old YAML settings (hidden in the config entry),
# to config entry options. Can be removed after YAML support is gone.
if CONF_LOCK_CODE_DIGITS in entry.data or CONF_DEFAULT_LOCK_CODE in entry.data:
options = entry.options.copy()
if (
CONF_LOCK_CODE_DIGITS in entry.data
and CONF_LOCK_CODE_DIGITS not in entry.options
and entry.data[CONF_LOCK_CODE_DIGITS] != DEFAULT_LOCK_CODE_DIGITS
):
options.update(
{
CONF_LOCK_CODE_DIGITS: entry.data[CONF_LOCK_CODE_DIGITS],
}
)
if (
CONF_DEFAULT_LOCK_CODE in entry.data
and CONF_DEFAULT_LOCK_CODE not in entry.options
):
options.update(
{
CONF_DEFAULT_LOCK_CODE: entry.data[CONF_DEFAULT_LOCK_CODE],
}
)
data = entry.data.copy()
data.pop(CONF_LOCK_CODE_DIGITS, None)
data.pop(CONF_DEFAULT_LOCK_CODE, None)
hass.config_entries.async_update_entry(entry, data=data, options=options)
# Continue as normal...
coordinator = VerisureDataUpdateCoordinator(hass, entry=entry)
if not await coordinator.async_login():

View File

@ -36,14 +36,6 @@ class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
installations: dict[str, str]
password: str
# These can be removed after YAML import has been removed.
giid: str | None = None
settings: dict[str, int | str]
def __init__(self):
"""Initialize."""
self.settings = {}
@staticmethod
@callback
def async_get_options_flow(config_entry: ConfigEntry) -> VerisureOptionsFlowHandler:
@ -95,8 +87,6 @@ class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
"""Select Verisure installation to add."""
if len(self.installations) == 1:
user_input = {CONF_GIID: list(self.installations)[0]}
elif self.giid and self.giid in self.installations:
user_input = {CONF_GIID: self.giid}
if user_input is None:
return self.async_show_form(
@ -115,7 +105,6 @@ class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
CONF_EMAIL: self.email,
CONF_PASSWORD: self.password,
CONF_GIID: user_input[CONF_GIID],
**self.settings,
},
)
@ -168,26 +157,6 @@ class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
errors=errors,
)
async def async_step_import(self, user_input: dict[str, Any]) -> FlowResult:
"""Import Verisure YAML configuration."""
if user_input[CONF_GIID]:
self.giid = user_input[CONF_GIID]
await self.async_set_unique_id(self.giid)
self._abort_if_unique_id_configured()
else:
# The old YAML configuration could handle 1 single Verisure instance.
# Therefore, if we don't know the GIID, we can use the discovery
# without a unique ID logic, to prevent re-import/discovery.
await self._async_handle_discovery_without_unique_id()
# Settings, later to be converted to config entry options
if user_input[CONF_LOCK_CODE_DIGITS]:
self.settings[CONF_LOCK_CODE_DIGITS] = user_input[CONF_LOCK_CODE_DIGITS]
if user_input[CONF_LOCK_DEFAULT_CODE]:
self.settings[CONF_LOCK_DEFAULT_CODE] = user_input[CONF_LOCK_DEFAULT_CODE]
return await self.async_step_user(user_input)
class VerisureOptionsFlowHandler(OptionsFlow):
"""Handle Verisure options."""

View File

@ -44,7 +44,3 @@ ALARM_STATE_TO_HA = {
"ARMED_AWAY": STATE_ALARM_ARMED_AWAY,
"PENDING": STATE_ALARM_PENDING,
}
# Legacy; to remove after YAML removal
CONF_CODE_DIGITS = "code_digits"
CONF_DEFAULT_LOCK_CODE = "default_lock_code"

View File

@ -44,8 +44,6 @@ async def test_full_user_flow_single_installation(hass: HomeAssistant) -> None:
with patch(
"homeassistant.components.verisure.config_flow.Verisure",
) as mock_verisure, patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
@ -72,7 +70,6 @@ async def test_full_user_flow_single_installation(hass: HomeAssistant) -> None:
}
assert len(mock_verisure.mock_calls) == 2
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@ -107,8 +104,6 @@ async def test_full_user_flow_multiple_installations(hass: HomeAssistant) -> Non
assert result2["errors"] is None
with patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
@ -126,7 +121,6 @@ async def test_full_user_flow_multiple_installations(hass: HomeAssistant) -> Non
}
assert len(mock_verisure.mock_calls) == 2
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@ -220,8 +214,6 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
"homeassistant.components.verisure.config_flow.Verisure.login",
return_value=True,
) as mock_verisure, patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
@ -243,7 +235,6 @@ async def test_reauth_flow(hass: HomeAssistant) -> None:
}
assert len(mock_verisure.mock_calls) == 1
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@ -365,8 +356,6 @@ async def test_options_flow(
entry.add_to_hass(hass)
with patch(
"homeassistant.components.verisure.async_setup", return_value=True
), patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
):
@ -397,8 +386,6 @@ async def test_options_flow_code_format_mismatch(hass: HomeAssistant) -> None:
entry.add_to_hass(hass)
with patch(
"homeassistant.components.verisure.async_setup", return_value=True
), patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
):
@ -422,185 +409,3 @@ async def test_options_flow_code_format_mismatch(hass: HomeAssistant) -> None:
assert result["type"] == RESULT_TYPE_FORM
assert result["step_id"] == "init"
assert result["errors"] == {"base": "code_format_mismatch"}
#
# Below this line are tests that can be removed once the YAML configuration
# has been removed from this integration.
#
@pytest.mark.parametrize(
"giid,installations",
[
("12345", TEST_INSTALLATION),
("12345", TEST_INSTALLATIONS),
(None, TEST_INSTALLATION),
],
)
async def test_imports(
hass: HomeAssistant, giid: str | None, installations: dict[str, str]
) -> None:
"""Test a YAML import with/without known giid on single/multiple installations."""
with patch(
"homeassistant.components.verisure.config_flow.Verisure",
) as mock_verisure, patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
type(mock_verisure.return_value).installations = PropertyMock(
return_value=installations
)
mock_verisure.login.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_GIID: giid,
CONF_LOCK_CODE_DIGITS: 10,
CONF_LOCK_DEFAULT_CODE: "123456",
CONF_PASSWORD: "SuperS3cr3t!",
},
)
assert result["type"] == RESULT_TYPE_CREATE_ENTRY
assert result["title"] == "ascending (12345th street)"
assert result["data"] == {
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_GIID: "12345",
CONF_LOCK_CODE_DIGITS: 10,
CONF_LOCK_DEFAULT_CODE: "123456",
CONF_PASSWORD: "SuperS3cr3t!",
}
assert len(mock_verisure.mock_calls) == 2
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_imports_invalid_login(hass: HomeAssistant) -> None:
"""Test a YAML import that results in a invalid login."""
with patch(
"homeassistant.components.verisure.config_flow.Verisure.login",
side_effect=VerisureLoginError,
):
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_GIID: None,
CONF_LOCK_CODE_DIGITS: None,
CONF_LOCK_DEFAULT_CODE: None,
CONF_PASSWORD: "SuperS3cr3t!",
},
)
assert result["step_id"] == "user"
assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] == {"base": "invalid_auth"}
with patch(
"homeassistant.components.verisure.config_flow.Verisure",
) as mock_verisure, patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
type(mock_verisure.return_value).installations = PropertyMock(
return_value=TEST_INSTALLATION
)
mock_verisure.login.return_value = True
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"],
{
"email": "verisure_my_pages@example.com",
"password": "SuperS3cr3t!",
},
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
assert result2["title"] == "ascending (12345th street)"
assert result2["data"] == {
CONF_GIID: "12345",
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_PASSWORD: "SuperS3cr3t!",
}
assert len(mock_verisure.mock_calls) == 2
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
async def test_imports_needs_user_installation_choice(hass: HomeAssistant) -> None:
"""Test a YAML import that needs to use to decide on the installation."""
with patch(
"homeassistant.components.verisure.config_flow.Verisure",
) as mock_verisure:
type(mock_verisure.return_value).installations = PropertyMock(
return_value=TEST_INSTALLATIONS
)
mock_verisure.login.return_value = True
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_GIID: None,
CONF_LOCK_CODE_DIGITS: None,
CONF_LOCK_DEFAULT_CODE: None,
CONF_PASSWORD: "SuperS3cr3t!",
},
)
assert result["step_id"] == "installation"
assert result["type"] == RESULT_TYPE_FORM
assert result["errors"] is None
with patch(
"homeassistant.components.verisure.async_setup", return_value=True
) as mock_setup, patch(
"homeassistant.components.verisure.async_setup_entry",
return_value=True,
) as mock_setup_entry:
result2 = await hass.config_entries.flow.async_configure(
result["flow_id"], {"giid": "12345"}
)
await hass.async_block_till_done()
assert result2["type"] == RESULT_TYPE_CREATE_ENTRY
assert result2["title"] == "ascending (12345th street)"
assert result2["data"] == {
CONF_GIID: "12345",
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_PASSWORD: "SuperS3cr3t!",
}
assert len(mock_verisure.mock_calls) == 2
assert len(mock_setup.mock_calls) == 1
assert len(mock_setup_entry.mock_calls) == 1
@pytest.mark.parametrize("giid", ["12345", None])
async def test_import_already_exists(hass: HomeAssistant, giid: str | None) -> None:
"""Test that import flow aborts if exists."""
MockConfigEntry(domain=DOMAIN, data={}, unique_id="12345").add_to_hass(hass)
result = await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": config_entries.SOURCE_IMPORT},
data={
CONF_EMAIL: "verisure_my_pages@example.com",
CONF_PASSWORD: "SuperS3cr3t!",
CONF_GIID: giid,
},
)
assert result["type"] == RESULT_TYPE_ABORT
assert result["reason"] == "already_configured"