From ce4de125478210af977feebc3ec691a11b2c8afd Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Thu, 19 Mar 2026 08:29:30 +1000 Subject: [PATCH] Source Tessie battery sensors from state data keys --- homeassistant/components/tessie/entity.py | 23 ++++++---- homeassistant/components/tessie/sensor.py | 48 +++++++------------- tests/components/tessie/fixtures/online.json | 6 +++ 3 files changed, 38 insertions(+), 39 deletions(-) diff --git a/homeassistant/components/tessie/entity.py b/homeassistant/components/tessie/entity.py index a717fa5f06a4c4..223b6f7d6515bf 100644 --- a/homeassistant/components/tessie/entity.py +++ b/homeassistant/components/tessie/entity.py @@ -42,10 +42,12 @@ def __init__( | TessieEnergySiteLiveCoordinator | TessieEnergyHistoryCoordinator, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Tessie entity.""" self.key = key + self.data_key = data_key or key self._attr_translation_key = key super().__init__(coordinator) self._async_update_attrs() @@ -53,11 +55,11 @@ def __init__( @property def _value(self) -> Any: """Return value from coordinator data.""" - return self.coordinator.data.get(self.key) + return self.coordinator.data.get(self.data_key) def get(self, key: str | None = None, default: Any | None = None) -> Any: """Return a specific value from coordinator data.""" - return self.coordinator.data.get(key or self.key, default) + return self.coordinator.data.get(key or self.data_key, default) def _handle_coordinator_update(self) -> None: """Handle updated data from the coordinator.""" @@ -76,6 +78,7 @@ def __init__( self, vehicle: TessieVehicleData, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Tessie vehicle entity.""" self.vin = vehicle.vin @@ -84,12 +87,12 @@ def __init__( self._attr_unique_id = f"{vehicle.vin}-{key}" self._attr_device_info = vehicle.device - super().__init__(vehicle.data_coordinator, key) + super().__init__(vehicle.data_coordinator, key, data_key) @property def _value(self) -> Any: """Return value from coordinator data.""" - return self.coordinator.data.get(self.key) + return self.coordinator.data.get(self.data_key) def set(self, *args: Any) -> None: """Set a value in coordinator data.""" @@ -133,13 +136,14 @@ def __init__( data: TessieEnergyData, coordinator: TessieEnergySiteInfoCoordinator | TessieEnergySiteLiveCoordinator, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Tessie energy site entity.""" self.api = data.api self._attr_unique_id = f"{data.id}-{key}" self._attr_device_info = data.device - super().__init__(coordinator, key) + super().__init__(coordinator, key, data_key) class TessieBatteryEntity(TessieBaseEntity): @@ -149,13 +153,14 @@ def __init__( self, vehicle: TessieVehicleData, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Tessie battery health entity.""" self.vin = vehicle.vin self._attr_unique_id = f"{vehicle.vin}-{key}" self._attr_device_info = vehicle.device - super().__init__(vehicle.battery_coordinator, key) + super().__init__(vehicle.battery_coordinator, key, data_key) class TessieEnergyHistoryEntity(TessieBaseEntity): @@ -165,13 +170,14 @@ def __init__( self, data: TessieEnergyData, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Tessie energy history entity.""" self.api = data.api self._attr_unique_id = f"{data.id}-{key}" self._attr_device_info = data.device assert data.history_coordinator - super().__init__(data.history_coordinator, key) + super().__init__(data.history_coordinator, key, data_key) class TessieWallConnectorEntity(TessieBaseEntity): @@ -182,6 +188,7 @@ def __init__( data: TessieEnergyData, din: str, key: str, + data_key: str | None = None, ) -> None: """Initialize common aspects of a Teslemetry entity.""" self.din = din @@ -194,7 +201,7 @@ def __init__( serial_number=din.rsplit("-", maxsplit=1)[-1], ) assert data.live_coordinator - super().__init__(data.live_coordinator, key) + super().__init__(data.live_coordinator, key, data_key) @property def _value(self) -> int: diff --git a/homeassistant/components/tessie/sensor.py b/homeassistant/components/tessie/sensor.py index b4489f9a724624..8992440377c655 100644 --- a/homeassistant/components/tessie/sensor.py +++ b/homeassistant/components/tessie/sensor.py @@ -41,7 +41,6 @@ TessieWallConnectorStates, ) from .entity import ( - TessieBatteryEntity, TessieEnergyEntity, TessieEnergyHistoryEntity, TessieEntity, @@ -62,6 +61,7 @@ def minutes_to_datetime(value: StateType) -> datetime | None: class TessieSensorEntityDescription(SensorEntityDescription): """Describes Tessie Sensor entity.""" + data_key: str | None = None value_fn: Callable[[StateType], StateType | datetime] = lambda x: x available_fn: Callable[[StateType], bool] = lambda _: True @@ -142,6 +142,14 @@ class TessieSensorEntityDescription(SensorEntityDescription): suggested_display_precision=1, entity_registry_enabled_default=False, ), + TessieSensorEntityDescription( + key="phantom_drain_percent", + data_key="charge_state_phantom_drain_percent", + state_class=SensorStateClass.MEASUREMENT, + native_unit_of_measurement=PERCENTAGE, + entity_category=EntityCategory.DIAGNOSTIC, + suggested_display_precision=2, + ), TessieSensorEntityDescription( key="charge_state_energy_remaining", state_class=SensorStateClass.MEASUREMENT, @@ -292,15 +300,9 @@ class TessieSensorEntityDescription(SensorEntityDescription): BATTERY_DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = ( - TessieSensorEntityDescription( - key="phantom_drain_percent", - state_class=SensorStateClass.MEASUREMENT, - native_unit_of_measurement=PERCENTAGE, - entity_category=EntityCategory.DIAGNOSTIC, - suggested_display_precision=2, - ), TessieSensorEntityDescription( key="lifetime_energy_used", + data_key="charge_state_lifetime_energy_used", state_class=SensorStateClass.TOTAL_INCREASING, native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, device_class=SensorDeviceClass.ENERGY, @@ -309,6 +311,7 @@ class TessieSensorEntityDescription(SensorEntityDescription): ), TessieSensorEntityDescription( key="pack_current", + data_key="charge_state_pack_current", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, device_class=SensorDeviceClass.CURRENT, @@ -317,6 +320,7 @@ class TessieSensorEntityDescription(SensorEntityDescription): ), TessieSensorEntityDescription( key="pack_voltage", + data_key="charge_state_pack_voltage", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfElectricPotential.VOLT, device_class=SensorDeviceClass.VOLTAGE, @@ -325,6 +329,7 @@ class TessieSensorEntityDescription(SensorEntityDescription): ), TessieSensorEntityDescription( key="module_temp_min", + data_key="charge_state_module_temp_min", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, @@ -333,6 +338,7 @@ class TessieSensorEntityDescription(SensorEntityDescription): ), TessieSensorEntityDescription( key="module_temp_max", + data_key="charge_state_module_temp_max", state_class=SensorStateClass.MEASUREMENT, native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, @@ -494,11 +500,10 @@ async def async_setup_entry( for vehicle in entry.runtime_data.vehicles for description in DESCRIPTIONS ), - ( # Add vehicle battery health - TessieBatteryHealthSensorEntity(vehicle, description) + ( # Add vehicle battery health from state endpoint + TessieVehicleSensorEntity(vehicle, description) for vehicle in entry.runtime_data.vehicles for description in BATTERY_DESCRIPTIONS - if description.key in vehicle.battery_coordinator.data ), ( # Add energy site info TessieEnergyInfoSensorEntity(energysite, description) @@ -545,7 +550,7 @@ def __init__( ) -> None: """Initialize the sensor.""" self.entity_description = description - super().__init__(vehicle, description.key) + super().__init__(vehicle, description.key, description.data_key) @property def native_value(self) -> StateType | datetime: @@ -558,25 +563,6 @@ def available(self) -> bool: return super().available and self.entity_description.available_fn(self.get()) -class TessieBatteryHealthSensorEntity(TessieBatteryEntity, SensorEntity): - """Sensor entity for Tessie battery health data.""" - - entity_description: TessieSensorEntityDescription - - def __init__( - self, - vehicle: TessieVehicleData, - description: TessieSensorEntityDescription, - ) -> None: - """Initialize the sensor.""" - self.entity_description = description - super().__init__(vehicle, description.key) - - def _async_update_attrs(self) -> None: - """Update the attributes of the sensor.""" - self._attr_native_value = self.entity_description.value_fn(self._value) - - class TessieEnergyLiveSensorEntity(TessieEnergyEntity, SensorEntity): """Base class for Tessie energy site sensor entity.""" diff --git a/tests/components/tessie/fixtures/online.json b/tests/components/tessie/fixtures/online.json index 38b904cdffba93..c9ac55baf99e51 100644 --- a/tests/components/tessie/fixtures/online.json +++ b/tests/components/tessie/fixtures/online.json @@ -54,6 +54,12 @@ "off_peak_charging_enabled": false, "off_peak_charging_times": "all_week", "off_peak_hours_end_time": 900, + "lifetime_energy_used": 12345.6, + "module_temp_max": 24, + "module_temp_min": 22.5, + "pack_current": -0.6, + "pack_voltage": 390.1, + "phantom_drain_percent": 0.5, "preconditioning_enabled": false, "preconditioning_times": "all_week", "scheduled_charging_mode": "StartAt",