Home Assistant Unofficial Reference 2024.12.1
select.py
Go to the documentation of this file.
1 """Select platform for BMW."""
2 
3 from collections.abc import Callable, Coroutine
4 from dataclasses import dataclass
5 import logging
6 from typing import Any
7 
8 from bimmer_connected.models import MyBMWAPIError
9 from bimmer_connected.vehicle import MyBMWVehicle
10 from bimmer_connected.vehicle.charging_profile import ChargingMode
11 
12 from homeassistant.components.select import SelectEntity, SelectEntityDescription
13 from homeassistant.const import UnitOfElectricCurrent
14 from homeassistant.core import HomeAssistant, callback
15 from homeassistant.exceptions import HomeAssistantError
16 from homeassistant.helpers.entity_platform import AddEntitiesCallback
17 
18 from . import BMWConfigEntry
19 from .coordinator import BMWDataUpdateCoordinator
20 from .entity import BMWBaseEntity
21 
22 _LOGGER = logging.getLogger(__name__)
23 
24 
25 @dataclass(frozen=True, kw_only=True)
27  """Describes BMW sensor entity."""
28 
29  current_option: Callable[[MyBMWVehicle], str]
30  remote_service: Callable[[MyBMWVehicle, str], Coroutine[Any, Any, Any]]
31  is_available: Callable[[MyBMWVehicle], bool] = lambda _: False
32  dynamic_options: Callable[[MyBMWVehicle], list[str]] | None = None
33 
34 
35 SELECT_TYPES: tuple[BMWSelectEntityDescription, ...] = (
37  key="ac_limit",
38  translation_key="ac_limit",
39  is_available=lambda v: v.is_remote_set_ac_limit_enabled,
40  dynamic_options=lambda v: [
41  str(lim)
42  for lim in v.charging_profile.ac_available_limits # type: ignore[union-attr]
43  ],
44  current_option=lambda v: str(v.charging_profile.ac_current_limit), # type: ignore[union-attr]
45  remote_service=lambda v, o: v.remote_services.trigger_charging_settings_update(
46  ac_limit=int(o)
47  ),
48  unit_of_measurement=UnitOfElectricCurrent.AMPERE,
49  ),
51  key="charging_mode",
52  translation_key="charging_mode",
53  is_available=lambda v: v.is_charging_plan_supported,
54  options=[c.value.lower() for c in ChargingMode if c != ChargingMode.UNKNOWN],
55  current_option=lambda v: v.charging_profile.charging_mode.value.lower(), # type: ignore[union-attr]
56  remote_service=lambda v, o: v.remote_services.trigger_charging_profile_update(
57  charging_mode=ChargingMode(o)
58  ),
59  ),
60 )
61 
62 
64  hass: HomeAssistant,
65  config_entry: BMWConfigEntry,
66  async_add_entities: AddEntitiesCallback,
67 ) -> None:
68  """Set up the MyBMW lock from config entry."""
69  coordinator = config_entry.runtime_data.coordinator
70 
71  entities: list[BMWSelect] = []
72 
73  for vehicle in coordinator.account.vehicles:
74  if not coordinator.read_only:
75  entities.extend(
76  [
77  BMWSelect(coordinator, vehicle, description)
78  for description in SELECT_TYPES
79  if description.is_available(vehicle)
80  ]
81  )
82  async_add_entities(entities)
83 
84 
86  """Representation of BMW select entity."""
87 
88  entity_description: BMWSelectEntityDescription
89 
90  def __init__(
91  self,
92  coordinator: BMWDataUpdateCoordinator,
93  vehicle: MyBMWVehicle,
94  description: BMWSelectEntityDescription,
95  ) -> None:
96  """Initialize an BMW select."""
97  super().__init__(coordinator, vehicle)
98  self.entity_descriptionentity_description = description
99  self._attr_unique_id_attr_unique_id = f"{vehicle.vin}-{description.key}"
100  if description.dynamic_options:
101  self._attr_options_attr_options = description.dynamic_options(vehicle)
102  self._attr_current_option_attr_current_option = description.current_option(vehicle)
103 
104  @callback
105  def _handle_coordinator_update(self) -> None:
106  """Handle updated data from the coordinator."""
107  _LOGGER.debug(
108  "Updating select '%s' of %s", self.entity_descriptionentity_description.key, self.vehiclevehicle.name
109  )
110  self._attr_current_option_attr_current_option = self.entity_descriptionentity_description.current_option(self.vehiclevehicle)
112 
113  async def async_select_option(self, option: str) -> None:
114  """Update to the vehicle."""
115  _LOGGER.debug(
116  "Executing '%s' on vehicle '%s' to value '%s'",
117  self.entity_descriptionentity_description.key,
118  self.vehiclevehicle.vin,
119  option,
120  )
121  try:
122  await self.entity_descriptionentity_description.remote_service(self.vehiclevehicle, option)
123  except MyBMWAPIError as ex:
124  raise HomeAssistantError(ex) from ex
125 
126  self.coordinator.async_update_listeners()
None __init__(self, BMWDataUpdateCoordinator coordinator, MyBMWVehicle vehicle, BMWSelectEntityDescription description)
Definition: select.py:95
None async_setup_entry(HomeAssistant hass, BMWConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: select.py:67