diff --git a/homeassistant/components/tessie/sensor.py b/homeassistant/components/tessie/sensor.py index 07f54ebde5b..ae9e06b2b35 100644 --- a/homeassistant/components/tessie/sensor.py +++ b/homeassistant/components/tessie/sensor.py @@ -4,6 +4,7 @@ from __future__ import annotations from collections.abc import Callable from dataclasses import dataclass from datetime import datetime, timedelta +from typing import cast from homeassistant.components.sensor import ( SensorDeviceClass, @@ -29,6 +30,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.typing import StateType from homeassistant.util import dt as dt_util +from homeassistant.util.variance import ignore_variance from .const import DOMAIN from .coordinator import TessieStateUpdateCoordinator @@ -36,8 +38,8 @@ from .entity import TessieEntity @callback -def hours_to_datetime(value: StateType) -> datetime | None: - """Convert relative hours into absolute datetime.""" +def minutes_to_datetime(value: StateType) -> datetime | None: + """Convert relative minutes into absolute datetime.""" if isinstance(value, (int, float)) and value > 0: return dt_util.now() + timedelta(minutes=value) return None @@ -48,6 +50,7 @@ class TessieSensorEntityDescription(SensorEntityDescription): """Describes Tessie Sensor entity.""" value_fn: Callable[[StateType], StateType | datetime] = lambda x: x + available_fn: Callable[[StateType], bool] = lambda _: True DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = ( @@ -95,7 +98,7 @@ DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = ( key="charge_state_minutes_to_full_charge", device_class=SensorDeviceClass.TIMESTAMP, entity_category=EntityCategory.DIAGNOSTIC, - value_fn=hours_to_datetime, + value_fn=minutes_to_datetime, ), TessieSensorEntityDescription( key="charge_state_battery_range", @@ -219,9 +222,12 @@ DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = ( ), TessieSensorEntityDescription( key="drive_state_active_route_minutes_to_arrival", - state_class=SensorStateClass.MEASUREMENT, - native_unit_of_measurement=UnitOfTime.MINUTES, - device_class=SensorDeviceClass.DURATION, + device_class=SensorDeviceClass.TIMESTAMP, + value_fn=ignore_variance( + lambda value: dt_util.now() + timedelta(minutes=cast(float, value)), + timedelta(seconds=30), + ), + available_fn=lambda x: x is not None, ), TessieSensorEntityDescription( key="drive_state_active_route_destination", @@ -262,3 +268,8 @@ class TessieSensorEntity(TessieEntity, SensorEntity): def native_value(self) -> StateType | datetime: """Return the state of the sensor.""" return self.entity_description.value_fn(self.get()) + + @property + def available(self) -> bool: + """Return if sensor is available.""" + return super().available and self.entity_description.available_fn(self.get()) diff --git a/homeassistant/components/tessie/strings.json b/homeassistant/components/tessie/strings.json index 57ba1f12bec..8340557843d 100644 --- a/homeassistant/components/tessie/strings.json +++ b/homeassistant/components/tessie/strings.json @@ -142,7 +142,7 @@ "drive_state_active_route_miles_to_arrival": { "name": "Distance to arrival" }, - "drive_state_active_route_time_to_arrival": { + "drive_state_active_route_minutes_to_arrival": { "name": "Time to arrival" }, "drive_state_active_route_destination": { diff --git a/tests/components/tessie/snapshots/test_sensor.ambr b/tests/components/tessie/snapshots/test_sensor.ambr index 921aba0b330..2f5e1e8ddb2 100644 --- a/tests/components/tessie/snapshots/test_sensor.ambr +++ b/tests/components/tessie/snapshots/test_sensor.ambr @@ -493,54 +493,6 @@ 'state': '22.5', }) # --- -# name: test_sensors[sensor.test_duration-entry] - EntityRegistryEntrySnapshot({ - 'aliases': set({ - }), - 'area_id': None, - 'capabilities': dict({ - 'state_class': , - }), - 'config_entry_id': , - 'device_class': None, - 'device_id': , - 'disabled_by': None, - 'domain': 'sensor', - 'entity_category': None, - 'entity_id': 'sensor.test_duration', - 'has_entity_name': True, - 'hidden_by': None, - 'icon': None, - 'id': , - 'name': None, - 'options': dict({ - }), - 'original_device_class': , - 'original_icon': None, - 'original_name': 'Duration', - 'platform': 'tessie', - 'previous_unique_id': None, - 'supported_features': 0, - 'translation_key': 'drive_state_active_route_minutes_to_arrival', - 'unique_id': 'VINVINVIN-drive_state_active_route_minutes_to_arrival', - 'unit_of_measurement': , - }) -# --- -# name: test_sensors[sensor.test_duration-state] - StateSnapshot({ - 'attributes': ReadOnlyDict({ - 'device_class': 'duration', - 'friendly_name': 'Test Duration', - 'state_class': , - 'unit_of_measurement': , - }), - 'context': , - 'entity_id': 'sensor.test_duration', - 'last_changed': , - 'last_updated': , - 'state': '59.2', - }) -# --- # name: test_sensors[sensor.test_inside_temperature-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -953,6 +905,50 @@ 'state': '65', }) # --- +# name: test_sensors[sensor.test_time_to_arrival-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.test_time_to_arrival', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Time to arrival', + 'platform': 'tessie', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'drive_state_active_route_minutes_to_arrival', + 'unique_id': 'VINVINVIN-drive_state_active_route_minutes_to_arrival', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[sensor.test_time_to_arrival-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', + 'friendly_name': 'Test Time to arrival', + }), + 'context': , + 'entity_id': 'sensor.test_time_to_arrival', + 'last_changed': , + 'last_updated': , + 'state': '2024-01-01T00:59:12+00:00', + }) +# --- # name: test_sensors[sensor.test_time_to_full_charge-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tessie/test_sensor.py b/tests/components/tessie/test_sensor.py index fef251f0108..090f9df0ca5 100644 --- a/tests/components/tessie/test_sensor.py +++ b/tests/components/tessie/test_sensor.py @@ -1,4 +1,5 @@ """Test the Tessie sensor platform.""" +from freezegun.api import FrozenDateTimeFactory from syrupy import SnapshotAssertion from homeassistant.const import Platform @@ -9,10 +10,15 @@ from .common import assert_entities, setup_platform async def test_sensors( - hass: HomeAssistant, snapshot: SnapshotAssertion, entity_registry: er.EntityRegistry + hass: HomeAssistant, + snapshot: SnapshotAssertion, + entity_registry: er.EntityRegistry, + freezer: FrozenDateTimeFactory, ) -> None: """Tests that the sensor entities are correct.""" + freezer.move_to("2024-01-01 00:00:00+00:00") + entry = await setup_platform(hass, [Platform.SENSOR]) assert_entities(hass, entry.entry_id, entity_registry, snapshot)