2019-02-13 20:21:14 +00:00
|
|
|
"""Support for Blink Home Camera System."""
|
2024-03-08 13:51:32 +00:00
|
|
|
|
2020-08-05 10:21:14 +00:00
|
|
|
from copy import deepcopy
|
2019-10-18 15:14:50 +00:00
|
|
|
import logging
|
|
|
|
|
2023-10-16 11:41:45 +00:00
|
|
|
from aiohttp import ClientError
|
2020-08-05 10:21:14 +00:00
|
|
|
from blinkpy.auth import Auth
|
2020-05-13 13:50:29 +00:00
|
|
|
from blinkpy.blinkpy import Blink
|
2018-10-03 02:17:14 +00:00
|
|
|
import voluptuous as vol
|
|
|
|
|
2020-08-05 10:21:14 +00:00
|
|
|
from homeassistant.components import persistent_notification
|
2022-01-02 16:05:18 +00:00
|
|
|
from homeassistant.config_entries import SOURCE_REAUTH, ConfigEntry
|
2023-06-01 18:06:53 +00:00
|
|
|
from homeassistant.const import (
|
|
|
|
CONF_FILE_PATH,
|
|
|
|
CONF_FILENAME,
|
|
|
|
CONF_NAME,
|
|
|
|
CONF_PIN,
|
|
|
|
CONF_SCAN_INTERVAL,
|
|
|
|
)
|
2022-01-02 16:05:18 +00:00
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2023-10-16 11:41:45 +00:00
|
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
2021-05-22 08:15:30 +00:00
|
|
|
from homeassistant.helpers import config_validation as cv
|
2023-10-16 11:41:45 +00:00
|
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
2023-11-28 07:34:41 +00:00
|
|
|
from homeassistant.helpers.typing import ConfigType
|
2021-05-22 08:15:30 +00:00
|
|
|
|
2023-11-28 07:34:41 +00:00
|
|
|
from .const import DEFAULT_SCAN_INTERVAL, DOMAIN, PLATFORMS
|
2023-10-23 13:34:28 +00:00
|
|
|
from .coordinator import BlinkUpdateCoordinator
|
2023-11-30 21:40:41 +00:00
|
|
|
from .services import setup_services
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2020-05-13 13:50:29 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2019-07-31 19:25:30 +00:00
|
|
|
SERVICE_SAVE_VIDEO_SCHEMA = vol.Schema(
|
|
|
|
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILENAME): cv.string}
|
|
|
|
)
|
2020-05-13 13:50:29 +00:00
|
|
|
SERVICE_SEND_PIN_SCHEMA = vol.Schema({vol.Optional(CONF_PIN): cv.string})
|
2023-06-01 18:06:53 +00:00
|
|
|
SERVICE_SAVE_RECENT_CLIPS_SCHEMA = vol.Schema(
|
|
|
|
{vol.Required(CONF_NAME): cv.string, vol.Required(CONF_FILE_PATH): cv.string}
|
|
|
|
)
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2023-11-28 07:34:41 +00:00
|
|
|
CONFIG_SCHEMA = cv.config_entry_only_config_schema(DOMAIN)
|
|
|
|
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2023-10-16 11:41:45 +00:00
|
|
|
async def _reauth_flow_wrapper(hass, data):
|
2020-08-05 10:21:14 +00:00
|
|
|
"""Reauth flow wrapper."""
|
|
|
|
hass.add_job(
|
|
|
|
hass.config_entries.flow.async_init(
|
2021-03-31 17:48:32 +00:00
|
|
|
DOMAIN, context={"source": SOURCE_REAUTH}, data=data
|
2020-08-05 10:21:14 +00:00
|
|
|
)
|
|
|
|
)
|
|
|
|
persistent_notification.async_create(
|
|
|
|
hass,
|
2022-12-22 09:12:50 +00:00
|
|
|
(
|
|
|
|
"Blink configuration migrated to a new version. Please go to the"
|
|
|
|
" integrations page to re-configure (such as sending a new 2FA key)."
|
|
|
|
),
|
2020-08-05 10:21:14 +00:00
|
|
|
"Blink Migration",
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2022-01-02 16:05:18 +00:00
|
|
|
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
2020-08-05 10:21:14 +00:00
|
|
|
"""Handle migration of a previous version config entry."""
|
2021-03-23 08:24:42 +00:00
|
|
|
_LOGGER.debug("Migrating from version %s", entry.version)
|
2020-08-05 10:21:14 +00:00
|
|
|
data = {**entry.data}
|
|
|
|
if entry.version == 1:
|
|
|
|
data.pop("login_response", None)
|
2023-10-16 11:41:45 +00:00
|
|
|
await _reauth_flow_wrapper(hass, data)
|
2020-08-05 10:21:14 +00:00
|
|
|
return False
|
2021-03-23 08:24:42 +00:00
|
|
|
if entry.version == 2:
|
2023-10-16 11:41:45 +00:00
|
|
|
await _reauth_flow_wrapper(hass, data)
|
2021-03-23 08:24:42 +00:00
|
|
|
return False
|
2020-05-13 13:50:29 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
2023-11-28 07:34:41 +00:00
|
|
|
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
|
|
|
|
"""Set up Blink."""
|
|
|
|
|
2023-11-30 21:40:41 +00:00
|
|
|
setup_services(hass)
|
2023-11-28 07:34:41 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2022-01-02 16:05:18 +00:00
|
|
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
2020-05-13 13:50:29 +00:00
|
|
|
"""Set up Blink via config entry."""
|
2021-03-29 23:23:44 +00:00
|
|
|
hass.data.setdefault(DOMAIN, {})
|
2020-06-10 16:38:17 +00:00
|
|
|
|
2021-03-29 23:23:44 +00:00
|
|
|
_async_import_options_from_data_if_missing(hass, entry)
|
2023-10-16 11:41:45 +00:00
|
|
|
session = async_get_clientsession(hass)
|
|
|
|
blink = Blink(session=session)
|
|
|
|
auth_data = deepcopy(dict(entry.data))
|
|
|
|
blink.auth = Auth(auth_data, no_prompt=True, session=session)
|
|
|
|
blink.refresh_rate = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
|
2023-10-23 13:34:28 +00:00
|
|
|
coordinator = BlinkUpdateCoordinator(hass, blink)
|
2023-10-16 11:41:45 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
await blink.start()
|
2024-02-05 10:31:33 +00:00
|
|
|
except (ClientError, TimeoutError) as ex:
|
2023-10-16 11:41:45 +00:00
|
|
|
raise ConfigEntryNotReady("Can not connect to host") from ex
|
|
|
|
|
2023-10-16 15:41:56 +00:00
|
|
|
if blink.auth.check_key_required():
|
|
|
|
_LOGGER.debug("Attempting a reauth flow")
|
|
|
|
raise ConfigEntryAuthFailed("Need 2FA for Blink")
|
|
|
|
|
2023-10-16 11:41:45 +00:00
|
|
|
if not blink.available:
|
2020-08-05 10:21:14 +00:00
|
|
|
raise ConfigEntryNotReady
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2023-10-25 21:57:47 +00:00
|
|
|
await coordinator.async_config_entry_first_refresh()
|
|
|
|
hass.data[DOMAIN][entry.entry_id] = coordinator
|
|
|
|
|
2022-07-09 15:27:42 +00:00
|
|
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
2018-10-03 02:17:14 +00:00
|
|
|
|
2020-05-13 13:50:29 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
2020-06-10 16:38:17 +00:00
|
|
|
@callback
|
2022-11-30 13:59:26 +00:00
|
|
|
def _async_import_options_from_data_if_missing(
|
|
|
|
hass: HomeAssistant, entry: ConfigEntry
|
|
|
|
) -> None:
|
2020-06-10 16:38:17 +00:00
|
|
|
options = dict(entry.options)
|
|
|
|
if CONF_SCAN_INTERVAL not in entry.options:
|
|
|
|
options[CONF_SCAN_INTERVAL] = entry.data.get(
|
|
|
|
CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL
|
|
|
|
)
|
|
|
|
hass.config_entries.async_update_entry(entry, options=options)
|
|
|
|
|
|
|
|
|
2022-01-02 16:05:18 +00:00
|
|
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
2020-05-13 13:50:29 +00:00
|
|
|
"""Unload Blink entry."""
|
2023-10-23 13:34:28 +00:00
|
|
|
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
|
|
|
hass.data[DOMAIN].pop(entry.entry_id)
|
|
|
|
return unload_ok
|