Skip to content

Commit

Permalink
Add TPMS sensors [closes #41] (#42)
Browse files Browse the repository at this point in the history
* Reformat with python black

* Add TPMS sensors [closes #41]
  • Loading branch information
jhansche authored Jun 21, 2024
1 parent bfa8f27 commit d230968
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 12 deletions.
6 changes: 3 additions & 3 deletions custom_components/teslafi/alarm_control_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,9 +132,9 @@ def _handle_coordinator_update(self) -> None:
key="sentry_mode",
name="Sentry Mode",
entity_registry_enabled_default=False,
convert=lambda v: STATE_ALARM_ARMED_AWAY
if _convert_to_bool(v)
else STATE_ALARM_DISARMED,
convert=lambda v: (
STATE_ALARM_ARMED_AWAY if _convert_to_bool(v) else STATE_ALARM_DISARMED
),
),
]

Expand Down
5 changes: 4 additions & 1 deletion custom_components/teslafi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ class TeslaFiSensorEntityDescription(
icons: dict[str, str] = None
"""Dictionary of state -> icon"""

fix_unit: Callable[[TeslaFiVehicle, HomeAssistant], str] = lambda d, h: None
"""Convert the native unit of measurement. Return None to keep the original unit."""


@dataclass
class TeslaFiNumberEntityDescription(
Expand All @@ -156,7 +159,7 @@ class TeslaFiNumberEntityDescription(
):
"""TeslaFi Number EntityDescription"""

convert: Callable[[any], bool] = lambda v: int(v) if v else None
convert: Callable[[any], int] = lambda v: int(v) if v else None
cmd: Callable[[TeslaFiCoordinator, Number], dict] = None

max_value_key: str = None
Expand Down
1 change: 1 addition & 0 deletions custom_components/teslafi/config_flow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Config flow for Bird Buddy integration."""

from __future__ import annotations

from typing import Any
Expand Down
7 changes: 2 additions & 5 deletions custom_components/teslafi/device_tracker.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Device tracker for MyBMW vehicles."""

from __future__ import annotations

from typing import Any
Expand Down Expand Up @@ -42,11 +43,7 @@ def __init__(self, coordinator: TeslaFiCoordinator) -> None:
@property
def extra_state_attributes(self) -> dict[str, Any]:
"""Return entity specific state attributes."""
heading = (
int(h)
if (h := self.coordinator.data.get("heading", None))
else None
)
heading = int(h) if (h := self.coordinator.data.get("heading", None)) else None
cardinal = _degrees_to_cardinal(heading) if heading is not None else None
return {
"heading": heading,
Expand Down
54 changes: 53 additions & 1 deletion custom_components/teslafi/model.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
"""TeslaFi Object Models"""

from collections import UserDict
from dataclasses import dataclass

from typing_extensions import deprecated

from homeassistant.const import UnitOfPressure

from .const import SHIFTER_STATES, VIN_YEARS
from .util import (
_convert_to_bool,
Expand All @@ -12,7 +16,6 @@
_lower_or_none,
)


NAN: float = float("NaN")

CHARGER_CONNECTED_STATES = [
Expand All @@ -24,6 +27,28 @@
]


@dataclass
class TeslaFiTirePressure:
"""TeslaFi Tire Pressure Data."""

front_left: float | None
front_right: float | None
rear_left: float | None
rear_right: float | None
unit: str | None = None

@staticmethod
def convert_unit(unit: str) -> str | None:
"""Convert units to Home Assistant's UnitOfPressure."""
unit_mapping = {
"kpa": UnitOfPressure.KPA,
"bar": UnitOfPressure.BAR,
"psi": UnitOfPressure.PSI,
"mmhg": UnitOfPressure.MMHG,
}
return unit_mapping.get(unit.lower(), None) if unit else None


class TeslaFiVehicle(UserDict):
"""TeslaFi Vehicle Data"""

Expand Down Expand Up @@ -196,3 +221,30 @@ def is_defrosting(self) -> bool | None:
or self.get("is_rear_defroster_on") == "1"
or self.get("defrost_mode", "0") != "0"
)

@property
def tpms(self) -> TeslaFiTirePressure:
"""TPMS state(s): (front-left, front-right, rear-left, rear-right)."""
return TeslaFiTirePressure(
front_left=(
float(tpms_fl)
if (tpms_fl := self.get("tpms_front_left", None))
else None
),
front_right=(
float(tpms_fr)
if (tpms_fr := self.get("tpms_front_right", None))
else None
),
rear_left=(
float(tpms_rl)
if (tpms_rl := self.get("tpms_rear_left", None))
else None
),
rear_right=(
float(tpms_rr)
if (tpms_rr := self.get("tpms_rear_right", None))
else None
),
unit=self.get("pressure", "psi"),
)
64 changes: 62 additions & 2 deletions custom_components/teslafi/sensor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Sensors"""

from typing_extensions import override
from typing import override

from homeassistant.components.sensor import (
SensorDeviceClass,
SensorEntity,
Expand All @@ -16,6 +17,7 @@
UnitOfEnergy,
UnitOfLength,
UnitOfPower,
UnitOfPressure,
UnitOfSpeed,
UnitOfTemperature,
UnitOfTime,
Expand All @@ -26,7 +28,7 @@
from .base import TeslaFiEntity, TeslaFiSensorEntityDescription
from .const import DOMAIN, SHIFTER_STATES
from .coordinator import TeslaFiCoordinator

from .model import TeslaFiTirePressure

SENSORS = [
# region Generic car info
Expand Down Expand Up @@ -187,6 +189,60 @@
),
# ... climate.py
# endregion
# region TPMS
TeslaFiSensorEntityDescription(
key="tpms_front_left",
name="TPMS Front Left",
icon="mdi:car-tire-alert",
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPressure.PSI,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
fix_unit=lambda d, h: TeslaFiTirePressure.convert_unit(d.tpms.unit),
value=lambda d, h: d.tpms.front_left,
available=lambda u, d, h: u and d.tpms.front_left,
),
TeslaFiSensorEntityDescription(
key="tpms_front_right",
name="TPMS Front Right",
icon="mdi:car-tire-alert",
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPressure.PSI,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
fix_unit=lambda d, h: TeslaFiTirePressure.convert_unit(d.tpms.unit),
value=lambda d, h: d.tpms.front_right,
available=lambda u, d, h: u and d.tpms.front_right,
),
TeslaFiSensorEntityDescription(
key="tpms_rear_left",
name="TPMS Rear Left",
icon="mdi:car-tire-alert",
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPressure.PSI,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
fix_unit=lambda d, h: TeslaFiTirePressure.convert_unit(d.tpms.unit),
value=lambda d, h: d.tpms.rear_left,
available=lambda u, d, h: u and d.tpms.rear_left,
),
TeslaFiSensorEntityDescription(
key="tpms_rear_right",
name="TPMS Rear Right",
icon="mdi:car-tire-alert",
device_class=SensorDeviceClass.PRESSURE,
state_class=SensorStateClass.MEASUREMENT,
native_unit_of_measurement=UnitOfPressure.PSI,
entity_category=EntityCategory.DIAGNOSTIC,
entity_registry_enabled_default=False,
fix_unit=lambda d, h: TeslaFiTirePressure.convert_unit(d.tpms.unit),
value=lambda d, h: d.tpms.rear_right,
available=lambda u, d, h: u and d.tpms.rear_right,
),
# endregion
]


Expand All @@ -195,6 +251,10 @@ class TeslaFiSensor(TeslaFiEntity[TeslaFiSensorEntityDescription], SensorEntity)

def _handle_coordinator_update(self) -> None:
self._attr_native_value = self._get_value()
if self.entity_description.fix_unit and (
fixed := self.entity_description.fix_unit(self.coordinator.data, self.hass)
):
self._attr_native_unit_of_measurement = fixed
return super()._handle_coordinator_update()

@property
Expand Down

0 comments on commit d230968

Please sign in to comment.