2022-05-17 07:59:39 +00:00
|
|
|
"""The yolink integration."""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-05-29 18:54:23 +00:00
|
|
|
import asyncio
|
2023-01-31 13:50:19 +00:00
|
|
|
from dataclasses import dataclass
|
2022-05-17 07:59:39 +00:00
|
|
|
from datetime import timedelta
|
2023-01-31 13:50:19 +00:00
|
|
|
from typing import Any
|
2022-05-17 07:59:39 +00:00
|
|
|
|
2022-05-29 18:54:23 +00:00
|
|
|
import async_timeout
|
|
|
|
from yolink.device import YoLinkDevice
|
|
|
|
from yolink.exception import YoLinkAuthFailError, YoLinkClientError
|
2023-01-31 13:50:19 +00:00
|
|
|
from yolink.home_manager import YoLinkHome
|
|
|
|
from yolink.message_listener import MessageListener
|
2022-05-17 07:59:39 +00:00
|
|
|
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2022-10-01 22:56:36 +00:00
|
|
|
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
|
2022-05-17 07:59:39 +00:00
|
|
|
from homeassistant.core import HomeAssistant
|
2022-05-29 18:54:23 +00:00
|
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
|
2022-05-17 07:59:39 +00:00
|
|
|
from homeassistant.helpers import aiohttp_client, config_entry_oauth2_flow
|
|
|
|
|
|
|
|
from . import api
|
2023-01-31 13:50:19 +00:00
|
|
|
from .const import DOMAIN
|
2022-05-17 07:59:39 +00:00
|
|
|
from .coordinator import YoLinkCoordinator
|
|
|
|
|
|
|
|
SCAN_INTERVAL = timedelta(minutes=5)
|
|
|
|
|
|
|
|
|
2022-06-06 03:58:29 +00:00
|
|
|
PLATFORMS = [
|
|
|
|
Platform.BINARY_SENSOR,
|
2022-06-10 12:18:46 +00:00
|
|
|
Platform.CLIMATE,
|
2022-07-18 09:40:18 +00:00
|
|
|
Platform.COVER,
|
2022-11-23 15:27:51 +00:00
|
|
|
Platform.LIGHT,
|
2022-06-06 03:58:29 +00:00
|
|
|
Platform.LOCK,
|
|
|
|
Platform.SENSOR,
|
|
|
|
Platform.SIREN,
|
|
|
|
Platform.SWITCH,
|
|
|
|
]
|
2022-05-17 07:59:39 +00:00
|
|
|
|
|
|
|
|
2023-01-31 13:50:19 +00:00
|
|
|
class YoLinkHomeMessageListener(MessageListener):
|
|
|
|
"""YoLink home message listener."""
|
|
|
|
|
|
|
|
def __init__(self, hass: HomeAssistant, entry: ConfigEntry) -> None:
|
|
|
|
"""Init YoLink home message listener."""
|
|
|
|
self._hass = hass
|
|
|
|
self._entry = entry
|
|
|
|
|
|
|
|
def on_message(self, device: YoLinkDevice, msg_data: dict[str, Any]) -> None:
|
|
|
|
"""On YoLink home message received."""
|
|
|
|
entry_data = self._hass.data[DOMAIN].get(self._entry.entry_id)
|
|
|
|
if not entry_data:
|
|
|
|
return
|
|
|
|
device_coordinators = entry_data.device_coordinators
|
|
|
|
if not device_coordinators:
|
|
|
|
return
|
|
|
|
device_coordiantor = device_coordinators.get(device.device_id)
|
|
|
|
if device_coordiantor is not None:
|
|
|
|
device_coordiantor.async_set_updated_data(msg_data)
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
class YoLinkHomeStore:
|
|
|
|
"""YoLink home store."""
|
|
|
|
|
|
|
|
home_instance: YoLinkHome
|
|
|
|
device_coordinators: dict[str, YoLinkCoordinator]
|
|
|
|
|
|
|
|
|
2022-05-17 07:59:39 +00:00
|
|
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
|
"""Set up yolink from a config entry."""
|
|
|
|
hass.data.setdefault(DOMAIN, {})
|
|
|
|
implementation = (
|
|
|
|
await config_entry_oauth2_flow.async_get_config_entry_implementation(
|
|
|
|
hass, entry
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
session = config_entry_oauth2_flow.OAuth2Session(hass, entry, implementation)
|
|
|
|
|
|
|
|
auth_mgr = api.ConfigEntryAuth(
|
|
|
|
hass, aiohttp_client.async_get_clientsession(hass), session
|
|
|
|
)
|
2023-01-31 13:50:19 +00:00
|
|
|
yolink_home = YoLinkHome()
|
2022-05-17 07:59:39 +00:00
|
|
|
try:
|
2022-05-29 18:54:23 +00:00
|
|
|
async with async_timeout.timeout(10):
|
2023-01-31 13:50:19 +00:00
|
|
|
await yolink_home.async_setup(
|
|
|
|
auth_mgr, YoLinkHomeMessageListener(hass, entry)
|
2022-05-29 18:54:23 +00:00
|
|
|
)
|
|
|
|
except YoLinkAuthFailError as yl_auth_err:
|
|
|
|
raise ConfigEntryAuthFailed from yl_auth_err
|
|
|
|
except (YoLinkClientError, asyncio.TimeoutError) as err:
|
|
|
|
raise ConfigEntryNotReady from err
|
2022-05-17 07:59:39 +00:00
|
|
|
|
2022-05-29 18:54:23 +00:00
|
|
|
device_coordinators = {}
|
2023-01-31 13:50:19 +00:00
|
|
|
for device in yolink_home.get_devices():
|
2022-05-29 18:54:23 +00:00
|
|
|
device_coordinator = YoLinkCoordinator(hass, device)
|
|
|
|
try:
|
|
|
|
await device_coordinator.async_config_entry_first_refresh()
|
|
|
|
except ConfigEntryNotReady:
|
|
|
|
# Not failure by fetching device state
|
|
|
|
device_coordinator.data = {}
|
|
|
|
device_coordinators[device.device_id] = device_coordinator
|
2023-01-31 13:50:19 +00:00
|
|
|
hass.data[DOMAIN][entry.entry_id] = YoLinkHomeStore(
|
|
|
|
yolink_home, device_coordinators
|
|
|
|
)
|
2022-07-09 15:27:42 +00:00
|
|
|
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
2022-10-01 22:56:36 +00:00
|
|
|
|
2023-01-31 13:50:19 +00:00
|
|
|
async def async_yolink_unload(event) -> None:
|
|
|
|
"""Unload yolink."""
|
|
|
|
await yolink_home.async_unload()
|
2022-10-01 22:56:36 +00:00
|
|
|
|
|
|
|
entry.async_on_unload(
|
2023-01-31 13:50:19 +00:00
|
|
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, async_yolink_unload)
|
2022-10-01 22:56:36 +00:00
|
|
|
)
|
|
|
|
|
2022-05-17 07:59:39 +00:00
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
|
"""Unload a config entry."""
|
|
|
|
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
|
2023-01-31 13:50:19 +00:00
|
|
|
await hass.data[DOMAIN][entry.entry_id].home_instance.async_unload()
|
2022-05-17 07:59:39 +00:00
|
|
|
hass.data[DOMAIN].pop(entry.entry_id)
|
|
|
|
return unload_ok
|