core/homeassistant/components/verisure/__init__.py

178 lines
5.4 KiB
Python

"""Support for Verisure devices."""
from __future__ import annotations
import asyncio
import os
from typing import Any
import voluptuous as vol
from homeassistant.components.alarm_control_panel import (
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
)
from homeassistant.components.binary_sensor import DOMAIN as BINARY_SENSOR_DOMAIN
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, SOURCE_REAUTH, ConfigEntry
from homeassistant.const import (
CONF_EMAIL,
CONF_PASSWORD,
CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP,
)
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
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 .coordinator import VerisureDataUpdateCoordinator
PLATFORMS = [
ALARM_CONTROL_PANEL_DOMAIN,
BINARY_SENSOR_DOMAIN,
CAMERA_DOMAIN,
LOCK_DOMAIN,
SENSOR_DOMAIN,
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
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():
await hass.config_entries.flow.async_init(
DOMAIN,
context={"source": SOURCE_REAUTH},
data={"entry": entry},
)
return False
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, coordinator.async_logout)
await coordinator.async_refresh()
if not coordinator.last_update_success:
raise ConfigEntryNotReady
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = coordinator
# Set up all platforms for this device/entry.
for platform in PLATFORMS:
hass.async_create_task(
hass.config_entries.async_forward_entry_setup(entry, platform)
)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload Verisure config entry."""
unload_ok = all(
await asyncio.gather(
*(
hass.config_entries.async_forward_entry_unload(entry, platform)
for platform in PLATFORMS
)
)
)
if not unload_ok:
return False
cookie_file = hass.config.path(STORAGE_DIR, f"verisure_{entry.entry_id}")
try:
await hass.async_add_executor_job(os.unlink, cookie_file)
except FileNotFoundError:
pass
del hass.data[DOMAIN][entry.entry_id]
if not hass.data[DOMAIN]:
del hass.data[DOMAIN]
return True