Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Switch 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.fuel_and_battery import ChargingState
11 
12 from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription
13 from homeassistant.core import HomeAssistant
14 from homeassistant.exceptions import HomeAssistantError
15 from homeassistant.helpers.entity_platform import AddEntitiesCallback
16 
17 from . import BMWConfigEntry
18 from .coordinator import BMWDataUpdateCoordinator
19 from .entity import BMWBaseEntity
20 
21 _LOGGER = logging.getLogger(__name__)
22 
23 
24 @dataclass(frozen=True, kw_only=True)
26  """Describes BMW switch entity."""
27 
28  value_fn: Callable[[MyBMWVehicle], bool]
29  remote_service_on: Callable[[MyBMWVehicle], Coroutine[Any, Any, Any]]
30  remote_service_off: Callable[[MyBMWVehicle], Coroutine[Any, Any, Any]]
31  is_available: Callable[[MyBMWVehicle], bool] = lambda _: False
32  dynamic_options: Callable[[MyBMWVehicle], list[str]] | None = None
33 
34 
35 CHARGING_STATE_ON = {
36  ChargingState.CHARGING,
37  ChargingState.COMPLETE,
38  ChargingState.FULLY_CHARGED,
39  ChargingState.FINISHED_FULLY_CHARGED,
40  ChargingState.FINISHED_NOT_FULL,
41  ChargingState.TARGET_REACHED,
42 }
43 
44 NUMBER_TYPES: list[BMWSwitchEntityDescription] = [
46  key="climate",
47  translation_key="climate",
48  is_available=lambda v: v.is_remote_climate_stop_enabled,
49  value_fn=lambda v: v.climate.is_climate_on,
50  remote_service_on=lambda v: v.remote_services.trigger_remote_air_conditioning(),
51  remote_service_off=lambda v: v.remote_services.trigger_remote_air_conditioning_stop(),
52  ),
54  key="charging",
55  translation_key="charging",
56  is_available=lambda v: v.is_remote_charge_stop_enabled,
57  value_fn=lambda v: v.fuel_and_battery.charging_status in CHARGING_STATE_ON,
58  remote_service_on=lambda v: v.remote_services.trigger_charge_start(),
59  remote_service_off=lambda v: v.remote_services.trigger_charge_stop(),
60  ),
61 ]
62 
63 
65  hass: HomeAssistant,
66  config_entry: BMWConfigEntry,
67  async_add_entities: AddEntitiesCallback,
68 ) -> None:
69  """Set up the MyBMW switch from config entry."""
70  coordinator = config_entry.runtime_data.coordinator
71 
72  entities: list[BMWSwitch] = []
73 
74  for vehicle in coordinator.account.vehicles:
75  if not coordinator.read_only:
76  entities.extend(
77  [
78  BMWSwitch(coordinator, vehicle, description)
79  for description in NUMBER_TYPES
80  if description.is_available(vehicle)
81  ]
82  )
83  async_add_entities(entities)
84 
85 
87  """Representation of BMW Switch entity."""
88 
89  entity_description: BMWSwitchEntityDescription
90 
91  def __init__(
92  self,
93  coordinator: BMWDataUpdateCoordinator,
94  vehicle: MyBMWVehicle,
95  description: BMWSwitchEntityDescription,
96  ) -> None:
97  """Initialize an BMW Switch."""
98  super().__init__(coordinator, vehicle)
99  self.entity_descriptionentity_description = description
100  self._attr_unique_id_attr_unique_id = f"{vehicle.vin}-{description.key}"
101 
102  @property
103  def is_on(self) -> bool:
104  """Return the entity value to represent the entity state."""
105  return self.entity_descriptionentity_description.value_fn(self.vehiclevehicle)
106 
107  async def async_turn_on(self, **kwargs: Any) -> None:
108  """Turn the switch on."""
109  try:
110  await self.entity_descriptionentity_description.remote_service_on(self.vehiclevehicle)
111  except MyBMWAPIError as ex:
112  raise HomeAssistantError(ex) from ex
113 
114  self.coordinator.async_update_listeners()
115 
116  async def async_turn_off(self, **kwargs: Any) -> None:
117  """Turn the switch off."""
118  try:
119  await self.entity_descriptionentity_description.remote_service_off(self.vehiclevehicle)
120  except MyBMWAPIError as ex:
121  raise HomeAssistantError(ex) from ex
122 
123  self.coordinator.async_update_listeners()
None __init__(self, BMWDataUpdateCoordinator coordinator, MyBMWVehicle vehicle, BMWSwitchEntityDescription description)
Definition: switch.py:96
None async_setup_entry(HomeAssistant hass, BMWConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:68