1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00
ha-core/homeassistant/components/gogogate2/common.py
2021-11-06 14:13:48 +01:00

181 lines
5.6 KiB
Python

"""Common code for GogoGate2 component."""
from __future__ import annotations
from collections.abc import Awaitable, Callable, Mapping
from datetime import timedelta
import logging
from typing import Any, NamedTuple
from ismartgate import AbstractGateApi, GogoGate2Api, ISmartGateApi
from ismartgate.common import AbstractDoor, get_door_by_id
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import (
CONF_DEVICE,
CONF_IP_ADDRESS,
CONF_PASSWORD,
CONF_USERNAME,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.debounce import Debouncer
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.httpx_client import get_async_client
from homeassistant.helpers.update_coordinator import (
CoordinatorEntity,
DataUpdateCoordinator,
UpdateFailed,
)
from .const import DATA_UPDATE_COORDINATOR, DEVICE_TYPE_ISMARTGATE, DOMAIN, MANUFACTURER
_LOGGER = logging.getLogger(__name__)
class StateData(NamedTuple):
"""State data for a cover entity."""
config_unique_id: str
unique_id: str | None
door: AbstractDoor | None
class DeviceDataUpdateCoordinator(DataUpdateCoordinator):
"""Manages polling for state changes from the device."""
def __init__(
self,
hass: HomeAssistant,
logger: logging.Logger,
api: AbstractGateApi,
*,
name: str,
update_interval: timedelta,
update_method: Callable[[], Awaitable] | None = None,
request_refresh_debouncer: Debouncer | None = None,
) -> None:
"""Initialize the data update coordinator."""
DataUpdateCoordinator.__init__(
self,
hass,
logger,
name=name,
update_interval=update_interval,
update_method=update_method,
request_refresh_debouncer=request_refresh_debouncer,
)
self.api = api
class GoGoGate2Entity(CoordinatorEntity):
"""Base class for gogogate2 entities."""
def __init__(
self,
config_entry: ConfigEntry,
data_update_coordinator: DeviceDataUpdateCoordinator,
door: AbstractDoor,
unique_id: str,
) -> None:
"""Initialize gogogate2 base entity."""
super().__init__(data_update_coordinator)
self._config_entry = config_entry
self._door = door
self._door_id = door.door_id
self._api = data_update_coordinator.api
self._attr_unique_id = unique_id
@property
def door(self) -> AbstractDoor:
"""Return the door object."""
door = get_door_by_id(self._door.door_id, self.coordinator.data)
self._door = door or self._door
return self._door
@property
def door_status(self) -> AbstractDoor:
"""Return the door with status."""
data = self.coordinator.data
door_with_statuses = self._api.async_get_door_statuses_from_info(data)
return door_with_statuses[self._door_id]
@property
def device_info(self) -> DeviceInfo:
"""Device info for the controller."""
data = self.coordinator.data
configuration_url = (
f"https://{data.remoteaccess}" if data.remoteaccess else None
)
return DeviceInfo(
configuration_url=configuration_url,
identifiers={(DOMAIN, str(self._config_entry.unique_id))},
name=self._config_entry.title,
manufacturer=MANUFACTURER,
model=data.model,
sw_version=data.firmwareversion,
)
@property
def extra_state_attributes(self):
"""Return the state attributes."""
return {"door_id": self._door_id}
def get_data_update_coordinator(
hass: HomeAssistant, config_entry: ConfigEntry
) -> DeviceDataUpdateCoordinator:
"""Get an update coordinator."""
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN].setdefault(config_entry.entry_id, {})
config_entry_data = hass.data[DOMAIN][config_entry.entry_id]
if DATA_UPDATE_COORDINATOR not in config_entry_data:
api = get_api(hass, config_entry.data)
async def async_update_data():
try:
return await api.async_info()
except Exception as exception:
raise UpdateFailed(
f"Error communicating with API: {exception}"
) from exception
config_entry_data[DATA_UPDATE_COORDINATOR] = DeviceDataUpdateCoordinator(
hass,
_LOGGER,
api,
# Name of the data. For logging purposes.
name="gogogate2",
update_method=async_update_data,
# Polling interval. Will only be polled if there are subscribers.
update_interval=timedelta(seconds=5),
)
return config_entry_data[DATA_UPDATE_COORDINATOR]
def cover_unique_id(config_entry: ConfigEntry, door: AbstractDoor) -> str:
"""Generate a cover entity unique id."""
return f"{config_entry.unique_id}_{door.door_id}"
def sensor_unique_id(
config_entry: ConfigEntry, door: AbstractDoor, sensor_type: str
) -> str:
"""Generate a cover entity unique id."""
return f"{config_entry.unique_id}_{door.door_id}_{sensor_type}"
def get_api(hass: HomeAssistant, config_data: Mapping[str, Any]) -> AbstractGateApi:
"""Get an api object for config data."""
gate_class = GogoGate2Api
if config_data[CONF_DEVICE] == DEVICE_TYPE_ISMARTGATE:
gate_class = ISmartGateApi
return gate_class(
config_data[CONF_IP_ADDRESS],
config_data[CONF_USERNAME],
config_data[CONF_PASSWORD],
httpx_async_client=get_async_client(hass),
)