core/homeassistant/components/gree/bridge.py

97 lines
3.2 KiB
Python

"""Helper and wrapper classes for Gree module."""
from __future__ import annotations
from datetime import timedelta
import logging
from greeclimate.device import Device, DeviceInfo
from greeclimate.discovery import Discovery
from greeclimate.exceptions import DeviceNotBoundError, DeviceTimeoutError
from homeassistant import exceptions
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, MAX_ERRORS
_LOGGER = logging.getLogger(__name__)
class DeviceDataUpdateCoordinator(DataUpdateCoordinator):
"""Manages polling for state changes from the device."""
def __init__(self, hass: HomeAssistant, device: Device):
"""Initialize the data update coordinator."""
DataUpdateCoordinator.__init__(
self,
hass,
_LOGGER,
name=f"{DOMAIN}-{device.device_info.name}",
update_interval=timedelta(seconds=60),
)
self.device = device
self._error_count = 0
async def _async_update_data(self):
"""Update the state of the device."""
try:
await self.device.update_state()
except DeviceTimeoutError as error:
self._error_count += 1
# Under normal conditions GREE units timeout every once in a while
if self.last_update_success and self._error_count >= MAX_ERRORS:
_LOGGER.warning(
"Device is unavailable: %s (%s)",
self.name,
self.device.device_info,
)
raise UpdateFailed(error) from error
else:
if not self.last_update_success and self._error_count:
_LOGGER.warning(
"Device is available: %s (%s)",
self.name,
str(self.device.device_info),
)
self._error_count = 0
async def push_state_update(self):
"""Send state updates to the physical device."""
try:
return await self.device.push_state_update()
except DeviceTimeoutError:
_LOGGER.warning(
"Timeout send state update to: %s (%s)",
self.name,
self.device.device_info,
)
class DeviceHelper:
"""Device search and bind wrapper for Gree platform."""
@staticmethod
async def try_bind_device(device_info: DeviceInfo) -> Device:
"""Try and bing with a discovered device.
Note the you must bind with the device very quickly after it is discovered, or the
process may not be completed correctly, raising a `CannotConnect` error.
"""
device = Device(device_info)
try:
await device.bind()
except DeviceNotBoundError as exception:
raise CannotConnect from exception
return device
@staticmethod
async def find_devices() -> list[DeviceInfo]:
"""Gather a list of device infos from the local network."""
return await Discovery.search_devices()
class CannotConnect(exceptions.HomeAssistantError):
"""Error to indicate we cannot connect."""