-
-
Notifications
You must be signed in to change notification settings - Fork 28.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add binary sensor platform to Teslemetry (#117230)
* Add binary sensor platform * Add tests * Cleanup * Add refresh test * Fix runtime_data after rebase * Remove streaming strings * test error * updated_once * fix updated_once * assert_entities_alt * Update homeassistant/components/teslemetry/binary_sensor.py Co-authored-by: G Johansson <goran.johansson@shiftit.se> --------- Co-authored-by: G Johansson <goran.johansson@shiftit.se>
- Loading branch information
1 parent
8da799e
commit ad90ece
Showing
8 changed files
with
3,601 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,271 @@ | ||
"""Binary Sensor platform for Teslemetry integration.""" | ||
|
||
from __future__ import annotations | ||
|
||
from collections.abc import Callable | ||
from dataclasses import dataclass | ||
from itertools import chain | ||
from typing import cast | ||
|
||
from homeassistant.components.binary_sensor import ( | ||
BinarySensorDeviceClass, | ||
BinarySensorEntity, | ||
BinarySensorEntityDescription, | ||
) | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import EntityCategory | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||
from homeassistant.helpers.typing import StateType | ||
|
||
from .const import TeslemetryState | ||
from .entity import ( | ||
TeslemetryEnergyInfoEntity, | ||
TeslemetryEnergyLiveEntity, | ||
TeslemetryVehicleEntity, | ||
) | ||
from .models import TeslemetryEnergyData, TeslemetryVehicleData | ||
|
||
|
||
@dataclass(frozen=True, kw_only=True) | ||
class TeslemetryBinarySensorEntityDescription(BinarySensorEntityDescription): | ||
"""Describes Teslemetry binary sensor entity.""" | ||
|
||
is_on: Callable[[StateType], bool] = bool | ||
|
||
|
||
VEHICLE_DESCRIPTIONS: tuple[TeslemetryBinarySensorEntityDescription, ...] = ( | ||
TeslemetryBinarySensorEntityDescription( | ||
key="state", | ||
device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||
is_on=lambda x: x == TeslemetryState.ONLINE, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_battery_heater_on", | ||
device_class=BinarySensorDeviceClass.HEAT, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_charger_phases", | ||
is_on=lambda x: cast(int, x) > 1, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_preconditioning_enabled", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="climate_state_is_preconditioning", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_scheduled_charging_pending", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_trip_charging", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="charge_state_conn_charge_cable", | ||
is_on=lambda x: x != "<invalid>", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
device_class=BinarySensorDeviceClass.CONNECTIVITY, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="climate_state_cabin_overheat_protection_actively_cooling", | ||
device_class=BinarySensorDeviceClass.HEAT, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_dashcam_state", | ||
device_class=BinarySensorDeviceClass.RUNNING, | ||
is_on=lambda x: x == "Recording", | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_is_user_present", | ||
device_class=BinarySensorDeviceClass.PRESENCE, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_tpms_soft_warning_fl", | ||
device_class=BinarySensorDeviceClass.PROBLEM, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_tpms_soft_warning_fr", | ||
device_class=BinarySensorDeviceClass.PROBLEM, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_tpms_soft_warning_rl", | ||
device_class=BinarySensorDeviceClass.PROBLEM, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_tpms_soft_warning_rr", | ||
device_class=BinarySensorDeviceClass.PROBLEM, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
entity_registry_enabled_default=False, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_fd_window", | ||
device_class=BinarySensorDeviceClass.WINDOW, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_fp_window", | ||
device_class=BinarySensorDeviceClass.WINDOW, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_rd_window", | ||
device_class=BinarySensorDeviceClass.WINDOW, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_rp_window", | ||
device_class=BinarySensorDeviceClass.WINDOW, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_df", | ||
device_class=BinarySensorDeviceClass.DOOR, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_dr", | ||
device_class=BinarySensorDeviceClass.DOOR, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_pf", | ||
device_class=BinarySensorDeviceClass.DOOR, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
TeslemetryBinarySensorEntityDescription( | ||
key="vehicle_state_pr", | ||
device_class=BinarySensorDeviceClass.DOOR, | ||
entity_category=EntityCategory.DIAGNOSTIC, | ||
), | ||
) | ||
|
||
ENERGY_LIVE_DESCRIPTIONS: tuple[BinarySensorEntityDescription, ...] = ( | ||
BinarySensorEntityDescription(key="backup_capable"), | ||
BinarySensorEntityDescription(key="grid_services_active"), | ||
) | ||
|
||
|
||
ENERGY_INFO_DESCRIPTIONS: tuple[BinarySensorEntityDescription, ...] = ( | ||
BinarySensorEntityDescription( | ||
key="components_grid_services_enabled", | ||
), | ||
) | ||
|
||
|
||
async def async_setup_entry( | ||
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback | ||
) -> None: | ||
"""Set up the Teslemetry binary sensor platform from a config entry.""" | ||
|
||
async_add_entities( | ||
chain( | ||
( # Vehicles | ||
TeslemetryVehicleBinarySensorEntity(vehicle, description) | ||
for vehicle in entry.runtime_data.vehicles | ||
for description in VEHICLE_DESCRIPTIONS | ||
), | ||
( # Energy Site Live | ||
TeslemetryEnergyLiveBinarySensorEntity(energysite, description) | ||
for energysite in entry.runtime_data.energysites | ||
for description in ENERGY_LIVE_DESCRIPTIONS | ||
if energysite.info_coordinator.data.get("components_battery") | ||
), | ||
( # Energy Site Info | ||
TeslemetryEnergyInfoBinarySensorEntity(energysite, description) | ||
for energysite in entry.runtime_data.energysites | ||
for description in ENERGY_INFO_DESCRIPTIONS | ||
if energysite.info_coordinator.data.get("components_battery") | ||
), | ||
) | ||
) | ||
|
||
|
||
class TeslemetryVehicleBinarySensorEntity(TeslemetryVehicleEntity, BinarySensorEntity): | ||
"""Base class for Teslemetry vehicle binary sensors.""" | ||
|
||
entity_description: TeslemetryBinarySensorEntityDescription | ||
|
||
def __init__( | ||
self, | ||
data: TeslemetryVehicleData, | ||
description: TeslemetryBinarySensorEntityDescription, | ||
) -> None: | ||
"""Initialize the binary sensor.""" | ||
self.entity_description = description | ||
super().__init__(data, description.key) | ||
|
||
def _async_update_attrs(self) -> None: | ||
"""Update the attributes of the binary sensor.""" | ||
|
||
if self.coordinator.updated_once: | ||
if self._value is None: | ||
self._attr_available = False | ||
self._attr_is_on = None | ||
else: | ||
self._attr_available = True | ||
self._attr_is_on = self.entity_description.is_on(self._value) | ||
else: | ||
self._attr_is_on = None | ||
|
||
|
||
class TeslemetryEnergyLiveBinarySensorEntity( | ||
TeslemetryEnergyLiveEntity, BinarySensorEntity | ||
): | ||
"""Base class for Teslemetry energy live binary sensors.""" | ||
|
||
entity_description: BinarySensorEntityDescription | ||
|
||
def __init__( | ||
self, | ||
data: TeslemetryEnergyData, | ||
description: BinarySensorEntityDescription, | ||
) -> None: | ||
"""Initialize the binary sensor.""" | ||
self.entity_description = description | ||
super().__init__(data, description.key) | ||
|
||
def _async_update_attrs(self) -> None: | ||
"""Update the attributes of the binary sensor.""" | ||
self._attr_is_on = self._value | ||
|
||
|
||
class TeslemetryEnergyInfoBinarySensorEntity( | ||
TeslemetryEnergyInfoEntity, BinarySensorEntity | ||
): | ||
"""Base class for Teslemetry energy info binary sensors.""" | ||
|
||
entity_description: BinarySensorEntityDescription | ||
|
||
def __init__( | ||
self, | ||
data: TeslemetryEnergyData, | ||
description: BinarySensorEntityDescription, | ||
) -> None: | ||
"""Initialize the binary sensor.""" | ||
self.entity_description = description | ||
super().__init__(data, description.key) | ||
|
||
def _async_update_attrs(self) -> None: | ||
"""Update the attributes of the binary sensor.""" | ||
self._attr_is_on = self._value |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.