Home Assistant Unofficial Reference 2024.12.1
select.py
Go to the documentation of this file.
1 """Support for Homekit select entities."""
2 
3 from __future__ import annotations
4 
5 from dataclasses import dataclass
6 from enum import IntEnum
7 
8 from aiohomekit.model.characteristics import Characteristic, CharacteristicsTypes
9 from aiohomekit.model.characteristics.const import (
10  TargetAirPurifierStateValues,
11  TemperatureDisplayUnits,
12 )
13 
14 from homeassistant.components.select import SelectEntity, SelectEntityDescription
15 from homeassistant.config_entries import ConfigEntry
16 from homeassistant.const import EntityCategory, Platform
17 from homeassistant.core import HomeAssistant, callback
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 from homeassistant.helpers.typing import ConfigType
20 
21 from . import KNOWN_DEVICES
22 from .connection import HKDevice
23 from .entity import CharacteristicEntity
24 
25 
26 @dataclass(frozen=True, kw_only=True)
28  """A generic description of a select entity backed by a single characteristic."""
29 
30  choices: dict[str, IntEnum]
31  name: str | None = None
32 
33 
34 SELECT_ENTITIES: dict[str, HomeKitSelectEntityDescription] = {
35  CharacteristicsTypes.TEMPERATURE_UNITS: HomeKitSelectEntityDescription(
36  key="temperature_display_units",
37  translation_key="temperature_display_units",
38  name="Temperature Display Units",
39  entity_category=EntityCategory.CONFIG,
40  choices={
41  "celsius": TemperatureDisplayUnits.CELSIUS,
42  "fahrenheit": TemperatureDisplayUnits.FAHRENHEIT,
43  },
44  ),
45  CharacteristicsTypes.AIR_PURIFIER_STATE_TARGET: HomeKitSelectEntityDescription(
46  key="air_purifier_state_target",
47  translation_key="air_purifier_state_target",
48  name="Air Purifier Mode",
49  entity_category=EntityCategory.CONFIG,
50  choices={
51  "automatic": TargetAirPurifierStateValues.AUTOMATIC,
52  "manual": TargetAirPurifierStateValues.MANUAL,
53  },
54  ),
55 }
56 
57 _ECOBEE_MODE_TO_TEXT = {
58  0: "home",
59  1: "sleep",
60  2: "away",
61 }
62 _ECOBEE_MODE_TO_NUMBERS = {v: k for (k, v) in _ECOBEE_MODE_TO_TEXT.items()}
63 
64 
66  """Base entity for select entities backed by a single characteristics."""
67 
68 
69 class HomeKitSelect(BaseHomeKitSelect):
70  """Representation of a select control on a homekit accessory."""
71 
72  entity_description: HomeKitSelectEntityDescription
73 
74  def __init__(
75  self,
76  conn: HKDevice,
77  info: ConfigType,
78  char: Characteristic,
79  description: HomeKitSelectEntityDescription,
80  ) -> None:
81  """Initialise a HomeKit select control."""
82  self.entity_descriptionentity_description = description
83 
84  self._choice_to_enum_choice_to_enum = self.entity_descriptionentity_description.choices
85  self._enum_to_choice_enum_to_choice = {
86  v: k for (k, v) in self.entity_descriptionentity_description.choices.items()
87  }
88 
89  self._attr_options_attr_options = list(self.entity_descriptionentity_description.choices.keys())
90 
91  super().__init__(conn, info, char)
92 
93  def get_characteristic_types(self) -> list[str]:
94  """Define the homekit characteristics the entity cares about."""
95  return [self._char_char.type]
96 
97  @property
98  def name(self) -> str | None:
99  """Return the name of the device if any."""
100  if name := self.accessoryaccessory.name:
101  return f"{name} {self.entity_description.name}"
102  return self.entity_descriptionentity_description.name
103 
104  @property
105  def current_option(self) -> str | None:
106  """Return the current selected option."""
107  return self._enum_to_choice_enum_to_choice.get(self._char_char.value)
108 
109  async def async_select_option(self, option: str) -> None:
110  """Set the current option."""
111  await self.async_put_characteristicsasync_put_characteristics(
112  {self._char_char.type: self._choice_to_enum_choice_to_enum[option]}
113  )
114 
115 
117  """Represents a ecobee mode select entity."""
118 
119  _attr_options = ["home", "sleep", "away"]
120  _attr_translation_key = "ecobee_mode"
121 
122  @property
123  def name(self) -> str:
124  """Return the name of the device if any."""
125  if name := super().name:
126  return f"{name} Current Mode"
127  return "Current Mode"
128 
129  def get_characteristic_types(self) -> list[str]:
130  """Define the homekit characteristics the entity cares about."""
131  return [
132  CharacteristicsTypes.VENDOR_ECOBEE_CURRENT_MODE,
133  ]
134 
135  @property
136  def current_option(self) -> str | None:
137  """Return the current selected option."""
138  return _ECOBEE_MODE_TO_TEXT.get(self._char_char.value)
139 
140  async def async_select_option(self, option: str) -> None:
141  """Set the current mode."""
142  option_int = _ECOBEE_MODE_TO_NUMBERS[option]
143  await self.async_put_characteristicsasync_put_characteristics(
144  {CharacteristicsTypes.VENDOR_ECOBEE_SET_HOLD_SCHEDULE: option_int}
145  )
146 
147 
149  hass: HomeAssistant,
150  config_entry: ConfigEntry,
151  async_add_entities: AddEntitiesCallback,
152 ) -> None:
153  """Set up Homekit select entities."""
154  hkid: str = config_entry.data["AccessoryPairingID"]
155  conn: HKDevice = hass.data[KNOWN_DEVICES][hkid]
156 
157  @callback
158  def async_add_characteristic(char: Characteristic) -> bool:
159  entities: list[BaseHomeKitSelect] = []
160  info = {"aid": char.service.accessory.aid, "iid": char.service.iid}
161 
162  if description := SELECT_ENTITIES.get(char.type):
163  entities.append(HomeKitSelect(conn, info, char, description))
164  elif char.type == CharacteristicsTypes.VENDOR_ECOBEE_CURRENT_MODE:
165  entities.append(EcobeeModeSelect(conn, info, char))
166 
167  if not entities:
168  return False
169 
170  for entity in entities:
171  conn.async_migrate_unique_id(
172  entity.old_unique_id, entity.unique_id, Platform.SELECT
173  )
174 
175  async_add_entities(entities)
176  return True
177 
178  conn.add_char_factory(async_add_characteristic)
None async_put_characteristics(self, dict[str, Any] characteristics)
Definition: entity.py:125
None __init__(self, HKDevice conn, ConfigType info, Characteristic char, HomeKitSelectEntityDescription description)
Definition: select.py:80
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
bool async_add_characteristic(Characteristic char)
Definition: number.py:78
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: select.py:152