Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Sensor 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 datetime import timedelta
8 from itertools import chain
9 from typing import cast
10 
12  RestoreSensor,
13  SensorDeviceClass,
14  SensorEntity,
15  SensorEntityDescription,
16  SensorStateClass,
17 )
18 from homeassistant.const import (
19  PERCENTAGE,
20  EntityCategory,
21  UnitOfElectricCurrent,
22  UnitOfElectricPotential,
23  UnitOfEnergy,
24  UnitOfLength,
25  UnitOfPower,
26  UnitOfPressure,
27  UnitOfSpeed,
28  UnitOfTemperature,
29  UnitOfTime,
30 )
31 from homeassistant.core import HomeAssistant
32 from homeassistant.helpers.entity_platform import AddEntitiesCallback
33 from homeassistant.helpers.typing import StateType
34 from homeassistant.util import dt as dt_util
35 from homeassistant.util.variance import ignore_variance
36 
37 from . import TeslaFleetConfigEntry
38 from .const import TeslaFleetState
39 from .entity import (
40  TeslaFleetEnergyInfoEntity,
41  TeslaFleetEnergyLiveEntity,
42  TeslaFleetVehicleEntity,
43  TeslaFleetWallConnectorEntity,
44 )
45 from .models import TeslaFleetEnergyData, TeslaFleetVehicleData
46 
47 PARALLEL_UPDATES = 0
48 
49 CHARGE_STATES = {
50  "Starting": "starting",
51  "Charging": "charging",
52  "Stopped": "stopped",
53  "Complete": "complete",
54  "Disconnected": "disconnected",
55  "NoPower": "no_power",
56 }
57 
58 SHIFT_STATES = {"P": "p", "D": "d", "R": "r", "N": "n"}
59 
60 
61 @dataclass(frozen=True, kw_only=True)
63  """Describes Tesla Fleet Sensor entity."""
64 
65  value_fn: Callable[[StateType], StateType] = lambda x: x
66 
67 
68 VEHICLE_DESCRIPTIONS: tuple[TeslaFleetSensorEntityDescription, ...] = (
70  key="charge_state_charging_state",
71  options=list(CHARGE_STATES.values()),
72  device_class=SensorDeviceClass.ENUM,
73  value_fn=lambda value: CHARGE_STATES.get(cast(str, value)),
74  ),
76  key="charge_state_battery_level",
77  state_class=SensorStateClass.MEASUREMENT,
78  native_unit_of_measurement=PERCENTAGE,
79  device_class=SensorDeviceClass.BATTERY,
80  ),
82  key="charge_state_usable_battery_level",
83  state_class=SensorStateClass.MEASUREMENT,
84  native_unit_of_measurement=PERCENTAGE,
85  device_class=SensorDeviceClass.BATTERY,
86  entity_registry_enabled_default=False,
87  ),
89  key="charge_state_charge_energy_added",
90  state_class=SensorStateClass.TOTAL_INCREASING,
91  native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
92  device_class=SensorDeviceClass.ENERGY,
93  suggested_display_precision=1,
94  ),
96  key="charge_state_charger_power",
97  state_class=SensorStateClass.MEASUREMENT,
98  native_unit_of_measurement=UnitOfPower.KILO_WATT,
99  device_class=SensorDeviceClass.POWER,
100  ),
102  key="charge_state_charger_voltage",
103  state_class=SensorStateClass.MEASUREMENT,
104  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
105  device_class=SensorDeviceClass.VOLTAGE,
106  entity_category=EntityCategory.DIAGNOSTIC,
107  ),
109  key="charge_state_charger_actual_current",
110  state_class=SensorStateClass.MEASUREMENT,
111  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
112  device_class=SensorDeviceClass.CURRENT,
113  entity_category=EntityCategory.DIAGNOSTIC,
114  ),
116  key="charge_state_charge_rate",
117  state_class=SensorStateClass.MEASUREMENT,
118  native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
119  device_class=SensorDeviceClass.SPEED,
120  entity_category=EntityCategory.DIAGNOSTIC,
121  ),
123  key="charge_state_conn_charge_cable",
124  entity_category=EntityCategory.DIAGNOSTIC,
125  entity_registry_enabled_default=False,
126  ),
128  key="charge_state_fast_charger_type",
129  entity_category=EntityCategory.DIAGNOSTIC,
130  entity_registry_enabled_default=False,
131  ),
133  key="charge_state_battery_range",
134  state_class=SensorStateClass.MEASUREMENT,
135  native_unit_of_measurement=UnitOfLength.MILES,
136  device_class=SensorDeviceClass.DISTANCE,
137  suggested_display_precision=1,
138  ),
140  key="charge_state_est_battery_range",
141  state_class=SensorStateClass.MEASUREMENT,
142  native_unit_of_measurement=UnitOfLength.MILES,
143  device_class=SensorDeviceClass.DISTANCE,
144  suggested_display_precision=1,
145  entity_registry_enabled_default=False,
146  ),
148  key="charge_state_ideal_battery_range",
149  state_class=SensorStateClass.MEASUREMENT,
150  native_unit_of_measurement=UnitOfLength.MILES,
151  device_class=SensorDeviceClass.DISTANCE,
152  suggested_display_precision=1,
153  entity_registry_enabled_default=False,
154  ),
156  key="drive_state_speed",
157  state_class=SensorStateClass.MEASUREMENT,
158  native_unit_of_measurement=UnitOfSpeed.MILES_PER_HOUR,
159  device_class=SensorDeviceClass.SPEED,
160  entity_registry_enabled_default=False,
161  value_fn=lambda value: value or 0,
162  ),
164  key="drive_state_power",
165  state_class=SensorStateClass.MEASUREMENT,
166  native_unit_of_measurement=UnitOfPower.KILO_WATT,
167  device_class=SensorDeviceClass.POWER,
168  entity_category=EntityCategory.DIAGNOSTIC,
169  entity_registry_enabled_default=False,
170  value_fn=lambda value: value or 0,
171  ),
173  key="drive_state_shift_state",
174  options=list(SHIFT_STATES.values()),
175  device_class=SensorDeviceClass.ENUM,
176  value_fn=lambda x: SHIFT_STATES.get(str(x), "p"),
177  entity_registry_enabled_default=False,
178  ),
180  key="vehicle_state_odometer",
181  state_class=SensorStateClass.TOTAL_INCREASING,
182  native_unit_of_measurement=UnitOfLength.MILES,
183  device_class=SensorDeviceClass.DISTANCE,
184  suggested_display_precision=0,
185  entity_category=EntityCategory.DIAGNOSTIC,
186  entity_registry_enabled_default=False,
187  ),
189  key="vehicle_state_tpms_pressure_fl",
190  state_class=SensorStateClass.MEASUREMENT,
191  native_unit_of_measurement=UnitOfPressure.BAR,
192  suggested_unit_of_measurement=UnitOfPressure.PSI,
193  device_class=SensorDeviceClass.PRESSURE,
194  suggested_display_precision=1,
195  entity_category=EntityCategory.DIAGNOSTIC,
196  entity_registry_enabled_default=False,
197  ),
199  key="vehicle_state_tpms_pressure_fr",
200  state_class=SensorStateClass.MEASUREMENT,
201  native_unit_of_measurement=UnitOfPressure.BAR,
202  suggested_unit_of_measurement=UnitOfPressure.PSI,
203  device_class=SensorDeviceClass.PRESSURE,
204  suggested_display_precision=1,
205  entity_category=EntityCategory.DIAGNOSTIC,
206  entity_registry_enabled_default=False,
207  ),
209  key="vehicle_state_tpms_pressure_rl",
210  state_class=SensorStateClass.MEASUREMENT,
211  native_unit_of_measurement=UnitOfPressure.BAR,
212  suggested_unit_of_measurement=UnitOfPressure.PSI,
213  device_class=SensorDeviceClass.PRESSURE,
214  suggested_display_precision=1,
215  entity_category=EntityCategory.DIAGNOSTIC,
216  entity_registry_enabled_default=False,
217  ),
219  key="vehicle_state_tpms_pressure_rr",
220  state_class=SensorStateClass.MEASUREMENT,
221  native_unit_of_measurement=UnitOfPressure.BAR,
222  suggested_unit_of_measurement=UnitOfPressure.PSI,
223  device_class=SensorDeviceClass.PRESSURE,
224  suggested_display_precision=1,
225  entity_category=EntityCategory.DIAGNOSTIC,
226  entity_registry_enabled_default=False,
227  ),
229  key="climate_state_inside_temp",
230  state_class=SensorStateClass.MEASUREMENT,
231  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
232  device_class=SensorDeviceClass.TEMPERATURE,
233  suggested_display_precision=1,
234  ),
236  key="climate_state_outside_temp",
237  state_class=SensorStateClass.MEASUREMENT,
238  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
239  device_class=SensorDeviceClass.TEMPERATURE,
240  suggested_display_precision=1,
241  ),
243  key="climate_state_driver_temp_setting",
244  state_class=SensorStateClass.MEASUREMENT,
245  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
246  device_class=SensorDeviceClass.TEMPERATURE,
247  suggested_display_precision=1,
248  entity_category=EntityCategory.DIAGNOSTIC,
249  entity_registry_enabled_default=False,
250  ),
252  key="climate_state_passenger_temp_setting",
253  state_class=SensorStateClass.MEASUREMENT,
254  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
255  device_class=SensorDeviceClass.TEMPERATURE,
256  suggested_display_precision=1,
257  entity_category=EntityCategory.DIAGNOSTIC,
258  entity_registry_enabled_default=False,
259  ),
261  key="drive_state_active_route_traffic_minutes_delay",
262  state_class=SensorStateClass.MEASUREMENT,
263  native_unit_of_measurement=UnitOfTime.MINUTES,
264  device_class=SensorDeviceClass.DURATION,
265  entity_registry_enabled_default=False,
266  ),
268  key="drive_state_active_route_energy_at_arrival",
269  state_class=SensorStateClass.MEASUREMENT,
270  native_unit_of_measurement=PERCENTAGE,
271  device_class=SensorDeviceClass.BATTERY,
272  entity_category=EntityCategory.DIAGNOSTIC,
273  entity_registry_enabled_default=False,
274  ),
276  key="drive_state_active_route_miles_to_arrival",
277  state_class=SensorStateClass.MEASUREMENT,
278  native_unit_of_measurement=UnitOfLength.MILES,
279  device_class=SensorDeviceClass.DISTANCE,
280  ),
281 )
282 
283 
284 @dataclass(frozen=True, kw_only=True)
286  """Describes Tesla Fleet Sensor entity."""
287 
288  variance: int
289 
290 
291 VEHICLE_TIME_DESCRIPTIONS: tuple[TeslaFleetTimeEntityDescription, ...] = (
293  key="charge_state_minutes_to_full_charge",
294  device_class=SensorDeviceClass.TIMESTAMP,
295  entity_category=EntityCategory.DIAGNOSTIC,
296  variance=4,
297  ),
299  key="drive_state_active_route_minutes_to_arrival",
300  device_class=SensorDeviceClass.TIMESTAMP,
301  variance=1,
302  ),
303 )
304 
305 ENERGY_LIVE_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
307  key="solar_power",
308  state_class=SensorStateClass.MEASUREMENT,
309  native_unit_of_measurement=UnitOfPower.WATT,
310  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
311  suggested_display_precision=2,
312  device_class=SensorDeviceClass.POWER,
313  ),
315  key="energy_left",
316  state_class=SensorStateClass.MEASUREMENT,
317  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
318  suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
319  suggested_display_precision=2,
320  device_class=SensorDeviceClass.ENERGY_STORAGE,
321  entity_category=EntityCategory.DIAGNOSTIC,
322  ),
324  key="total_pack_energy",
325  state_class=SensorStateClass.MEASUREMENT,
326  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
327  suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
328  suggested_display_precision=2,
329  device_class=SensorDeviceClass.ENERGY_STORAGE,
330  entity_category=EntityCategory.DIAGNOSTIC,
331  entity_registry_enabled_default=False,
332  ),
334  key="percentage_charged",
335  state_class=SensorStateClass.MEASUREMENT,
336  native_unit_of_measurement=PERCENTAGE,
337  device_class=SensorDeviceClass.BATTERY,
338  suggested_display_precision=2,
339  ),
341  key="battery_power",
342  state_class=SensorStateClass.MEASUREMENT,
343  native_unit_of_measurement=UnitOfPower.WATT,
344  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
345  suggested_display_precision=2,
346  device_class=SensorDeviceClass.POWER,
347  ),
349  key="load_power",
350  state_class=SensorStateClass.MEASUREMENT,
351  native_unit_of_measurement=UnitOfPower.WATT,
352  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
353  suggested_display_precision=2,
354  device_class=SensorDeviceClass.POWER,
355  ),
357  key="grid_power",
358  state_class=SensorStateClass.MEASUREMENT,
359  native_unit_of_measurement=UnitOfPower.WATT,
360  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
361  suggested_display_precision=2,
362  device_class=SensorDeviceClass.POWER,
363  ),
365  key="grid_services_power",
366  state_class=SensorStateClass.MEASUREMENT,
367  native_unit_of_measurement=UnitOfPower.WATT,
368  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
369  suggested_display_precision=2,
370  device_class=SensorDeviceClass.POWER,
371  ),
373  key="generator_power",
374  state_class=SensorStateClass.MEASUREMENT,
375  native_unit_of_measurement=UnitOfPower.WATT,
376  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
377  suggested_display_precision=2,
378  device_class=SensorDeviceClass.POWER,
379  entity_registry_enabled_default=False,
380  ),
382  key="island_status",
383  options=[
384  "island_status_unknown",
385  "on_grid",
386  "off_grid",
387  "off_grid_unintentional",
388  "off_grid_intentional",
389  ],
390  device_class=SensorDeviceClass.ENUM,
391  ),
392 )
393 
394 WALL_CONNECTOR_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
396  key="wall_connector_state",
397  entity_category=EntityCategory.DIAGNOSTIC,
398  entity_registry_enabled_default=False,
399  ),
401  key="wall_connector_fault_state",
402  entity_category=EntityCategory.DIAGNOSTIC,
403  entity_registry_enabled_default=False,
404  ),
406  key="wall_connector_power",
407  state_class=SensorStateClass.MEASUREMENT,
408  native_unit_of_measurement=UnitOfPower.WATT,
409  suggested_unit_of_measurement=UnitOfPower.KILO_WATT,
410  suggested_display_precision=2,
411  device_class=SensorDeviceClass.POWER,
412  ),
414  key="vin",
415  ),
416 )
417 
418 ENERGY_INFO_DESCRIPTIONS: tuple[SensorEntityDescription, ...] = (
420  key="vpp_backup_reserve_percent",
421  entity_category=EntityCategory.DIAGNOSTIC,
422  device_class=SensorDeviceClass.BATTERY,
423  native_unit_of_measurement=PERCENTAGE,
424  ),
425  SensorEntityDescription(key="version"),
426 )
427 
428 
430  hass: HomeAssistant,
431  entry: TeslaFleetConfigEntry,
432  async_add_entities: AddEntitiesCallback,
433 ) -> None:
434  """Set up the Tesla Fleet sensor platform from a config entry."""
436  chain(
437  ( # Add vehicles
438  TeslaFleetVehicleSensorEntity(vehicle, description)
439  for vehicle in entry.runtime_data.vehicles
440  for description in VEHICLE_DESCRIPTIONS
441  ),
442  ( # Add vehicles time sensors
443  TeslaFleetVehicleTimeSensorEntity(vehicle, description)
444  for vehicle in entry.runtime_data.vehicles
445  for description in VEHICLE_TIME_DESCRIPTIONS
446  ),
447  ( # Add energy site live
448  TeslaFleetEnergyLiveSensorEntity(energysite, description)
449  for energysite in entry.runtime_data.energysites
450  for description in ENERGY_LIVE_DESCRIPTIONS
451  if description.key in energysite.live_coordinator.data
452  ),
453  ( # Add wall connectors
454  TeslaFleetWallConnectorSensorEntity(energysite, wc["din"], description)
455  for energysite in entry.runtime_data.energysites
456  for wc in energysite.info_coordinator.data.get(
457  "components_wall_connectors", []
458  )
459  if "din" in wc
460  for description in WALL_CONNECTOR_DESCRIPTIONS
461  ),
462  ( # Add energy site info
463  TeslaFleetEnergyInfoSensorEntity(energysite, description)
464  for energysite in entry.runtime_data.energysites
465  for description in ENERGY_INFO_DESCRIPTIONS
466  if description.key in energysite.info_coordinator.data
467  ),
468  )
469  )
470 
471 
473  """Base class for Tesla Fleet vehicle metric sensors."""
474 
475  entity_description: TeslaFleetSensorEntityDescription
476 
477  def __init__(
478  self,
479  data: TeslaFleetVehicleData,
480  description: TeslaFleetSensorEntityDescription,
481  ) -> None:
482  """Initialize the sensor."""
483  self.entity_descriptionentity_description = description
484  super().__init__(data, description.key)
485 
486  async def async_added_to_hass(self) -> None:
487  """Handle entity which will be added."""
488  await super().async_added_to_hass()
489  if self.coordinator.data.get("state") != TeslaFleetState.ONLINE:
490  if (sensor_data := await self.async_get_last_sensor_dataasync_get_last_sensor_data()) is not None:
491  self._attr_native_value_attr_native_value = sensor_data.native_value
492 
493  def _async_update_attrs(self) -> None:
494  """Update the attributes of the sensor."""
495  if self.hashas:
496  self._attr_native_value_attr_native_value = self.entity_descriptionentity_description.value_fn(self._value_value_value)
497  else:
498  self._attr_native_value_attr_native_value = None
499 
500 
502  """Base class for Tesla Fleet vehicle time sensors."""
503 
504  entity_description: TeslaFleetTimeEntityDescription
505 
506  def __init__(
507  self,
508  data: TeslaFleetVehicleData,
509  description: TeslaFleetTimeEntityDescription,
510  ) -> None:
511  """Initialize the sensor."""
512  self.entity_descriptionentity_description = description
513  self._get_timestamp_get_timestamp = ignore_variance(
514  func=lambda value: dt_util.now() + timedelta(minutes=value),
515  ignored_variance=timedelta(minutes=description.variance),
516  )
517 
518  super().__init__(data, description.key)
519 
520  def _async_update_attrs(self) -> None:
521  """Update the attributes of the sensor."""
522  self._attr_available_attr_available = isinstance(self._value_value_value, int | float) and self._value_value_value > 0
523  if self._attr_available_attr_available:
524  self._attr_native_value_attr_native_value = self._get_timestamp_get_timestamp(self._value_value_value)
525 
526 
528  """Base class for Tesla Fleet energy site metric sensors."""
529 
530  entity_description: SensorEntityDescription
531 
532  def __init__(
533  self,
534  data: TeslaFleetEnergyData,
535  description: SensorEntityDescription,
536  ) -> None:
537  """Initialize the sensor."""
538  self.entity_descriptionentity_description = description
539  super().__init__(data, description.key)
540 
541  def _async_update_attrs(self) -> None:
542  """Update the attributes of the sensor."""
543  self._attr_available_attr_available = not self.is_noneis_none
544  self._attr_native_value_attr_native_value = self._value_value
545 
546 
548  """Base class for Tesla Fleet energy site metric sensors."""
549 
550  entity_description: SensorEntityDescription
551 
552  def __init__(
553  self,
554  data: TeslaFleetEnergyData,
555  din: str,
556  description: SensorEntityDescription,
557  ) -> None:
558  """Initialize the sensor."""
559  self.entity_descriptionentity_description = description
560  super().__init__(
561  data,
562  din,
563  description.key,
564  )
565 
566  def _async_update_attrs(self) -> None:
567  """Update the attributes of the sensor."""
568  self._attr_available_attr_available = not self.is_noneis_none
569  self._attr_native_value_attr_native_value = self._value_value_value
570 
571 
573  """Base class for Tesla Fleet energy site metric sensors."""
574 
575  entity_description: SensorEntityDescription
576 
577  def __init__(
578  self,
579  data: TeslaFleetEnergyData,
580  description: SensorEntityDescription,
581  ) -> None:
582  """Initialize the sensor."""
583  self.entity_descriptionentity_description = description
584  super().__init__(data, description.key)
585 
586  def _async_update_attrs(self) -> None:
587  """Update the attributes of the sensor."""
588  self._attr_available_attr_available = not self.is_noneis_none
589  self._attr_native_value_attr_native_value = self._value_value
SensorExtraStoredData|None async_get_last_sensor_data(self)
Definition: __init__.py:934
None __init__(self, TeslaFleetEnergyData data, SensorEntityDescription description)
Definition: sensor.py:581
None __init__(self, TeslaFleetEnergyData data, SensorEntityDescription description)
Definition: sensor.py:536
None __init__(self, TeslaFleetVehicleData data, TeslaFleetSensorEntityDescription description)
Definition: sensor.py:481
None __init__(self, TeslaFleetVehicleData data, TeslaFleetTimeEntityDescription description)
Definition: sensor.py:510
None __init__(self, TeslaFleetEnergyData data, str din, SensorEntityDescription description)
Definition: sensor.py:557
None async_setup_entry(HomeAssistant hass, TeslaFleetConfigEntry entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:433