mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Remove Verisure default lock code (#94676)
This commit is contained in:
parent
318b8adbed
commit
a093c383c3
@ -5,14 +5,16 @@ from contextlib import suppress
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
from homeassistant.components.lock import CONF_DEFAULT_CODE, DOMAIN as LOCK_DOMAIN
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import CONF_EMAIL, Platform
|
from homeassistant.const import CONF_EMAIL, Platform
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.exceptions import ConfigEntryNotReady
|
from homeassistant.exceptions import ConfigEntryNotReady
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.storage import STORAGE_DIR
|
from homeassistant.helpers.storage import STORAGE_DIR
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import CONF_LOCK_DEFAULT_CODE, DOMAIN, LOGGER
|
||||||
from .coordinator import VerisureDataUpdateCoordinator
|
from .coordinator import VerisureDataUpdateCoordinator
|
||||||
|
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
@ -41,6 +43,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|||||||
hass.data.setdefault(DOMAIN, {})
|
hass.data.setdefault(DOMAIN, {})
|
||||||
hass.data[DOMAIN][entry.entry_id] = coordinator
|
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.
|
# Set up all platforms for this device/entry.
|
||||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
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(
|
cookie_file.rename(
|
||||||
hass.config.path(STORAGE_DIR, f"verisure_{entry.data[CONF_EMAIL]}")
|
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
|
||||||
|
@ -21,7 +21,6 @@ from homeassistant.helpers.storage import STORAGE_DIR
|
|||||||
from .const import (
|
from .const import (
|
||||||
CONF_GIID,
|
CONF_GIID,
|
||||||
CONF_LOCK_CODE_DIGITS,
|
CONF_LOCK_CODE_DIGITS,
|
||||||
CONF_LOCK_DEFAULT_CODE,
|
|
||||||
DEFAULT_LOCK_CODE_DIGITS,
|
DEFAULT_LOCK_CODE_DIGITS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
@ -31,7 +30,7 @@ from .const import (
|
|||||||
class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
class VerisureConfigFlowHandler(ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a config flow for Verisure."""
|
"""Handle a config flow for Verisure."""
|
||||||
|
|
||||||
VERSION = 1
|
VERSION = 2
|
||||||
|
|
||||||
email: str
|
email: str
|
||||||
entry: ConfigEntry
|
entry: ConfigEntry
|
||||||
@ -306,16 +305,10 @@ class VerisureOptionsFlowHandler(OptionsFlow):
|
|||||||
self, user_input: dict[str, Any] | None = None
|
self, user_input: dict[str, Any] | None = None
|
||||||
) -> FlowResult:
|
) -> FlowResult:
|
||||||
"""Manage Verisure options."""
|
"""Manage Verisure options."""
|
||||||
errors = {}
|
errors: dict[str, Any] = {}
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
if len(user_input[CONF_LOCK_DEFAULT_CODE]) not in [
|
return self.async_create_entry(data=user_input)
|
||||||
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_show_form(
|
return self.async_show_form(
|
||||||
step_id="init",
|
step_id="init",
|
||||||
@ -323,14 +316,12 @@ class VerisureOptionsFlowHandler(OptionsFlow):
|
|||||||
{
|
{
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
CONF_LOCK_CODE_DIGITS,
|
CONF_LOCK_CODE_DIGITS,
|
||||||
default=self.entry.options.get(
|
description={
|
||||||
CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS
|
"suggested_value": self.entry.options.get(
|
||||||
),
|
CONF_LOCK_CODE_DIGITS, DEFAULT_LOCK_CODE_DIGITS
|
||||||
|
)
|
||||||
|
},
|
||||||
): int,
|
): int,
|
||||||
vol.Optional(
|
|
||||||
CONF_LOCK_DEFAULT_CODE,
|
|
||||||
default=self.entry.options.get(CONF_LOCK_DEFAULT_CODE, ""),
|
|
||||||
): str,
|
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
errors=errors,
|
errors=errors,
|
||||||
|
@ -20,7 +20,6 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|||||||
from .const import (
|
from .const import (
|
||||||
CONF_GIID,
|
CONF_GIID,
|
||||||
CONF_LOCK_CODE_DIGITS,
|
CONF_LOCK_CODE_DIGITS,
|
||||||
CONF_LOCK_DEFAULT_CODE,
|
|
||||||
DEFAULT_LOCK_CODE_DIGITS,
|
DEFAULT_LOCK_CODE_DIGITS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
LOGGER,
|
LOGGER,
|
||||||
@ -129,25 +128,15 @@ class VerisureDoorlock(CoordinatorEntity[VerisureDataUpdateCoordinator], LockEnt
|
|||||||
|
|
||||||
async def async_unlock(self, **kwargs: Any) -> None:
|
async def async_unlock(self, **kwargs: Any) -> None:
|
||||||
"""Send unlock command."""
|
"""Send unlock command."""
|
||||||
code = kwargs.get(
|
code = kwargs.get(ATTR_CODE)
|
||||||
ATTR_CODE, self.coordinator.entry.options.get(CONF_LOCK_DEFAULT_CODE)
|
if code:
|
||||||
)
|
await self.async_set_lock_state(code, STATE_UNLOCKED)
|
||||||
if code is None:
|
|
||||||
LOGGER.error("Code required but none provided")
|
|
||||||
return
|
|
||||||
|
|
||||||
await self.async_set_lock_state(code, STATE_UNLOCKED)
|
|
||||||
|
|
||||||
async def async_lock(self, **kwargs: Any) -> None:
|
async def async_lock(self, **kwargs: Any) -> None:
|
||||||
"""Send lock command."""
|
"""Send lock command."""
|
||||||
code = kwargs.get(
|
code = kwargs.get(ATTR_CODE)
|
||||||
ATTR_CODE, self.coordinator.entry.options.get(CONF_LOCK_DEFAULT_CODE)
|
if code:
|
||||||
)
|
await self.async_set_lock_state(code, STATE_LOCKED)
|
||||||
if code is None:
|
|
||||||
LOGGER.error("Code required but none provided")
|
|
||||||
return
|
|
||||||
|
|
||||||
await self.async_set_lock_state(code, STATE_LOCKED)
|
|
||||||
|
|
||||||
async def async_set_lock_state(self, code: str, state: str) -> None:
|
async def async_set_lock_state(self, code: str, state: str) -> None:
|
||||||
"""Send set lock state command."""
|
"""Send set lock state command."""
|
||||||
|
@ -48,13 +48,9 @@
|
|||||||
"step": {
|
"step": {
|
||||||
"init": {
|
"init": {
|
||||||
"data": {
|
"data": {
|
||||||
"lock_code_digits": "Number of digits in PIN code for locks",
|
"lock_code_digits": "Number of digits in PIN code for locks"
|
||||||
"lock_default_code": "Default PIN code for locks, used if none is given"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"code_format_mismatch": "The default PIN code does not match the required number of digits"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entity": {
|
"entity": {
|
||||||
|
@ -23,6 +23,7 @@ def mock_config_entry() -> MockConfigEntry:
|
|||||||
CONF_GIID: "12345",
|
CONF_GIID: "12345",
|
||||||
CONF_PASSWORD: "SuperS3cr3t!",
|
CONF_PASSWORD: "SuperS3cr3t!",
|
||||||
},
|
},
|
||||||
|
version=2,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,6 @@ from homeassistant.components import dhcp
|
|||||||
from homeassistant.components.verisure.const import (
|
from homeassistant.components.verisure.const import (
|
||||||
CONF_GIID,
|
CONF_GIID,
|
||||||
CONF_LOCK_CODE_DIGITS,
|
CONF_LOCK_CODE_DIGITS,
|
||||||
CONF_LOCK_DEFAULT_CODE,
|
|
||||||
DEFAULT_LOCK_CODE_DIGITS,
|
DEFAULT_LOCK_CODE_DIGITS,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
@ -561,48 +560,9 @@ async def test_reauth_flow_errors(
|
|||||||
assert len(mock_setup_entry.mock_calls) == 1
|
assert len(mock_setup_entry.mock_calls) == 1
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
async def test_options_flow(hass: HomeAssistant) -> None:
|
||||||
("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:
|
|
||||||
"""Test options config flow."""
|
"""Test options config flow."""
|
||||||
entry = MockConfigEntry(
|
entry = MockConfigEntry(domain=DOMAIN, unique_id="12345", data={}, version=2)
|
||||||
domain=DOMAIN,
|
|
||||||
unique_id="12345",
|
|
||||||
data={},
|
|
||||||
)
|
|
||||||
entry.add_to_hass(hass)
|
entry.add_to_hass(hass)
|
||||||
|
|
||||||
with patch(
|
with patch(
|
||||||
@ -619,43 +579,8 @@ async def test_options_flow(
|
|||||||
|
|
||||||
result = await hass.config_entries.options.async_configure(
|
result = await hass.config_entries.options.async_configure(
|
||||||
result["flow_id"],
|
result["flow_id"],
|
||||||
user_input=input,
|
user_input={CONF_LOCK_CODE_DIGITS: 4},
|
||||||
)
|
)
|
||||||
|
|
||||||
assert result.get("type") == FlowResultType.CREATE_ENTRY
|
assert result.get("type") == FlowResultType.CREATE_ENTRY
|
||||||
assert result.get("data") == output
|
assert result.get("data") == {CONF_LOCK_CODE_DIGITS: DEFAULT_LOCK_CODE_DIGITS}
|
||||||
|
|
||||||
|
|
||||||
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"}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user