From a093c383c3cb92154dabb9c0fcd6c03da96ee397 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Mon, 14 Aug 2023 13:43:08 +0200 Subject: [PATCH] Remove Verisure default lock code (#94676) --- homeassistant/components/verisure/__init__.py | 32 ++++++- .../components/verisure/config_flow.py | 25 ++---- homeassistant/components/verisure/lock.py | 23 ++--- .../components/verisure/strings.json | 6 +- tests/components/verisure/conftest.py | 1 + tests/components/verisure/test_config_flow.py | 83 +------------------ 6 files changed, 51 insertions(+), 119 deletions(-) diff --git a/homeassistant/components/verisure/__init__.py b/homeassistant/components/verisure/__init__.py index 94e8d667d75..302bd23b66f 100644 --- a/homeassistant/components/verisure/__init__.py +++ b/homeassistant/components/verisure/__init__.py @@ -5,14 +5,16 @@ from contextlib import suppress import os from pathlib import Path +from homeassistant.components.lock import CONF_DEFAULT_CODE, DOMAIN as LOCK_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_EMAIL, Platform from homeassistant.core import HomeAssistant from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers import entity_registry as er import homeassistant.helpers.config_validation as cv from homeassistant.helpers.storage import STORAGE_DIR -from .const import DOMAIN +from .const import CONF_LOCK_DEFAULT_CODE, DOMAIN, LOGGER from .coordinator import VerisureDataUpdateCoordinator PLATFORMS = [ @@ -41,6 +43,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: hass.data.setdefault(DOMAIN, {}) hass.data[DOMAIN][entry.entry_id] = coordinator + # Migrate lock default code from config entry to lock entity + # Set up all platforms for this device/entry. await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @@ -72,3 +76,29 @@ def migrate_cookie_files(hass: HomeAssistant, entry: ConfigEntry) -> None: cookie_file.rename( hass.config.path(STORAGE_DIR, f"verisure_{entry.data[CONF_EMAIL]}") ) + + +async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: + """Migrate old entry.""" + LOGGER.debug("Migrating from version %s", entry.version) + + if entry.version == 1: + config_entry_default_code = entry.options.get(CONF_LOCK_DEFAULT_CODE) + entity_reg = er.async_get(hass) + entries = er.async_entries_for_config_entry(entity_reg, entry.entry_id) + for entity in entries: + if entity.entity_id.startswith("lock"): + entity_reg.async_update_entity_options( + entity.entity_id, + LOCK_DOMAIN, + {CONF_DEFAULT_CODE: config_entry_default_code}, + ) + new_options = entry.options.copy() + del new_options[CONF_LOCK_DEFAULT_CODE] + + entry.version = 2 + hass.config_entries.async_update_entry(entry, options=new_options) + + LOGGER.info("Migration to version %s successful", entry.version) + + return True diff --git a/homeassistant/components/verisure/config_flow.py b/homeassistant/components/verisure/config_flow.py index 1fcf0eb9de2..d945463fa5e 100644 --- a/homeassistant/components/verisure/config_flow.py +++ b/homeassistant/components/verisure/config_flow.py @@ -21,7 +21,6 @@ from homeassistant.helpers.storage import STORAGE_DIR from .const import ( CONF_GIID, CONF_LOCK_CODE_DIGITS, - CONF_LOCK_DEFAULT_CODE, DEFAULT_LOCK_CODE_DIGITS, DOMAIN, LOGGER, @@ -31,7 +30,7 @@ from .const import ( class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN): """Handle a config flow for Verisure.""" - VERSION = 1 + VERSION = 2 email: str entry: ConfigEntry @@ -306,16 +305,10 @@ class VerisureOptionsFlowHandler(OptionsFlow): self, user_input: dict[str, Any] | None = None ) -> FlowResult: """Manage Verisure options.""" - errors = {} + errors: dict[str, Any] = {} if user_input is not None: - if len(user_input[CONF_LOCK_DEFAULT_CODE]) not in [ - 0, - user_input[CONF_LOCK_CODE_DIGITS], - ]: - errors["base"] = "code_format_mismatch" - else: - return self.async_create_entry(title="", data=user_input) + return self.async_create_entry(data=user_input) return self.async_show_form( step_id="init", @@ -323,14 +316,12 @@ class VerisureOptionsFlowHandler(OptionsFlow): { vol.Optional( CONF_LOCK_CODE_DIGITS, - default=self.entry.options.get( - CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS - ), + description={ + "suggested_value": self.entry.options.get( + CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS + ) + }, ): int, - vol.Optional( - CONF_LOCK_DEFAULT_CODE, - default=self.entry.options.get(CONF_LOCK_DEFAULT_CODE, ""), - ): str, } ), errors=errors, diff --git a/homeassistant/components/verisure/lock.py b/homeassistant/components/verisure/lock.py index 94a27784e78..ad9590d2524 100644 --- a/homeassistant/components/verisure/lock.py +++ b/homeassistant/components/verisure/lock.py @@ -20,7 +20,6 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( CONF_GIID, CONF_LOCK_CODE_DIGITS, - CONF_LOCK_DEFAULT_CODE, DEFAULT_LOCK_CODE_DIGITS, DOMAIN, LOGGER, @@ -129,25 +128,15 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt async def async_unlock(self, **kwargs: Any) -> None: """Send unlock command.""" - code = kwargs.get( - ATTR_CODE, self.coordinator.entry.options.get(CONF_LOCK_DEFAULT_CODE) - ) - if code is None: - LOGGER.error("Code required but none provided") - return - - await self.async_set_lock_state(code, STATE_UNLOCKED) + code = kwargs.get(ATTR_CODE) + if code: + await self.async_set_lock_state(code, STATE_UNLOCKED) async def async_lock(self, **kwargs: Any) -> None: """Send lock command.""" - code = kwargs.get( - ATTR_CODE, self.coordinator.entry.options.get(CONF_LOCK_DEFAULT_CODE) - ) - if code is None: - LOGGER.error("Code required but none provided") - return - - await self.async_set_lock_state(code, STATE_LOCKED) + code = kwargs.get(ATTR_CODE) + if code: + await self.async_set_lock_state(code, STATE_LOCKED) async def async_set_lock_state(self, code: str, state: str) -> None: """Send set lock state command.""" diff --git a/homeassistant/components/verisure/strings.json b/homeassistant/components/verisure/strings.json index f715529b36b..051f17262a0 100644 --- a/homeassistant/components/verisure/strings.json +++ b/homeassistant/components/verisure/strings.json @@ -48,13 +48,9 @@ "step": { "init": { "data": { - "lock_code_digits": "Number of digits in PIN code for locks", - "lock_default_code": "Default PIN code for locks, used if none is given" + "lock_code_digits": "Number of digits in PIN code for locks" } } - }, - "error": { - "code_format_mismatch": "The default PIN code does not match the required number of digits" } }, "entity": { diff --git a/tests/components/verisure/conftest.py b/tests/components/verisure/conftest.py index 8ddc3a99815..8e1da712a5c 100644 --- a/tests/components/verisure/conftest.py +++ b/tests/components/verisure/conftest.py @@ -23,6 +23,7 @@ def mock_config_entry() -> MockConfigEntry: CONF_GIID: "12345", CONF_PASSWORD: "SuperS3cr3t!", }, + version=2, ) diff --git a/tests/components/verisure/test_config_flow.py b/tests/components/verisure/test_config_flow.py index af102cced98..94a0963fdf6 100644 --- a/tests/components/verisure/test_config_flow.py +++ b/tests/components/verisure/test_config_flow.py @@ -11,7 +11,6 @@ from homeassistant.components import dhcp from homeassistant.components.verisure.const import ( CONF_GIID, CONF_LOCK_CODE_DIGITS, - CONF_LOCK_DEFAULT_CODE, DEFAULT_LOCK_CODE_DIGITS, DOMAIN, ) @@ -561,48 +560,9 @@ async def test_reauth_flow_errors( assert len(mock_setup_entry.mock_calls) == 1 -@pytest.mark.parametrize( - ("input", "output"), - [ - ( - { - CONF_LOCK_CODE_DIGITS: 5, - CONF_LOCK_DEFAULT_CODE: "12345", - }, - { - CONF_LOCK_CODE_DIGITS: 5, - CONF_LOCK_DEFAULT_CODE: "12345", - }, - ), - ( - { - CONF_LOCK_DEFAULT_CODE: "", - }, - { - CONF_LOCK_DEFAULT_CODE: "", - CONF_LOCK_CODE_DIGITS: DEFAULT_LOCK_CODE_DIGITS, - }, - ), - ( - { - CONF_LOCK_CODE_DIGITS: 5, - }, - { - CONF_LOCK_CODE_DIGITS: 5, - CONF_LOCK_DEFAULT_CODE: "", - }, - ), - ], -) -async def test_options_flow( - hass: HomeAssistant, input: dict[str, int | str], output: dict[str, int | str] -) -> None: +async def test_options_flow(hass: HomeAssistant) -> None: """Test options config flow.""" - entry = MockConfigEntry( - domain=DOMAIN, - unique_id="12345", - data={}, - ) + entry = MockConfigEntry(domain=DOMAIN, unique_id="12345", data={}, version=2) entry.add_to_hass(hass) with patch( @@ -619,43 +579,8 @@ async def test_options_flow( result = await hass.config_entries.options.async_configure( result["flow_id"], - user_input=input, + user_input={CONF_LOCK_CODE_DIGITS: 4}, ) assert result.get("type") == FlowResultType.CREATE_ENTRY - assert result.get("data") == output - - -async def test_options_flow_code_format_mismatch(hass: HomeAssistant) -> None: - """Test options config flow with a code format mismatch.""" - entry = MockConfigEntry( - domain=DOMAIN, - unique_id="12345", - data={}, - ) - entry.add_to_hass(hass) - - with patch( - "homeassistant.components.verisure.async_setup_entry", - return_value=True, - ): - assert await hass.config_entries.async_setup(entry.entry_id) - await hass.async_block_till_done() - - result = await hass.config_entries.options.async_init(entry.entry_id) - - assert result.get("type") == FlowResultType.FORM - assert result.get("step_id") == "init" - assert result.get("errors") == {} - - result = await hass.config_entries.options.async_configure( - result["flow_id"], - user_input={ - CONF_LOCK_CODE_DIGITS: 5, - CONF_LOCK_DEFAULT_CODE: "123", - }, - ) - - assert result.get("type") == FlowResultType.FORM - assert result.get("step_id") == "init" - assert result.get("errors") == {"base": "code_format_mismatch"} + assert result.get("data") == {CONF_LOCK_CODE_DIGITS: DEFAULT_LOCK_CODE_DIGITS}