Use generics in litterrobot (#77537)
This commit is contained in:
parent
110803f23a
commit
a2f1b88227
6 changed files with 46 additions and 45 deletions
|
@ -32,10 +32,9 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotResetWasteDrawerButton(LitterRobotEntity, ButtonEntity):
|
class LitterRobotResetWasteDrawerButton(LitterRobotEntity[LitterRobot3], ButtonEntity):
|
||||||
"""Litter-Robot reset waste drawer button."""
|
"""Litter-Robot reset waste drawer button."""
|
||||||
|
|
||||||
robot: LitterRobot3
|
|
||||||
_attr_icon = "mdi:delete-variant"
|
_attr_icon = "mdi:delete-variant"
|
||||||
_attr_entity_category = EntityCategory.CONFIG
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,9 @@ from __future__ import annotations
|
||||||
from collections.abc import Callable, Coroutine
|
from collections.abc import Callable, Coroutine
|
||||||
from datetime import time
|
from datetime import time
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any, Generic, TypeVar
|
||||||
|
|
||||||
from pylitterbot import LitterRobot, Robot
|
from pylitterbot import Robot
|
||||||
from pylitterbot.exceptions import InvalidCommandException
|
from pylitterbot.exceptions import InvalidCommandException
|
||||||
from typing_extensions import ParamSpec
|
from typing_extensions import ParamSpec
|
||||||
|
|
||||||
|
@ -23,17 +23,20 @@ from .const import DOMAIN
|
||||||
from .hub import LitterRobotHub
|
from .hub import LitterRobotHub
|
||||||
|
|
||||||
_P = ParamSpec("_P")
|
_P = ParamSpec("_P")
|
||||||
|
_RobotT = TypeVar("_RobotT", bound=Robot)
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
REFRESH_WAIT_TIME_SECONDS = 8
|
REFRESH_WAIT_TIME_SECONDS = 8
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotEntity(CoordinatorEntity[DataUpdateCoordinator[bool]]):
|
class LitterRobotEntity(
|
||||||
|
CoordinatorEntity[DataUpdateCoordinator[bool]], Generic[_RobotT]
|
||||||
|
):
|
||||||
"""Generic Litter-Robot entity representing common data and methods."""
|
"""Generic Litter-Robot entity representing common data and methods."""
|
||||||
|
|
||||||
_attr_has_entity_name = True
|
_attr_has_entity_name = True
|
||||||
|
|
||||||
def __init__(self, robot: Robot, entity_type: str, hub: LitterRobotHub) -> None:
|
def __init__(self, robot: _RobotT, entity_type: str, hub: LitterRobotHub) -> None:
|
||||||
"""Pass coordinator to CoordinatorEntity."""
|
"""Pass coordinator to CoordinatorEntity."""
|
||||||
super().__init__(hub.coordinator)
|
super().__init__(hub.coordinator)
|
||||||
self.robot = robot
|
self.robot = robot
|
||||||
|
@ -59,12 +62,10 @@ class LitterRobotEntity(CoordinatorEntity[DataUpdateCoordinator[bool]]):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotControlEntity(LitterRobotEntity):
|
class LitterRobotControlEntity(LitterRobotEntity[_RobotT]):
|
||||||
"""A Litter-Robot entity that can control the unit."""
|
"""A Litter-Robot entity that can control the unit."""
|
||||||
|
|
||||||
robot: LitterRobot
|
def __init__(self, robot: _RobotT, entity_type: str, hub: LitterRobotHub) -> None:
|
||||||
|
|
||||||
def __init__(self, robot: Robot, entity_type: str, hub: LitterRobotHub) -> None:
|
|
||||||
"""Init a Litter-Robot control entity."""
|
"""Init a Litter-Robot control entity."""
|
||||||
super().__init__(robot=robot, entity_type=entity_type, hub=hub)
|
super().__init__(robot=robot, entity_type=entity_type, hub=hub)
|
||||||
self._refresh_callback: CALLBACK_TYPE | None = None
|
self._refresh_callback: CALLBACK_TYPE | None = None
|
||||||
|
@ -128,13 +129,12 @@ class LitterRobotControlEntity(LitterRobotEntity):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotConfigEntity(LitterRobotControlEntity):
|
class LitterRobotConfigEntity(LitterRobotControlEntity[_RobotT]):
|
||||||
"""A Litter-Robot entity that can control configuration of the unit."""
|
"""A Litter-Robot entity that can control configuration of the unit."""
|
||||||
|
|
||||||
robot: LitterRobot
|
|
||||||
_attr_entity_category = EntityCategory.CONFIG
|
_attr_entity_category = EntityCategory.CONFIG
|
||||||
|
|
||||||
def __init__(self, robot: Robot, entity_type: str, hub: LitterRobotHub) -> None:
|
def __init__(self, robot: _RobotT, entity_type: str, hub: LitterRobotHub) -> None:
|
||||||
"""Init a Litter-Robot control entity."""
|
"""Init a Litter-Robot control entity."""
|
||||||
super().__init__(robot=robot, entity_type=entity_type, hub=hub)
|
super().__init__(robot=robot, entity_type=entity_type, hub=hub)
|
||||||
self._assumed_state: bool | None = None
|
self._assumed_state: bool | None = None
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
"""Support for Litter-Robot selects."""
|
"""Support for Litter-Robot selects."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pylitterbot import LitterRobot
|
||||||
|
|
||||||
from homeassistant.components.select import SelectEntity
|
from homeassistant.components.select import SelectEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
@ -29,7 +31,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotSelect(LitterRobotConfigEntity, SelectEntity):
|
class LitterRobotSelect(LitterRobotConfigEntity[LitterRobot], SelectEntity):
|
||||||
"""Litter-Robot Select."""
|
"""Litter-Robot Select."""
|
||||||
|
|
||||||
_attr_icon = "mdi:timer-outline"
|
_attr_icon = "mdi:timer-outline"
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
"""Support for Litter-Robot sensors."""
|
"""Support for Litter-Robot sensors."""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable, Iterable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Any, Union, cast
|
import itertools
|
||||||
|
from typing import Any, Generic, Union, cast
|
||||||
|
|
||||||
from pylitterbot import FeederRobot, LitterRobot, Robot
|
from pylitterbot import FeederRobot, LitterRobot
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
|
@ -20,7 +21,7 @@ from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import LitterRobotEntity
|
from .entity import LitterRobotEntity, _RobotT
|
||||||
from .hub import LitterRobotHub
|
from .hub import LitterRobotHub
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,30 +37,23 @@ def icon_for_gauge_level(gauge_level: int | None = None, offset: int = 0) -> str
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class RobotSensorEntityDescription(SensorEntityDescription):
|
class RobotSensorEntityDescription(SensorEntityDescription, Generic[_RobotT]):
|
||||||
"""A class that describes robot sensor entities."""
|
"""A class that describes robot sensor entities."""
|
||||||
|
|
||||||
icon_fn: Callable[[Any], str | None] = lambda _: None
|
icon_fn: Callable[[Any], str | None] = lambda _: None
|
||||||
should_report: Callable[[Robot], bool] = lambda _: True
|
should_report: Callable[[_RobotT], bool] = lambda _: True
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
class LitterRobotSensorEntity(LitterRobotEntity[_RobotT], SensorEntity):
|
||||||
class LitterRobotSensorEntityDescription(RobotSensorEntityDescription):
|
|
||||||
"""A class that describes Litter-Robot sensor entities."""
|
|
||||||
|
|
||||||
should_report: Callable[[LitterRobot], bool] = lambda _: True
|
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotSensorEntity(LitterRobotEntity, SensorEntity):
|
|
||||||
"""Litter-Robot sensor entity."""
|
"""Litter-Robot sensor entity."""
|
||||||
|
|
||||||
entity_description: RobotSensorEntityDescription
|
entity_description: RobotSensorEntityDescription[_RobotT]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
robot: LitterRobot | FeederRobot,
|
robot: _RobotT,
|
||||||
hub: LitterRobotHub,
|
hub: LitterRobotHub,
|
||||||
description: RobotSensorEntityDescription,
|
description: RobotSensorEntityDescription[_RobotT],
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Initialize a Litter-Robot sensor entity."""
|
"""Initialize a Litter-Robot sensor entity."""
|
||||||
assert description.name
|
assert description.name
|
||||||
|
@ -84,31 +78,31 @@ class LitterRobotSensorEntity(LitterRobotEntity, SensorEntity):
|
||||||
|
|
||||||
|
|
||||||
LITTER_ROBOT_SENSORS = [
|
LITTER_ROBOT_SENSORS = [
|
||||||
LitterRobotSensorEntityDescription(
|
RobotSensorEntityDescription[LitterRobot](
|
||||||
name="Waste Drawer",
|
name="Waste Drawer",
|
||||||
key="waste_drawer_level",
|
key="waste_drawer_level",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
icon_fn=lambda state: icon_for_gauge_level(state, 10),
|
icon_fn=lambda state: icon_for_gauge_level(state, 10),
|
||||||
),
|
),
|
||||||
LitterRobotSensorEntityDescription(
|
RobotSensorEntityDescription[LitterRobot](
|
||||||
name="Sleep Mode Start Time",
|
name="Sleep Mode Start Time",
|
||||||
key="sleep_mode_start_time",
|
key="sleep_mode_start_time",
|
||||||
device_class=SensorDeviceClass.TIMESTAMP,
|
device_class=SensorDeviceClass.TIMESTAMP,
|
||||||
should_report=lambda robot: robot.sleep_mode_enabled,
|
should_report=lambda robot: robot.sleep_mode_enabled,
|
||||||
),
|
),
|
||||||
LitterRobotSensorEntityDescription(
|
RobotSensorEntityDescription[LitterRobot](
|
||||||
name="Sleep Mode End Time",
|
name="Sleep Mode End Time",
|
||||||
key="sleep_mode_end_time",
|
key="sleep_mode_end_time",
|
||||||
device_class=SensorDeviceClass.TIMESTAMP,
|
device_class=SensorDeviceClass.TIMESTAMP,
|
||||||
should_report=lambda robot: robot.sleep_mode_enabled,
|
should_report=lambda robot: robot.sleep_mode_enabled,
|
||||||
),
|
),
|
||||||
LitterRobotSensorEntityDescription(
|
RobotSensorEntityDescription[LitterRobot](
|
||||||
name="Last Seen",
|
name="Last Seen",
|
||||||
key="last_seen",
|
key="last_seen",
|
||||||
device_class=SensorDeviceClass.TIMESTAMP,
|
device_class=SensorDeviceClass.TIMESTAMP,
|
||||||
entity_category=EntityCategory.DIAGNOSTIC,
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
),
|
),
|
||||||
LitterRobotSensorEntityDescription(
|
RobotSensorEntityDescription[LitterRobot](
|
||||||
name="Status Code",
|
name="Status Code",
|
||||||
key="status_code",
|
key="status_code",
|
||||||
device_class="litterrobot__status_code",
|
device_class="litterrobot__status_code",
|
||||||
|
@ -116,7 +110,7 @@ LITTER_ROBOT_SENSORS = [
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
FEEDER_ROBOT_SENSOR = RobotSensorEntityDescription(
|
FEEDER_ROBOT_SENSOR = RobotSensorEntityDescription[FeederRobot](
|
||||||
name="Food Level",
|
name="Food Level",
|
||||||
key="food_level",
|
key="food_level",
|
||||||
native_unit_of_measurement=PERCENTAGE,
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
@ -131,16 +125,17 @@ async def async_setup_entry(
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Set up Litter-Robot sensors using config entry."""
|
"""Set up Litter-Robot sensors using config entry."""
|
||||||
hub: LitterRobotHub = hass.data[DOMAIN][entry.entry_id]
|
hub: LitterRobotHub = hass.data[DOMAIN][entry.entry_id]
|
||||||
async_add_entities(
|
entities: Iterable[LitterRobotSensorEntity] = itertools.chain(
|
||||||
[
|
(
|
||||||
LitterRobotSensorEntity(robot=robot, hub=hub, description=description)
|
LitterRobotSensorEntity(robot=robot, hub=hub, description=description)
|
||||||
for description in LITTER_ROBOT_SENSORS
|
for description in LITTER_ROBOT_SENSORS
|
||||||
for robot in hub.litter_robots()
|
for robot in hub.litter_robots()
|
||||||
]
|
),
|
||||||
+ [
|
(
|
||||||
LitterRobotSensorEntity(
|
LitterRobotSensorEntity(
|
||||||
robot=robot, hub=hub, description=FEEDER_ROBOT_SENSOR
|
robot=robot, hub=hub, description=FEEDER_ROBOT_SENSOR
|
||||||
)
|
)
|
||||||
for robot in hub.feeder_robots()
|
for robot in hub.feeder_robots()
|
||||||
]
|
),
|
||||||
)
|
)
|
||||||
|
async_add_entities(entities)
|
||||||
|
|
|
@ -3,6 +3,8 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pylitterbot import LitterRobot
|
||||||
|
|
||||||
from homeassistant.components.switch import SwitchEntity
|
from homeassistant.components.switch import SwitchEntity
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
|
@ -13,7 +15,9 @@ from .entity import LitterRobotConfigEntity
|
||||||
from .hub import LitterRobotHub
|
from .hub import LitterRobotHub
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotNightLightModeSwitch(LitterRobotConfigEntity, SwitchEntity):
|
class LitterRobotNightLightModeSwitch(
|
||||||
|
LitterRobotConfigEntity[LitterRobot], SwitchEntity
|
||||||
|
):
|
||||||
"""Litter-Robot Night Light Mode Switch."""
|
"""Litter-Robot Night Light Mode Switch."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -37,7 +41,7 @@ class LitterRobotNightLightModeSwitch(LitterRobotConfigEntity, SwitchEntity):
|
||||||
await self.perform_action_and_assume_state(self.robot.set_night_light, False)
|
await self.perform_action_and_assume_state(self.robot.set_night_light, False)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotPanelLockoutSwitch(LitterRobotConfigEntity, SwitchEntity):
|
class LitterRobotPanelLockoutSwitch(LitterRobotConfigEntity[LitterRobot], SwitchEntity):
|
||||||
"""Litter-Robot Panel Lockout Switch."""
|
"""Litter-Robot Panel Lockout Switch."""
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from pylitterbot import LitterRobot
|
||||||
from pylitterbot.enums import LitterBoxStatus
|
from pylitterbot.enums import LitterBoxStatus
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
|
||||||
|
@ -68,7 +69,7 @@ async def async_setup_entry(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class LitterRobotCleaner(LitterRobotControlEntity, StateVacuumEntity):
|
class LitterRobotCleaner(LitterRobotControlEntity[LitterRobot], StateVacuumEntity):
|
||||||
"""Litter-Robot "Vacuum" Cleaner."""
|
"""Litter-Robot "Vacuum" Cleaner."""
|
||||||
|
|
||||||
_attr_supported_features = (
|
_attr_supported_features = (
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue