diff --git a/homeassistant/components/tessie/__init__.py b/homeassistant/components/tessie/__init__.py index ac77c3cc09e7c3..a1553aa0c7e38a 100644 --- a/homeassistant/components/tessie/__init__.py +++ b/homeassistant/components/tessie/__init__.py @@ -14,7 +14,7 @@ from .const import DOMAIN from .coordinator import TessieDataUpdateCoordinator -PLATFORMS = [Platform.SENSOR] +PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/tessie/binary_sensor.py b/homeassistant/components/tessie/binary_sensor.py new file mode 100644 index 00000000000000..ca78b19a42b2d1 --- /dev/null +++ b/homeassistant/components/tessie/binary_sensor.py @@ -0,0 +1,142 @@ +"""Binary Sensor platform for Tessie integration.""" +from __future__ import annotations + +from collections.abc import Callable +from dataclasses import dataclass + +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 .const import DOMAIN +from .coordinator import TessieDataUpdateCoordinator +from .entity import TessieEntity + + +@dataclass +class TessieBinarySensorEntityDescription(BinarySensorEntityDescription): + """Describes Tessie binary sensor entity.""" + + is_on: Callable[..., bool] = lambda x: x + + +DESCRIPTIONS: tuple[TessieBinarySensorEntityDescription, ...] = ( + TessieBinarySensorEntityDescription( + key="charge_state_battery_heater_on", + device_class=BinarySensorDeviceClass.HEAT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="charge_state_charging_state", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + is_on=lambda x: x == "Charging", + ), + TessieBinarySensorEntityDescription( + key="charge_state_preconditioning_enabled", + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="charge_state_scheduled_charging_pending", + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="charge_state_trip_charging", + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="climate_state_auto_seat_climate_left", + device_class=BinarySensorDeviceClass.HEAT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="climate_state_auto_seat_climate_right", + device_class=BinarySensorDeviceClass.HEAT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="climate_state_auto_steering_wheel_heat", + device_class=BinarySensorDeviceClass.HEAT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="climate_state_cabin_overheat_protection", + device_class=BinarySensorDeviceClass.RUNNING, + is_on=lambda x: x == "On", + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="climate_state_cabin_overheat_protection_actively_cooling", + device_class=BinarySensorDeviceClass.HEAT, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_dashcam_state", + device_class=BinarySensorDeviceClass.RUNNING, + is_on=lambda x: x == "Recording", + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_is_user_present", + device_class=BinarySensorDeviceClass.PRESENCE, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_tpms_soft_warning_fl", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_tpms_soft_warning_fr", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_tpms_soft_warning_rl", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + ), + TessieBinarySensorEntityDescription( + key="vehicle_state_tpms_soft_warning_rr", + device_class=BinarySensorDeviceClass.PROBLEM, + entity_category=EntityCategory.DIAGNOSTIC, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback +) -> None: + """Set up the Tessie binary sensor platform from a config entry.""" + coordinators = hass.data[DOMAIN][entry.entry_id] + + async_add_entities( + TessieBinarySensorEntity(coordinator, description) + for coordinator in coordinators + for description in DESCRIPTIONS + if description.key in coordinator.data + ) + + +class TessieBinarySensorEntity(TessieEntity, BinarySensorEntity): + """Base class for Tessie binary sensors.""" + + entity_description: TessieBinarySensorEntityDescription + + def __init__( + self, + coordinator: TessieDataUpdateCoordinator, + description: TessieBinarySensorEntityDescription, + ) -> None: + """Initialize the sensor.""" + super().__init__(coordinator, description.key) + self.entity_description = description + + @property + def is_on(self) -> bool: + """Return the state of the binary sensor.""" + return self.entity_description.is_on(self._value) diff --git a/homeassistant/components/tessie/strings.json b/homeassistant/components/tessie/strings.json index 84ca54286f23a2..8785f2aadc3c61 100644 --- a/homeassistant/components/tessie/strings.json +++ b/homeassistant/components/tessie/strings.json @@ -71,16 +71,16 @@ "name": "Odometer" }, "vehicle_state_tpms_pressure_fl": { - "name": "Tyre pressure front left" + "name": "Tire pressure front left" }, "vehicle_state_tpms_pressure_fr": { - "name": "Tyre pressure front right" + "name": "Tire pressure front right" }, "vehicle_state_tpms_pressure_rl": { - "name": "Tyre pressure rear left" + "name": "Tire pressure rear left" }, "vehicle_state_tpms_pressure_rr": { - "name": "Tyre pressure rear right" + "name": "Tire pressure rear right" }, "climate_state_inside_temp": { "name": "Inside temperature" @@ -94,6 +94,62 @@ "climate_state_passenger_temp_setting": { "name": "Passenger temperature setting" } + }, + "binary_sensor": { + "charge_state_battery_heater_on": { + "name": "Battery heater" + }, + "charge_state_charge_enable_request": { + "name": "Charge enable request" + }, + "charge_state_charge_port_door_open": { + "name": "Charge port door" + }, + "charge_state_charging_state": { + "name": "Charging" + }, + "charge_state_preconditioning_enabled": { + "name": "Preconditioning enabled" + }, + "charge_state_scheduled_charging_pending": { + "name": "Scheduled charging pending" + }, + "charge_state_trip_charging": { + "name": "Trip charging" + }, + "climate_state_auto_seat_climate_left": { + "name": "Auto seat climate left" + }, + "climate_state_auto_seat_climate_right": { + "name": "Auto seat climate right" + }, + "climate_state_auto_steering_wheel_heater": { + "name": "Auto steering wheel heater" + }, + "climate_state_cabin_overheat_protection": { + "name": "Cabin overheat protection" + }, + "climate_state_cabin_overheat_protection_actively_cooling": { + "name": "Cabin overheat protection actively cooling" + }, + "vehicle_state_dashcam_state": { + "name": "Dashcam" + }, + "vehicle_state_is_user_present": { + "name": "User present" + }, + "vehicle_state_tpms_soft_warning_fl": { + "name": "Tire pressure warning front left" + }, + "vehicle_state_tpms_soft_warning_fr": { + "name": "Tire pressure warning front right" + }, + "vehicle_state_tpms_soft_warning_rl": { + "name": "Tire pressure warning rear left" + }, + "vehicle_state_tpms_soft_warning_rr": { + "name": "Tire pressure warning rear right" + } } } } diff --git a/tests/components/tessie/common.py b/tests/components/tessie/common.py index 572a687a6e5d61..30b6feca4d7c09 100644 --- a/tests/components/tessie/common.py +++ b/tests/components/tessie/common.py @@ -15,6 +15,7 @@ TEST_STATE_OF_ALL_VEHICLES = load_json_object_fixture("vehicles.json", DOMAIN) TEST_VEHICLE_STATE_ONLINE = load_json_object_fixture("online.json", DOMAIN) TEST_VEHICLE_STATE_ASLEEP = load_json_object_fixture("asleep.json", DOMAIN) +TEST_RESPONSE = {"result": True} TEST_CONFIG = {CONF_ACCESS_TOKEN: "1234567890"} TESSIE_URL = "https://api.tessie.com/" diff --git a/tests/components/tessie/test_binary_sensors.py b/tests/components/tessie/test_binary_sensors.py new file mode 100644 index 00000000000000..594b270ec7af0c --- /dev/null +++ b/tests/components/tessie/test_binary_sensors.py @@ -0,0 +1,33 @@ +"""Test the Tessie binary sensor platform.""" + +from homeassistant.components.tessie.binary_sensor import DESCRIPTIONS +from homeassistant.const import STATE_OFF, STATE_ON +from homeassistant.core import HomeAssistant + +from .common import TEST_VEHICLE_STATE_ONLINE, setup_platform + +OFFON = [STATE_OFF, STATE_ON] + + +async def test_binary_sensors(hass: HomeAssistant) -> None: + """Tests that the sensors are correct.""" + + assert len(hass.states.async_all("binary_sensor")) == 0 + + await setup_platform(hass) + + assert len(hass.states.async_all("binary_sensor")) == len(DESCRIPTIONS) + + state = hass.states.get("binary_sensor.test_battery_heater").state + is_on = state == STATE_ON + assert is_on == TEST_VEHICLE_STATE_ONLINE["charge_state"]["battery_heater_on"] + + state = hass.states.get("binary_sensor.test_charging").state + is_on = state == STATE_ON + assert is_on == ( + TEST_VEHICLE_STATE_ONLINE["charge_state"]["charging_state"] == "Charging" + ) + + state = hass.states.get("binary_sensor.test_auto_seat_climate_left").state + is_on = state == STATE_ON + assert is_on == TEST_VEHICLE_STATE_ONLINE["climate_state"]["auto_seat_climate_left"]