2021-09-18 19:25:05 +00:00
|
|
|
"""Provides the switchbot DataUpdateCoordinator."""
|
|
|
|
from __future__ import annotations
|
|
|
|
|
2022-07-24 16:38:45 +00:00
|
|
|
import asyncio
|
2021-09-18 19:25:05 +00:00
|
|
|
import logging
|
2022-07-29 05:26:37 +00:00
|
|
|
from typing import TYPE_CHECKING, Any, cast
|
2021-09-18 19:25:05 +00:00
|
|
|
|
2022-06-27 11:56:51 +00:00
|
|
|
import switchbot
|
2021-09-18 19:25:05 +00:00
|
|
|
|
2022-07-24 16:38:45 +00:00
|
|
|
from homeassistant.components import bluetooth
|
|
|
|
from homeassistant.components.bluetooth.passive_update_coordinator import (
|
|
|
|
PassiveBluetoothDataUpdateCoordinator,
|
|
|
|
)
|
|
|
|
from homeassistant.core import HomeAssistant, callback
|
2021-09-18 19:25:05 +00:00
|
|
|
|
2022-07-29 05:26:37 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from bleak.backends.device import BLEDevice
|
|
|
|
|
|
|
|
|
2021-09-18 19:25:05 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2022-07-22 16:03:02 +00:00
|
|
|
def flatten_sensors_data(sensor):
|
|
|
|
"""Deconstruct SwitchBot library temp object C/Fº readings from dictionary."""
|
|
|
|
if "temp" in sensor["data"]:
|
|
|
|
sensor["data"]["temperature"] = sensor["data"]["temp"]["c"]
|
|
|
|
|
|
|
|
return sensor
|
|
|
|
|
|
|
|
|
2022-07-24 16:38:45 +00:00
|
|
|
class SwitchbotDataUpdateCoordinator(PassiveBluetoothDataUpdateCoordinator):
|
2021-09-18 19:25:05 +00:00
|
|
|
"""Class to manage fetching switchbot data."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
2022-07-24 16:38:45 +00:00
|
|
|
logger: logging.Logger,
|
|
|
|
ble_device: BLEDevice,
|
|
|
|
device: switchbot.SwitchbotDevice,
|
2021-09-18 19:25:05 +00:00
|
|
|
) -> None:
|
|
|
|
"""Initialize global switchbot data updater."""
|
2022-07-24 16:38:45 +00:00
|
|
|
super().__init__(hass, logger, ble_device.address)
|
|
|
|
self.ble_device = ble_device
|
|
|
|
self.device = device
|
|
|
|
self.data: dict[str, Any] = {}
|
|
|
|
self._ready_event = asyncio.Event()
|
|
|
|
|
|
|
|
@callback
|
|
|
|
def _async_handle_bluetooth_event(
|
|
|
|
self,
|
|
|
|
service_info: bluetooth.BluetoothServiceInfo,
|
|
|
|
change: bluetooth.BluetoothChange,
|
|
|
|
) -> None:
|
|
|
|
"""Handle a Bluetooth event."""
|
|
|
|
super()._async_handle_bluetooth_event(service_info, change)
|
|
|
|
discovery_info_bleak = cast(bluetooth.BluetoothServiceInfoBleak, service_info)
|
2022-07-29 05:26:37 +00:00
|
|
|
if adv := switchbot.parse_advertisement_data(
|
2022-07-24 16:38:45 +00:00
|
|
|
discovery_info_bleak.device, discovery_info_bleak.advertisement
|
|
|
|
):
|
|
|
|
self.data = flatten_sensors_data(adv.data)
|
|
|
|
if "modelName" in self.data:
|
|
|
|
self._ready_event.set()
|
|
|
|
_LOGGER.debug("%s: Switchbot data: %s", self.ble_device.address, self.data)
|
|
|
|
self.device.update_from_advertisement(adv)
|
|
|
|
self.async_update_listeners()
|
|
|
|
|
|
|
|
async def async_wait_ready(self) -> bool:
|
|
|
|
"""Wait for the device to be ready."""
|
|
|
|
try:
|
|
|
|
await asyncio.wait_for(self._ready_event.wait(), timeout=55)
|
|
|
|
except asyncio.TimeoutError:
|
|
|
|
return False
|
|
|
|
return True
|