"""Support for Litter-Robot sensors.""" from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from datetime import datetime from typing import Any, Union, cast from pylitterbot.robot import Robot from homeassistant.components.sensor import ( SensorDeviceClass, SensorEntity, SensorEntityDescription, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DOMAIN from .entity import LitterRobotEntity from .hub import LitterRobotHub def icon_for_gauge_level(gauge_level: int | None = None, offset: int = 0) -> str: """Return a gauge icon valid identifier.""" if gauge_level is None or gauge_level <= 0 + offset: return "mdi:gauge-empty" if gauge_level > 70 + offset: return "mdi:gauge-full" if gauge_level > 30 + offset: return "mdi:gauge" return "mdi:gauge-low" @dataclass class LitterRobotSensorEntityDescription(SensorEntityDescription): """A class that describes Litter-Robot sensor entities.""" icon_fn: Callable[[Any], str | None] = lambda _: None should_report: Callable[[Robot], bool] = lambda _: True class LitterRobotSensorEntity(LitterRobotEntity, SensorEntity): """Litter-Robot sensor entity.""" entity_description: LitterRobotSensorEntityDescription def __init__( self, robot: Robot, hub: LitterRobotHub, description: LitterRobotSensorEntityDescription, ) -> None: """Initialize a Litter-Robot sensor entity.""" assert description.name super().__init__(robot, description.name, hub) self.entity_description = description @property def native_value(self) -> float | datetime | str | None: """Return the state.""" if self.entity_description.should_report(self.robot): if isinstance(val := getattr(self.robot, self.entity_description.key), str): return val.lower() return cast(Union[float, datetime, None], val) return None @property def icon(self) -> str | None: """Return the icon to use in the frontend, if any.""" if (icon := self.entity_description.icon_fn(self.state)) is not None: return icon return super().icon ROBOT_SENSORS = [ LitterRobotSensorEntityDescription( name="Waste Drawer", key="waste_drawer_level", native_unit_of_measurement=PERCENTAGE, icon_fn=lambda state: icon_for_gauge_level(state, 10), ), LitterRobotSensorEntityDescription( name="Sleep Mode Start Time", key="sleep_mode_start_time", device_class=SensorDeviceClass.TIMESTAMP, should_report=lambda robot: robot.sleep_mode_enabled, # type: ignore[no-any-return] ), LitterRobotSensorEntityDescription( name="Sleep Mode End Time", key="sleep_mode_end_time", device_class=SensorDeviceClass.TIMESTAMP, should_report=lambda robot: robot.sleep_mode_enabled, # type: ignore[no-any-return] ), LitterRobotSensorEntityDescription( name="Last Seen", key="last_seen", device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, ), LitterRobotSensorEntityDescription( name="Status Code", key="status_code", device_class="litterrobot__status_code", entity_category=EntityCategory.DIAGNOSTIC, ), ] async def async_setup_entry( hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up Litter-Robot sensors using config entry.""" hub: LitterRobotHub = hass.data[DOMAIN][entry.entry_id] async_add_entities( LitterRobotSensorEntity(robot=robot, hub=hub, description=description) for description in ROBOT_SENSORS for robot in hub.account.robots )