97 lines
3.2 KiB
Python
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."""
|