2020-07-06 01:17:53 +00:00
|
|
|
"""The Bond integration."""
|
2020-07-26 23:27:18 +00:00
|
|
|
from asyncio import TimeoutError as AsyncIOTimeoutError
|
2021-10-13 04:39:46 +00:00
|
|
|
import logging
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-10-13 04:39:46 +00:00
|
|
|
from aiohttp import ClientError, ClientResponseError, ClientTimeout
|
2021-02-09 08:43:38 +00:00
|
|
|
from bond_api import Bond, BPUPSubscriptions, start_bpup
|
2020-07-06 01:17:53 +00:00
|
|
|
|
|
|
|
from homeassistant.config_entries import ConfigEntry
|
2021-10-13 04:39:46 +00:00
|
|
|
from homeassistant.const import (
|
|
|
|
CONF_ACCESS_TOKEN,
|
|
|
|
CONF_HOST,
|
|
|
|
EVENT_HOMEASSISTANT_STOP,
|
|
|
|
HTTP_UNAUTHORIZED,
|
|
|
|
)
|
2021-04-18 20:46:46 +00:00
|
|
|
from homeassistant.core import Event, HomeAssistant, callback
|
2020-07-26 23:27:18 +00:00
|
|
|
from homeassistant.exceptions import ConfigEntryNotReady
|
2020-07-12 16:31:53 +00:00
|
|
|
from homeassistant.helpers import device_registry as dr
|
2021-04-04 22:12:58 +00:00
|
|
|
from homeassistant.helpers.aiohttp_client import async_get_clientsession
|
2020-07-24 20:14:47 +00:00
|
|
|
from homeassistant.helpers.entity import SLOW_UPDATE_WARNING
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-02-09 08:43:38 +00:00
|
|
|
from .const import BPUP_STOP, BPUP_SUBS, BRIDGE_MAKE, DOMAIN, HUB
|
2020-07-12 16:31:53 +00:00
|
|
|
from .utils import BondHub
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2020-07-14 13:54:33 +00:00
|
|
|
PLATFORMS = ["cover", "fan", "light", "switch"]
|
2020-07-24 20:14:47 +00:00
|
|
|
_API_TIMEOUT = SLOW_UPDATE_WARNING - 1
|
2021-04-18 20:46:46 +00:00
|
|
|
_STOP_CANCEL = "stop_cancel"
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-10-13 04:39:46 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-03-01 02:16:30 +00:00
|
|
|
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
2020-07-06 01:17:53 +00:00
|
|
|
"""Set up Bond from a config entry."""
|
|
|
|
host = entry.data[CONF_HOST]
|
|
|
|
token = entry.data[CONF_ACCESS_TOKEN]
|
2021-02-08 23:37:32 +00:00
|
|
|
config_entry_id = entry.entry_id
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-04-04 22:12:58 +00:00
|
|
|
bond = Bond(
|
|
|
|
host=host,
|
|
|
|
token=token,
|
|
|
|
timeout=ClientTimeout(total=_API_TIMEOUT),
|
|
|
|
session=async_get_clientsession(hass),
|
|
|
|
)
|
2020-07-12 16:31:53 +00:00
|
|
|
hub = BondHub(bond)
|
2020-07-26 23:27:18 +00:00
|
|
|
try:
|
|
|
|
await hub.setup()
|
2021-10-13 04:39:46 +00:00
|
|
|
except ClientResponseError as ex:
|
|
|
|
if ex.status == HTTP_UNAUTHORIZED:
|
|
|
|
_LOGGER.error("Bond token no longer valid: %s", ex)
|
|
|
|
return False
|
|
|
|
raise ConfigEntryNotReady from ex
|
2020-07-26 23:27:18 +00:00
|
|
|
except (ClientError, AsyncIOTimeoutError, OSError) as error:
|
|
|
|
raise ConfigEntryNotReady from error
|
|
|
|
|
2021-02-09 08:43:38 +00:00
|
|
|
bpup_subs = BPUPSubscriptions()
|
|
|
|
stop_bpup = await start_bpup(host, bpup_subs)
|
|
|
|
|
2021-04-18 20:46:46 +00:00
|
|
|
@callback
|
|
|
|
def _async_stop_event(event: Event) -> None:
|
|
|
|
stop_bpup()
|
|
|
|
|
|
|
|
stop_event_cancel = hass.bus.async_listen(
|
|
|
|
EVENT_HOMEASSISTANT_STOP, _async_stop_event
|
|
|
|
)
|
2021-03-29 23:23:44 +00:00
|
|
|
hass.data.setdefault(DOMAIN, {})
|
2021-02-09 08:43:38 +00:00
|
|
|
hass.data[DOMAIN][entry.entry_id] = {
|
|
|
|
HUB: hub,
|
|
|
|
BPUP_SUBS: bpup_subs,
|
|
|
|
BPUP_STOP: stop_bpup,
|
2021-04-18 20:46:46 +00:00
|
|
|
_STOP_CANCEL: stop_event_cancel,
|
2021-02-09 08:43:38 +00:00
|
|
|
}
|
2020-07-12 16:31:53 +00:00
|
|
|
|
2020-07-30 23:00:58 +00:00
|
|
|
if not entry.unique_id:
|
|
|
|
hass.config_entries.async_update_entry(entry, unique_id=hub.bond_id)
|
|
|
|
|
2021-03-01 02:16:30 +00:00
|
|
|
assert hub.bond_id is not None
|
2021-02-20 07:06:43 +00:00
|
|
|
hub_name = hub.name or hub.bond_id
|
2020-07-12 16:31:53 +00:00
|
|
|
device_registry = await dr.async_get_registry(hass)
|
|
|
|
device_registry.async_get_or_create(
|
2021-02-08 23:37:32 +00:00
|
|
|
config_entry_id=config_entry_id,
|
2020-07-12 16:31:53 +00:00
|
|
|
identifiers={(DOMAIN, hub.bond_id)},
|
2021-02-08 23:37:32 +00:00
|
|
|
manufacturer=BRIDGE_MAKE,
|
2021-02-20 07:06:43 +00:00
|
|
|
name=hub_name,
|
2020-07-12 16:31:53 +00:00
|
|
|
model=hub.target,
|
|
|
|
sw_version=hub.fw_ver,
|
2021-02-20 07:06:43 +00:00
|
|
|
suggested_area=hub.location,
|
2020-07-12 16:31:53 +00:00
|
|
|
)
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-02-08 23:37:32 +00:00
|
|
|
_async_remove_old_device_identifiers(config_entry_id, device_registry, hub)
|
|
|
|
|
2021-04-26 17:46:55 +00:00
|
|
|
hass.config_entries.async_setup_platforms(entry, PLATFORMS)
|
2020-07-06 01:17:53 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
|
|
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
|
|
|
|
"""Unload a config entry."""
|
2021-04-26 17:46:55 +00:00
|
|
|
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
|
2020-07-06 01:17:53 +00:00
|
|
|
|
2021-02-09 08:43:38 +00:00
|
|
|
data = hass.data[DOMAIN][entry.entry_id]
|
2021-04-18 20:46:46 +00:00
|
|
|
data[_STOP_CANCEL]()
|
2021-02-09 08:43:38 +00:00
|
|
|
if BPUP_STOP in data:
|
|
|
|
data[BPUP_STOP]()
|
|
|
|
|
2020-07-06 01:17:53 +00:00
|
|
|
if unload_ok:
|
|
|
|
hass.data[DOMAIN].pop(entry.entry_id)
|
|
|
|
|
|
|
|
return unload_ok
|
2021-02-08 23:37:32 +00:00
|
|
|
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def _async_remove_old_device_identifiers(
|
|
|
|
config_entry_id: str, device_registry: dr.DeviceRegistry, hub: BondHub
|
2021-03-01 02:16:30 +00:00
|
|
|
) -> None:
|
2021-02-08 23:37:32 +00:00
|
|
|
"""Remove the non-unique device registry entries."""
|
|
|
|
for device in hub.devices:
|
|
|
|
dev = device_registry.async_get_device(identifiers={(DOMAIN, device.device_id)})
|
|
|
|
if dev is None:
|
|
|
|
continue
|
|
|
|
if config_entry_id in dev.config_entries:
|
|
|
|
device_registry.async_remove_device(dev.id)
|