Home Assistant Unofficial Reference 2024.12.1
select.py
Go to the documentation of this file.
1 """Support for Litter-Robot selects."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Coroutine
6 from dataclasses import dataclass
7 from typing import Any, Generic, TypeVar
8 
9 from pylitterbot import FeederRobot, LitterRobot, LitterRobot4, Robot
10 from pylitterbot.robot.litterrobot4 import BrightnessLevel
11 
12 from homeassistant.components.select import SelectEntity, SelectEntityDescription
13 from homeassistant.const import EntityCategory, UnitOfTime
14 from homeassistant.core import HomeAssistant
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from . import LitterRobotConfigEntry
18 from .entity import LitterRobotEntity, _RobotT
19 from .hub import LitterRobotHub
20 
21 _CastTypeT = TypeVar("_CastTypeT", int, float, str)
22 
23 BRIGHTNESS_LEVEL_ICON_MAP: dict[BrightnessLevel | None, str] = {
24  BrightnessLevel.LOW: "mdi:lightbulb-on-30",
25  BrightnessLevel.MEDIUM: "mdi:lightbulb-on-50",
26  BrightnessLevel.HIGH: "mdi:lightbulb-on",
27  None: "mdi:lightbulb-question",
28 }
29 
30 
31 @dataclass(frozen=True)
32 class RequiredKeysMixin(Generic[_RobotT, _CastTypeT]):
33  """A class that describes robot select entity required keys."""
34 
35  current_fn: Callable[[_RobotT], _CastTypeT | None]
36  options_fn: Callable[[_RobotT], list[_CastTypeT]]
37  select_fn: Callable[[_RobotT, str], Coroutine[Any, Any, bool]]
38 
39 
40 @dataclass(frozen=True)
42  SelectEntityDescription, RequiredKeysMixin[_RobotT, _CastTypeT]
43 ):
44  """A class that describes robot select entities."""
45 
46  entity_category: EntityCategory = EntityCategory.CONFIG
47  icon_fn: Callable[[_RobotT], str] | None = None
48 
49 
50 ROBOT_SELECT_MAP: dict[type[Robot], RobotSelectEntityDescription] = {
51  LitterRobot: RobotSelectEntityDescription[LitterRobot, int]( # type: ignore[type-abstract] # only used for isinstance check
52  key="cycle_delay",
53  translation_key="cycle_delay",
54  unit_of_measurement=UnitOfTime.MINUTES,
55  current_fn=lambda robot: robot.clean_cycle_wait_time_minutes,
56  options_fn=lambda robot: robot.VALID_WAIT_TIMES,
57  select_fn=lambda robot, opt: robot.set_wait_time(int(opt)),
58  ),
59  LitterRobot4: RobotSelectEntityDescription[LitterRobot4, str](
60  key="panel_brightness",
61  translation_key="brightness_level",
62  current_fn=lambda robot: bri.name.lower()
63  if (bri := robot.panel_brightness) is not None
64  else None,
65  options_fn=lambda _: [level.name.lower() for level in BrightnessLevel],
66  select_fn=lambda robot, opt: robot.set_panel_brightness(
67  BrightnessLevel[opt.upper()]
68  ),
69  icon_fn=lambda robot: BRIGHTNESS_LEVEL_ICON_MAP[robot.panel_brightness],
70  ),
71  FeederRobot: RobotSelectEntityDescription[FeederRobot, float](
72  key="meal_insert_size",
73  translation_key="meal_insert_size",
74  unit_of_measurement="cups",
75  current_fn=lambda robot: robot.meal_insert_size,
76  options_fn=lambda robot: robot.VALID_MEAL_INSERT_SIZES,
77  select_fn=lambda robot, opt: robot.set_meal_insert_size(float(opt)),
78  ),
79 }
80 
81 
83  hass: HomeAssistant,
84  entry: LitterRobotConfigEntry,
85  async_add_entities: AddEntitiesCallback,
86 ) -> None:
87  """Set up Litter-Robot selects using config entry."""
88  hub = entry.runtime_data
89  entities = [
90  LitterRobotSelectEntity(robot=robot, hub=hub, description=description)
91  for robot in hub.account.robots
92  for robot_type, description in ROBOT_SELECT_MAP.items()
93  if isinstance(robot, robot_type)
94  ]
95  async_add_entities(entities)
96 
97 
99  LitterRobotEntity[_RobotT], SelectEntity, Generic[_RobotT, _CastTypeT]
100 ):
101  """Litter-Robot Select."""
102 
103  entity_description: RobotSelectEntityDescription[_RobotT, _CastTypeT]
104 
105  def __init__(
106  self,
107  robot: _RobotT,
108  hub: LitterRobotHub,
109  description: RobotSelectEntityDescription[_RobotT, _CastTypeT],
110  ) -> None:
111  """Initialize a Litter-Robot select entity."""
112  super().__init__(robot, hub, description)
113  options = self.entity_descriptionentity_description.options_fn(self.robotrobot)
114  self._attr_options_attr_options = list(map(str, options))
115 
116  @property
117  def icon(self) -> str | None:
118  """Return the icon to use in the frontend, if any."""
119  if icon_fn := self.entity_descriptionentity_description.icon_fn:
120  return str(icon_fn(self.robotrobot))
121  return super().icon
122 
123  @property
124  def current_option(self) -> str | None:
125  """Return the selected entity option to represent the entity state."""
126  return str(self.entity_descriptionentity_description.current_fn(self.robotrobot))
127 
128  async def async_select_option(self, option: str) -> None:
129  """Change the selected option."""
130  await self.entity_descriptionentity_description.select_fn(self.robotrobot, option)
None __init__(self, _RobotT robot, LitterRobotHub hub, RobotSelectEntityDescription[_RobotT, _CastTypeT] description)
Definition: select.py:110
None async_setup_entry(HomeAssistant hass, LitterRobotConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: select.py:86