Home Assistant Unofficial Reference 2024.12.1
switch.py
Go to the documentation of this file.
1 """Switch platform for Tesla Fleet integration."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from itertools import chain
8 from typing import Any
9 
10 from tesla_fleet_api.const import Scope, Seat
11 
13  SwitchDeviceClass,
14  SwitchEntity,
15  SwitchEntityDescription,
16 )
17 from homeassistant.core import HomeAssistant
18 from homeassistant.helpers.entity_platform import AddEntitiesCallback
19 
20 from . import TeslaFleetConfigEntry
21 from .entity import TeslaFleetEnergyInfoEntity, TeslaFleetVehicleEntity
22 from .helpers import handle_command, handle_vehicle_command
23 from .models import TeslaFleetEnergyData, TeslaFleetVehicleData
24 
25 PARALLEL_UPDATES = 0
26 
27 
28 @dataclass(frozen=True, kw_only=True)
30  """Describes TeslaFleet Switch entity."""
31 
32  on_func: Callable
33  off_func: Callable
34  scopes: list[Scope]
35 
36 
37 VEHICLE_DESCRIPTIONS: tuple[TeslaFleetSwitchEntityDescription, ...] = (
39  key="vehicle_state_sentry_mode",
40  on_func=lambda api: api.set_sentry_mode(on=True),
41  off_func=lambda api: api.set_sentry_mode(on=False),
42  scopes=[Scope.VEHICLE_CMDS],
43  ),
45  key="climate_state_auto_seat_climate_left",
46  on_func=lambda api: api.remote_auto_seat_climate_request(Seat.FRONT_LEFT, True),
47  off_func=lambda api: api.remote_auto_seat_climate_request(
48  Seat.FRONT_LEFT, False
49  ),
50  scopes=[Scope.VEHICLE_CMDS],
51  ),
53  key="climate_state_auto_seat_climate_right",
54  on_func=lambda api: api.remote_auto_seat_climate_request(
55  Seat.FRONT_RIGHT, True
56  ),
57  off_func=lambda api: api.remote_auto_seat_climate_request(
58  Seat.FRONT_RIGHT, False
59  ),
60  scopes=[Scope.VEHICLE_CMDS],
61  ),
63  key="climate_state_auto_steering_wheel_heat",
64  on_func=lambda api: api.remote_auto_steering_wheel_heat_climate_request(
65  on=True
66  ),
67  off_func=lambda api: api.remote_auto_steering_wheel_heat_climate_request(
68  on=False
69  ),
70  scopes=[Scope.VEHICLE_CMDS],
71  ),
73  key="climate_state_defrost_mode",
74  on_func=lambda api: api.set_preconditioning_max(on=True, manual_override=False),
75  off_func=lambda api: api.set_preconditioning_max(
76  on=False, manual_override=False
77  ),
78  scopes=[Scope.VEHICLE_CMDS],
79  ),
80 )
81 
82 VEHICLE_CHARGE_DESCRIPTION = TeslaFleetSwitchEntityDescription(
83  key="charge_state_user_charge_enable_request",
84  on_func=lambda api: api.charge_start(),
85  off_func=lambda api: api.charge_stop(),
86  scopes=[Scope.VEHICLE_CHARGING_CMDS, Scope.VEHICLE_CMDS],
87 )
88 
89 
91  hass: HomeAssistant,
92  entry: TeslaFleetConfigEntry,
93  async_add_entities: AddEntitiesCallback,
94 ) -> None:
95  """Set up the TeslaFleet Switch platform from a config entry."""
96 
98  chain(
99  (
101  vehicle, description, entry.runtime_data.scopes
102  )
103  for vehicle in entry.runtime_data.vehicles
104  for description in VEHICLE_DESCRIPTIONS
105  ),
106  (
108  vehicle, VEHICLE_CHARGE_DESCRIPTION, entry.runtime_data.scopes
109  )
110  for vehicle in entry.runtime_data.vehicles
111  ),
112  (
114  energysite,
115  entry.runtime_data.scopes,
116  )
117  for energysite in entry.runtime_data.energysites
118  if energysite.info_coordinator.data.get("components_battery")
119  and energysite.info_coordinator.data.get("components_solar")
120  ),
121  (
122  TeslaFleetStormModeSwitchEntity(energysite, entry.runtime_data.scopes)
123  for energysite in entry.runtime_data.energysites
124  if energysite.info_coordinator.data.get("components_storm_mode_capable")
125  ),
126  )
127  )
128 
129 
131  """Base class for all TeslaFleet switch entities."""
132 
133  _attr_device_class = SwitchDeviceClass.SWITCH
134  entity_description: TeslaFleetSwitchEntityDescription
135 
136 
138  """Base class for TeslaFleet vehicle switch entities."""
139 
140  def __init__(
141  self,
142  data: TeslaFleetVehicleData,
143  description: TeslaFleetSwitchEntityDescription,
144  scopes: list[Scope],
145  ) -> None:
146  """Initialize the Switch."""
147  super().__init__(data, description.key)
148  self.entity_descriptionentity_description = description
149  self.scopedscoped = any(scope in scopes for scope in description.scopes)
150 
151  def _async_update_attrs(self) -> None:
152  """Update the attributes of the sensor."""
153  if self._value_value_value is None:
154  self._attr_is_on_attr_is_on = None
155  else:
156  self._attr_is_on_attr_is_on = bool(self._value_value_value)
157 
158  async def async_turn_on(self, **kwargs: Any) -> None:
159  """Turn on the Switch."""
160  self.raise_for_read_onlyraise_for_read_only(self.entity_descriptionentity_description.scopes[0])
161  await self.wake_up_if_asleepwake_up_if_asleep()
162  await handle_vehicle_command(self.entity_descriptionentity_description.on_func(self.apiapiapiapiapi))
163  self._attr_is_on_attr_is_on = True
164  self.async_write_ha_stateasync_write_ha_state()
165 
166  async def async_turn_off(self, **kwargs: Any) -> None:
167  """Turn off the Switch."""
168  self.raise_for_read_onlyraise_for_read_only(self.entity_descriptionentity_description.scopes[0])
169  await self.wake_up_if_asleepwake_up_if_asleep()
170  await handle_vehicle_command(self.entity_descriptionentity_description.off_func(self.apiapiapiapiapi))
171  self._attr_is_on_attr_is_on = False
172  self.async_write_ha_stateasync_write_ha_state()
173 
174 
176  """Entity class for TeslaFleet charge switch."""
177 
178  def _async_update_attrs(self) -> None:
179  """Update the attributes of the entity."""
180  if self._value_value_value is None:
181  self._attr_is_on_attr_is_on_attr_is_on = self.getget("charge_state_charge_enable_request")
182  else:
183  self._attr_is_on_attr_is_on_attr_is_on = self._value_value_value
184 
185 
187  TeslaFleetEnergyInfoEntity, TeslaFleetSwitchEntity
188 ):
189  """Entity class for Charge From Grid switch."""
190 
191  def __init__(
192  self,
193  data: TeslaFleetEnergyData,
194  scopes: list[Scope],
195  ) -> None:
196  """Initialize the Switch."""
197  self.scopedscoped = Scope.ENERGY_CMDS in scopes
198  super().__init__(
199  data, "components_disallow_charge_from_grid_with_solar_installed"
200  )
201 
202  def _async_update_attrs(self) -> None:
203  """Update the attributes of the entity."""
204  # When disallow_charge_from_grid_with_solar_installed is missing, its Off.
205  # But this sensor is flipped to match how the Tesla app works.
206  self._attr_is_on_attr_is_on = not self.getget(self.keykey, False)
207 
208  async def async_turn_on(self, **kwargs: Any) -> None:
209  """Turn on the Switch."""
210  self.raise_for_read_onlyraise_for_read_only(Scope.ENERGY_CMDS)
211  await handle_command(
212  self.apiapiapiapiapi.grid_import_export(
213  disallow_charge_from_grid_with_solar_installed=False
214  )
215  )
216  self._attr_is_on_attr_is_on = True
217  self.async_write_ha_stateasync_write_ha_state()
218 
219  async def async_turn_off(self, **kwargs: Any) -> None:
220  """Turn off the Switch."""
221  self.raise_for_read_onlyraise_for_read_only(Scope.ENERGY_CMDS)
222  await handle_command(
223  self.apiapiapiapiapi.grid_import_export(
224  disallow_charge_from_grid_with_solar_installed=True
225  )
226  )
227  self._attr_is_on_attr_is_on = False
228  self.async_write_ha_stateasync_write_ha_state()
229 
230 
232  TeslaFleetEnergyInfoEntity, TeslaFleetSwitchEntity
233 ):
234  """Entity class for Storm Mode switch."""
235 
236  def __init__(
237  self,
238  data: TeslaFleetEnergyData,
239  scopes: list[Scope],
240  ) -> None:
241  """Initialize the Switch."""
242  super().__init__(data, "user_settings_storm_mode_enabled")
243  self.scopedscoped = Scope.ENERGY_CMDS in scopes
244 
245  def _async_update_attrs(self) -> None:
246  """Update the attributes of the sensor."""
247  self._attr_available_attr_available = self._value_value is not None
248  self._attr_is_on_attr_is_on = bool(self._value_value)
249 
250  async def async_turn_on(self, **kwargs: Any) -> None:
251  """Turn on the Switch."""
252  self.raise_for_read_onlyraise_for_read_only(Scope.ENERGY_CMDS)
253  await handle_command(self.apiapiapiapiapi.storm_mode(enabled=True))
254  self._attr_is_on_attr_is_on = True
255  self.async_write_ha_stateasync_write_ha_state()
256 
257  async def async_turn_off(self, **kwargs: Any) -> None:
258  """Turn off the Switch."""
259  self.raise_for_read_onlyraise_for_read_only(Scope.ENERGY_CMDS)
260  await handle_command(self.apiapiapiapiapi.storm_mode(enabled=False))
261  self._attr_is_on_attr_is_on = False
262  self.async_write_ha_stateasync_write_ha_state()
Any|None get(self, str key, Any|None default=None)
Definition: entity.py:61
None __init__(self, TeslaFleetEnergyData data, list[Scope] scopes)
Definition: switch.py:195
None __init__(self, TeslaFleetEnergyData data, list[Scope] scopes)
Definition: switch.py:240
None __init__(self, TeslaFleetVehicleData data, TeslaFleetSwitchEntityDescription description, list[Scope] scopes)
Definition: switch.py:145
bool handle_vehicle_command(Awaitable command)
Definition: helpers.py:50
dict[str, Any] handle_command(Awaitable command)
Definition: helpers.py:36
None async_setup_entry(HomeAssistant hass, TeslaFleetConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: switch.py:94