mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 17:27:10 +00:00
Add coordinator to Aladdin Connect (#118781)
This commit is contained in:
parent
42414d55e0
commit
e9f01be090
@ -2,6 +2,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from genie_partner_sdk.client import AladdinConnectClient
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -12,10 +14,11 @@ from homeassistant.helpers.config_entry_oauth2_flow import (
|
||||
)
|
||||
|
||||
from .api import AsyncConfigEntryAuth
|
||||
from .coordinator import AladdinConnectCoordinator
|
||||
|
||||
PLATFORMS: list[Platform] = [Platform.COVER]
|
||||
|
||||
type AladdinConnectConfigEntry = ConfigEntry[AsyncConfigEntryAuth]
|
||||
type AladdinConnectConfigEntry = ConfigEntry[AladdinConnectCoordinator]
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
@ -25,8 +28,13 @@ async def async_setup_entry(
|
||||
implementation = await async_get_config_entry_implementation(hass, entry)
|
||||
|
||||
session = OAuth2Session(hass, entry, implementation)
|
||||
auth = AsyncConfigEntryAuth(async_get_clientsession(hass), session)
|
||||
coordinator = AladdinConnectCoordinator(hass, AladdinConnectClient(auth))
|
||||
|
||||
entry.runtime_data = AsyncConfigEntryAuth(async_get_clientsession(hass), session)
|
||||
await coordinator.async_setup()
|
||||
await coordinator.async_config_entry_first_refresh()
|
||||
|
||||
entry.runtime_data = coordinator
|
||||
|
||||
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
|
||||
|
||||
|
38
homeassistant/components/aladdin_connect/coordinator.py
Normal file
38
homeassistant/components/aladdin_connect/coordinator.py
Normal file
@ -0,0 +1,38 @@
|
||||
"""Define an object to coordinate fetching Aladdin Connect data."""
|
||||
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
|
||||
from genie_partner_sdk.client import AladdinConnectClient
|
||||
from genie_partner_sdk.model import GarageDoor
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
|
||||
from .const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AladdinConnectCoordinator(DataUpdateCoordinator[None]):
|
||||
"""Aladdin Connect Data Update Coordinator."""
|
||||
|
||||
def __init__(self, hass: HomeAssistant, acc: AladdinConnectClient) -> None:
|
||||
"""Initialize."""
|
||||
super().__init__(
|
||||
hass,
|
||||
logger=_LOGGER,
|
||||
name=DOMAIN,
|
||||
update_interval=timedelta(seconds=15),
|
||||
)
|
||||
self.acc = acc
|
||||
self.doors: list[GarageDoor] = []
|
||||
|
||||
async def async_setup(self) -> None:
|
||||
"""Fetch initial data."""
|
||||
self.doors = await self.acc.get_doors()
|
||||
|
||||
async def _async_update_data(self) -> None:
|
||||
"""Fetch data from API endpoint."""
|
||||
for door in self.doors:
|
||||
await self.acc.update_door(door.device_id, door.door_number)
|
@ -1,9 +1,7 @@
|
||||
"""Cover Entity for Genie Garage Door."""
|
||||
|
||||
from datetime import timedelta
|
||||
from typing import Any
|
||||
|
||||
from genie_partner_sdk.client import AladdinConnectClient
|
||||
from genie_partner_sdk.model import GarageDoor
|
||||
|
||||
from homeassistant.components.cover import (
|
||||
@ -11,52 +9,36 @@ from homeassistant.components.cover import (
|
||||
CoverEntity,
|
||||
CoverEntityFeature,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import PlatformNotReady
|
||||
import homeassistant.helpers.device_registry as dr
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import api
|
||||
from . import AladdinConnectConfigEntry, AladdinConnectCoordinator
|
||||
from .const import DOMAIN
|
||||
|
||||
SCAN_INTERVAL = timedelta(seconds=15)
|
||||
from .entity import AladdinConnectEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
config_entry: AladdinConnectConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up the Aladdin Connect platform."""
|
||||
session: api.AsyncConfigEntryAuth = config_entry.runtime_data
|
||||
acc = AladdinConnectClient(session)
|
||||
doors = await acc.get_doors()
|
||||
if doors is None:
|
||||
raise PlatformNotReady("Error from Aladdin Connect getting doors")
|
||||
device_registry = dr.async_get(hass)
|
||||
doors_to_add = []
|
||||
for door in doors:
|
||||
existing = device_registry.async_get(door.unique_id)
|
||||
if existing is None:
|
||||
doors_to_add.append(door)
|
||||
coordinator = config_entry.runtime_data
|
||||
|
||||
async_add_entities(
|
||||
(AladdinDevice(acc, door, config_entry) for door in doors_to_add),
|
||||
)
|
||||
remove_stale_devices(hass, config_entry, doors)
|
||||
async_add_entities(AladdinDevice(coordinator, door) for door in coordinator.doors)
|
||||
remove_stale_devices(hass, config_entry)
|
||||
|
||||
|
||||
def remove_stale_devices(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry, devices: list[GarageDoor]
|
||||
hass: HomeAssistant, config_entry: AladdinConnectConfigEntry
|
||||
) -> None:
|
||||
"""Remove stale devices from device registry."""
|
||||
device_registry = dr.async_get(hass)
|
||||
device_entries = dr.async_entries_for_config_entry(
|
||||
device_registry, config_entry.entry_id
|
||||
)
|
||||
all_device_ids = {door.unique_id for door in devices}
|
||||
all_device_ids = {door.unique_id for door in config_entry.runtime_data.doors}
|
||||
|
||||
for device_entry in device_entries:
|
||||
device_id: str | None = None
|
||||
@ -75,45 +57,38 @@ def remove_stale_devices(
|
||||
)
|
||||
|
||||
|
||||
class AladdinDevice(CoverEntity):
|
||||
class AladdinDevice(AladdinConnectEntity, CoverEntity):
|
||||
"""Representation of Aladdin Connect cover."""
|
||||
|
||||
_attr_device_class = CoverDeviceClass.GARAGE
|
||||
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
|
||||
_attr_has_entity_name = True
|
||||
_attr_name = None
|
||||
|
||||
def __init__(
|
||||
self, acc: AladdinConnectClient, device: GarageDoor, entry: ConfigEntry
|
||||
self, coordinator: AladdinConnectCoordinator, device: GarageDoor
|
||||
) -> None:
|
||||
"""Initialize the Aladdin Connect cover."""
|
||||
self._acc = acc
|
||||
self._device_id = device.device_id
|
||||
self._number = device.door_number
|
||||
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, device.unique_id)},
|
||||
name=device.name,
|
||||
manufacturer="Overhead Door",
|
||||
)
|
||||
super().__init__(coordinator, device)
|
||||
self._attr_unique_id = device.unique_id
|
||||
|
||||
async def async_open_cover(self, **kwargs: Any) -> None:
|
||||
"""Issue open command to cover."""
|
||||
await self._acc.open_door(self._device_id, self._number)
|
||||
await self.coordinator.acc.open_door(
|
||||
self._device.device_id, self._device.door_number
|
||||
)
|
||||
|
||||
async def async_close_cover(self, **kwargs: Any) -> None:
|
||||
"""Issue close command to cover."""
|
||||
await self._acc.close_door(self._device_id, self._number)
|
||||
|
||||
async def async_update(self) -> None:
|
||||
"""Update status of cover."""
|
||||
await self._acc.update_door(self._device_id, self._number)
|
||||
await self.coordinator.acc.close_door(
|
||||
self._device.device_id, self._device.door_number
|
||||
)
|
||||
|
||||
@property
|
||||
def is_closed(self) -> bool | None:
|
||||
"""Update is closed attribute."""
|
||||
value = self._acc.get_door_status(self._device_id, self._number)
|
||||
value = self.coordinator.acc.get_door_status(
|
||||
self._device.device_id, self._device.door_number
|
||||
)
|
||||
if value is None:
|
||||
return None
|
||||
return bool(value == "closed")
|
||||
@ -121,7 +96,9 @@ class AladdinDevice(CoverEntity):
|
||||
@property
|
||||
def is_closing(self) -> bool | None:
|
||||
"""Update is closing attribute."""
|
||||
value = self._acc.get_door_status(self._device_id, self._number)
|
||||
value = self.coordinator.acc.get_door_status(
|
||||
self._device.device_id, self._device.door_number
|
||||
)
|
||||
if value is None:
|
||||
return None
|
||||
return bool(value == "closing")
|
||||
@ -129,7 +106,9 @@ class AladdinDevice(CoverEntity):
|
||||
@property
|
||||
def is_opening(self) -> bool | None:
|
||||
"""Update is opening attribute."""
|
||||
value = self._acc.get_door_status(self._device_id, self._number)
|
||||
value = self.coordinator.acc.get_door_status(
|
||||
self._device.device_id, self._device.door_number
|
||||
)
|
||||
if value is None:
|
||||
return None
|
||||
return bool(value == "opening")
|
||||
|
27
homeassistant/components/aladdin_connect/entity.py
Normal file
27
homeassistant/components/aladdin_connect/entity.py
Normal file
@ -0,0 +1,27 @@
|
||||
"""Defines a base Aladdin Connect entity."""
|
||||
|
||||
from genie_partner_sdk.model import GarageDoor
|
||||
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import DOMAIN
|
||||
from .coordinator import AladdinConnectCoordinator
|
||||
|
||||
|
||||
class AladdinConnectEntity(CoordinatorEntity[AladdinConnectCoordinator]):
|
||||
"""Defines a base Aladdin Connect entity."""
|
||||
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self, coordinator: AladdinConnectCoordinator, device: GarageDoor
|
||||
) -> None:
|
||||
"""Initialize the entity."""
|
||||
super().__init__(coordinator)
|
||||
self._device = device
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, device.unique_id)},
|
||||
name=device.name,
|
||||
manufacturer="Overhead Door",
|
||||
)
|
@ -4,7 +4,6 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import cast
|
||||
|
||||
from genie_partner_sdk.client import AladdinConnectClient
|
||||
from genie_partner_sdk.model import GarageDoor
|
||||
@ -15,21 +14,19 @@ from homeassistant.components.sensor import (
|
||||
SensorEntityDescription,
|
||||
SensorStateClass,
|
||||
)
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import PERCENTAGE
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
|
||||
from . import api
|
||||
from .const import DOMAIN
|
||||
from . import AladdinConnectConfigEntry, AladdinConnectCoordinator
|
||||
from .entity import AladdinConnectEntity
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class AccSensorEntityDescription(SensorEntityDescription):
|
||||
"""Describes AladdinConnect sensor entity."""
|
||||
|
||||
value_fn: Callable
|
||||
value_fn: Callable[[AladdinConnectClient, str, int], float | None]
|
||||
|
||||
|
||||
SENSORS: tuple[AccSensorEntityDescription, ...] = (
|
||||
@ -45,52 +42,39 @@ SENSORS: tuple[AccSensorEntityDescription, ...] = (
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
|
||||
hass: HomeAssistant,
|
||||
entry: AladdinConnectConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up Aladdin Connect sensor devices."""
|
||||
coordinator = entry.runtime_data
|
||||
|
||||
session: api.AsyncConfigEntryAuth = hass.data[DOMAIN][entry.entry_id]
|
||||
acc = AladdinConnectClient(session)
|
||||
|
||||
entities = []
|
||||
doors = await acc.get_doors()
|
||||
|
||||
for door in doors:
|
||||
entities.extend(
|
||||
[AladdinConnectSensor(acc, door, description) for description in SENSORS]
|
||||
)
|
||||
|
||||
async_add_entities(entities)
|
||||
async_add_entities(
|
||||
AladdinConnectSensor(coordinator, door, description)
|
||||
for description in SENSORS
|
||||
for door in coordinator.doors
|
||||
)
|
||||
|
||||
|
||||
class AladdinConnectSensor(SensorEntity):
|
||||
class AladdinConnectSensor(AladdinConnectEntity, SensorEntity):
|
||||
"""A sensor implementation for Aladdin Connect devices."""
|
||||
|
||||
entity_description: AccSensorEntityDescription
|
||||
_attr_has_entity_name = True
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
acc: AladdinConnectClient,
|
||||
coordinator: AladdinConnectCoordinator,
|
||||
device: GarageDoor,
|
||||
description: AccSensorEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize a sensor for an Aladdin Connect device."""
|
||||
self._device_id = device.device_id
|
||||
self._number = device.door_number
|
||||
self._acc = acc
|
||||
super().__init__(coordinator, device)
|
||||
self.entity_description = description
|
||||
self._attr_unique_id = f"{device.unique_id}-{description.key}"
|
||||
self._attr_device_info = DeviceInfo(
|
||||
identifiers={(DOMAIN, device.unique_id)},
|
||||
name=device.name,
|
||||
manufacturer="Overhead Door",
|
||||
)
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
"""Return the state of the sensor."""
|
||||
return cast(
|
||||
float,
|
||||
self.entity_description.value_fn(self._acc, self._device_id, self._number),
|
||||
return self.entity_description.value_fn(
|
||||
self.coordinator.acc, self._device.device_id, self._device.door_number
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user