Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Binary Sensor platform to Tessie #105421

Merged
merged 18 commits into from
Dec 16, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion homeassistant/components/tessie/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down
142 changes: 142 additions & 0 deletions homeassistant/components/tessie/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -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):
Comment on lines +22 to +23
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a followup these should be changed due to a recent change https://developers.home-assistant.io/blog/2023/12/11/entity-description-changes/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will come up a few times in the other platforms, but ill look at addressing them all once I fully understand the repercussions.

"""Describes Tessie binary sensor entity."""

is_on: Callable[..., bool] = lambda x: x


DESCRIPTIONS: tuple[TessieBinarySensorEntityDescription, ...] = (
Bre77 marked this conversation as resolved.
Show resolved Hide resolved
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)
56 changes: 56 additions & 0 deletions homeassistant/components/tessie/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "Tyre preasure warning front left"
},
"vehicle_state_tpms_soft_warning_fr": {
"name": "Tyre preasure warning front right"
},
"vehicle_state_tpms_soft_warning_rl": {
"name": "Tyre preasure warning rear left"
},
"vehicle_state_tpms_soft_warning_rr": {
"name": "Tyre preasure warning rear right"
Bre77 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
1 change: 1 addition & 0 deletions tests/components/tessie/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -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/"
Expand Down
33 changes: 33 additions & 0 deletions tests/components/tessie/test_binary_sensors.py
Original file line number Diff line number Diff line change
@@ -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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OFFON isn't used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes, that was an idea I gave up on. I'll raise a PR to remove it.



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"]