mirror of
https://github.com/home-assistant/core.git
synced 2026-04-02 08:26:41 +01:00
Source Tessie phantom drain and battery sensors from state data (#165970)
This commit is contained in:
@@ -13,7 +13,7 @@ from tesla_fleet_api.exceptions import (
|
||||
TeslaFleetError,
|
||||
)
|
||||
from tesla_fleet_api.tessie import Tessie
|
||||
from tessie_api import get_battery, get_state_of_all_vehicles
|
||||
from tessie_api import get_state_of_all_vehicles
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.const import CONF_ACCESS_TOKEN, Platform
|
||||
@@ -28,7 +28,6 @@ from homeassistant.helpers.device_registry import DeviceInfo
|
||||
|
||||
from .const import DOMAIN, MODELS
|
||||
from .coordinator import (
|
||||
TessieBatteryHealthCoordinator,
|
||||
TessieEnergyHistoryCoordinator,
|
||||
TessieEnergySiteInfoCoordinator,
|
||||
TessieEnergySiteLiveCoordinator,
|
||||
@@ -74,25 +73,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo
|
||||
except ClientError as e:
|
||||
raise ConfigEntryNotReady from e
|
||||
|
||||
try:
|
||||
batteries = await asyncio.gather(
|
||||
*(
|
||||
get_battery(
|
||||
session=session,
|
||||
api_key=api_key,
|
||||
vin=vehicle["vin"],
|
||||
)
|
||||
for vehicle in state_of_all_vehicles["results"]
|
||||
if vehicle["last_state"] is not None
|
||||
)
|
||||
)
|
||||
except ClientResponseError as e:
|
||||
if e.status == HTTPStatus.UNAUTHORIZED:
|
||||
raise ConfigEntryAuthFailed from e
|
||||
raise ConfigEntryError("Setup failed, unable to get battery data") from e
|
||||
except ClientError as e:
|
||||
raise ConfigEntryNotReady from e
|
||||
|
||||
vehicles = [
|
||||
TessieVehicleData(
|
||||
vin=vehicle["vin"],
|
||||
@@ -103,13 +83,6 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo
|
||||
vin=vehicle["vin"],
|
||||
data=vehicle["last_state"],
|
||||
),
|
||||
battery_coordinator=TessieBatteryHealthCoordinator(
|
||||
hass,
|
||||
entry,
|
||||
api_key=api_key,
|
||||
vin=vehicle["vin"],
|
||||
data=battery,
|
||||
),
|
||||
device=DeviceInfo(
|
||||
identifiers={(DOMAIN, vehicle["vin"])},
|
||||
manufacturer="Tesla",
|
||||
@@ -126,15 +99,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo
|
||||
serial_number=vehicle["vin"],
|
||||
),
|
||||
)
|
||||
for vehicle, battery in zip(
|
||||
(
|
||||
v
|
||||
for v in state_of_all_vehicles["results"]
|
||||
if v["last_state"] is not None
|
||||
),
|
||||
batteries,
|
||||
strict=True,
|
||||
)
|
||||
for vehicle in state_of_all_vehicles["results"]
|
||||
if vehicle["last_state"] is not None
|
||||
]
|
||||
|
||||
# Energy Sites
|
||||
|
||||
@@ -11,7 +11,7 @@ from aiohttp import ClientResponseError
|
||||
from tesla_fleet_api.const import TeslaEnergyPeriod
|
||||
from tesla_fleet_api.exceptions import InvalidToken, MissingToken, TeslaFleetError
|
||||
from tesla_fleet_api.tessie import EnergySite
|
||||
from tessie_api import get_battery, get_state
|
||||
from tessie_api import get_state
|
||||
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ConfigEntryAuthFailed
|
||||
@@ -87,48 +87,6 @@ class TessieStateUpdateCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
return flatten(vehicle)
|
||||
|
||||
|
||||
class TessieBatteryHealthCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching battery health data from the Tessie API."""
|
||||
|
||||
config_entry: TessieConfigEntry
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hass: HomeAssistant,
|
||||
config_entry: TessieConfigEntry,
|
||||
api_key: str,
|
||||
vin: str,
|
||||
data: dict[str, Any],
|
||||
) -> None:
|
||||
"""Initialize Tessie Battery Health coordinator."""
|
||||
super().__init__(
|
||||
hass,
|
||||
_LOGGER,
|
||||
config_entry=config_entry,
|
||||
name="Tessie Battery Health",
|
||||
update_interval=timedelta(seconds=TESSIE_SYNC_INTERVAL),
|
||||
)
|
||||
self.api_key = api_key
|
||||
self.vin = vin
|
||||
self.session = async_get_clientsession(hass)
|
||||
self.data = data
|
||||
|
||||
async def _async_update_data(self) -> dict[str, Any]:
|
||||
"""Update battery health data using Tessie API."""
|
||||
try:
|
||||
data = await get_battery(
|
||||
session=self.session,
|
||||
api_key=self.api_key,
|
||||
vin=self.vin,
|
||||
)
|
||||
except ClientResponseError as e:
|
||||
if e.status == HTTPStatus.UNAUTHORIZED:
|
||||
raise ConfigEntryAuthFailed from e
|
||||
raise UpdateFailed from e
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class TessieEnergySiteLiveCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
||||
"""Class to manage fetching energy site live status from the Tessie API."""
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ async def async_get_config_entry_diagnostics(
|
||||
vehicles = [
|
||||
{
|
||||
"data": async_redact_data(x.data_coordinator.data, VEHICLE_REDACT),
|
||||
"battery": x.battery_coordinator.data,
|
||||
}
|
||||
for x in entry.runtime_data.vehicles
|
||||
]
|
||||
|
||||
@@ -12,7 +12,6 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||
|
||||
from .const import DOMAIN, TRANSLATED_ERRORS
|
||||
from .coordinator import (
|
||||
TessieBatteryHealthCoordinator,
|
||||
TessieEnergyHistoryCoordinator,
|
||||
TessieEnergySiteInfoCoordinator,
|
||||
TessieEnergySiteLiveCoordinator,
|
||||
@@ -24,7 +23,6 @@ from .models import TessieEnergyData, TessieVehicleData
|
||||
class TessieBaseEntity(
|
||||
CoordinatorEntity[
|
||||
TessieStateUpdateCoordinator
|
||||
| TessieBatteryHealthCoordinator
|
||||
| TessieEnergySiteInfoCoordinator
|
||||
| TessieEnergySiteLiveCoordinator
|
||||
| TessieEnergyHistoryCoordinator
|
||||
@@ -37,15 +35,16 @@ class TessieBaseEntity(
|
||||
def __init__(
|
||||
self,
|
||||
coordinator: TessieStateUpdateCoordinator
|
||||
| TessieBatteryHealthCoordinator
|
||||
| TessieEnergySiteInfoCoordinator
|
||||
| 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 +52,11 @@ class TessieBaseEntity(
|
||||
@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 +75,7 @@ class TessieEntity(TessieBaseEntity):
|
||||
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 +84,7 @@ class TessieEntity(TessieBaseEntity):
|
||||
self._attr_unique_id = f"{vehicle.vin}-{key}"
|
||||
self._attr_device_info = vehicle.device
|
||||
|
||||
super().__init__(vehicle.data_coordinator, key)
|
||||
|
||||
@property
|
||||
def _value(self) -> Any:
|
||||
"""Return value from coordinator data."""
|
||||
return self.coordinator.data.get(self.key)
|
||||
super().__init__(vehicle.data_coordinator, key, data_key)
|
||||
|
||||
def set(self, *args: Any) -> None:
|
||||
"""Set a value in coordinator data."""
|
||||
@@ -133,29 +128,14 @@ class TessieEnergyEntity(TessieBaseEntity):
|
||||
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)
|
||||
|
||||
|
||||
class TessieBatteryEntity(TessieBaseEntity):
|
||||
"""Parent class for Tessie battery health entities."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
vehicle: TessieVehicleData,
|
||||
key: str,
|
||||
) -> 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__(coordinator, key, data_key)
|
||||
|
||||
|
||||
class TessieEnergyHistoryEntity(TessieBaseEntity):
|
||||
@@ -165,13 +145,14 @@ class TessieEnergyHistoryEntity(TessieBaseEntity):
|
||||
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 +163,7 @@ class TessieWallConnectorEntity(TessieBaseEntity):
|
||||
data: TessieEnergyData,
|
||||
din: str,
|
||||
key: str,
|
||||
data_key: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize common aspects of a Teslemetry entity."""
|
||||
self.din = din
|
||||
@@ -194,7 +176,7 @@ class TessieWallConnectorEntity(TessieBaseEntity):
|
||||
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:
|
||||
|
||||
@@ -9,7 +9,6 @@ from tesla_fleet_api.tessie import EnergySite
|
||||
from homeassistant.helpers.device_registry import DeviceInfo
|
||||
|
||||
from .coordinator import (
|
||||
TessieBatteryHealthCoordinator,
|
||||
TessieEnergyHistoryCoordinator,
|
||||
TessieEnergySiteInfoCoordinator,
|
||||
TessieEnergySiteLiveCoordinator,
|
||||
@@ -42,6 +41,5 @@ class TessieVehicleData:
|
||||
"""Data for a Tessie vehicle."""
|
||||
|
||||
data_coordinator: TessieStateUpdateCoordinator
|
||||
battery_coordinator: TessieBatteryHealthCoordinator
|
||||
device: DeviceInfo
|
||||
vin: str
|
||||
|
||||
@@ -41,7 +41,6 @@ from .const import (
|
||||
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 @@ DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = (
|
||||
suggested_display_precision=1,
|
||||
entity_registry_enabled_default=False,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="phantom_drain_percent",
|
||||
data_key="charge_state_phantom_drain",
|
||||
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,
|
||||
@@ -150,6 +158,51 @@ DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = (
|
||||
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,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="pack_current",
|
||||
data_key="charge_state_pack_current",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="pack_voltage",
|
||||
data_key="charge_state_pack_voltage",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
|
||||
device_class=SensorDeviceClass.VOLTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
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,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
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,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="charge_state_conn_charge_cable",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
@@ -290,57 +343,6 @@ DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = (
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
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",
|
||||
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
|
||||
device_class=SensorDeviceClass.ENERGY,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="pack_current",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
|
||||
device_class=SensorDeviceClass.CURRENT,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="pack_voltage",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfElectricPotential.VOLT,
|
||||
device_class=SensorDeviceClass.VOLTAGE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="module_temp_min",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
TessieSensorEntityDescription(
|
||||
key="module_temp_max",
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_class=SensorDeviceClass.TEMPERATURE,
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
suggested_display_precision=1,
|
||||
),
|
||||
)
|
||||
|
||||
ENERGY_LIVE_DESCRIPTIONS: tuple[TessieSensorEntityDescription, ...] = (
|
||||
TessieSensorEntityDescription(
|
||||
key="solar_power",
|
||||
@@ -494,12 +496,6 @@ async def async_setup_entry(
|
||||
for vehicle in entry.runtime_data.vehicles
|
||||
for description in DESCRIPTIONS
|
||||
),
|
||||
( # Add vehicle battery health
|
||||
TessieBatteryHealthSensorEntity(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)
|
||||
for energysite in entry.runtime_data.energysites
|
||||
@@ -545,7 +541,7 @@ class TessieVehicleSensorEntity(TessieEntity, SensorEntity):
|
||||
) -> 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 +554,6 @@ class TessieVehicleSensorEntity(TessieEntity, SensorEntity):
|
||||
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."""
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ from tests.common import MockConfigEntry, load_json_object_fixture
|
||||
# Tessie library
|
||||
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_BATTERY = load_json_object_fixture("battery.json", DOMAIN)
|
||||
TEST_RESPONSE = {"result": True}
|
||||
TEST_RESPONSE_ERROR = {"result": False, "reason": "reason_why"}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ from .common import (
|
||||
SCOPES,
|
||||
SITE_INFO,
|
||||
TEST_STATE_OF_ALL_VEHICLES,
|
||||
TEST_VEHICLE_BATTERY,
|
||||
TEST_VEHICLE_STATE_ONLINE,
|
||||
)
|
||||
|
||||
@@ -32,22 +31,6 @@ def mock_get_state():
|
||||
yield mock_get_state
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_get_battery():
|
||||
"""Mock get_battery function."""
|
||||
with (
|
||||
patch(
|
||||
"homeassistant.components.tessie.get_battery",
|
||||
return_value=TEST_VEHICLE_BATTERY,
|
||||
) as mock_get_battery,
|
||||
patch(
|
||||
"homeassistant.components.tessie.coordinator.get_battery",
|
||||
new=mock_get_battery,
|
||||
),
|
||||
):
|
||||
yield mock_get_battery
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def mock_get_state_of_all_vehicles():
|
||||
"""Mock get_state_of_all_vehicles function."""
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
{
|
||||
"timestamp": 1704067200,
|
||||
"battery_level": 73,
|
||||
"battery_range": 250.5,
|
||||
"ideal_battery_range": 280.2,
|
||||
"phantom_drain_percent": 0.5,
|
||||
"energy_remaining": 55.2,
|
||||
"lifetime_energy_used": 12345.6,
|
||||
"pack_current": -0.6,
|
||||
"pack_voltage": 390.1,
|
||||
"module_temp_min": 22.5,
|
||||
"module_temp_max": 24
|
||||
}
|
||||
@@ -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": 0.5,
|
||||
"preconditioning_enabled": false,
|
||||
"preconditioning_times": "all_week",
|
||||
"scheduled_charging_mode": "StartAt",
|
||||
|
||||
@@ -161,19 +161,6 @@
|
||||
]),
|
||||
'vehicles': list([
|
||||
dict({
|
||||
'battery': dict({
|
||||
'battery_level': 73,
|
||||
'battery_range': 250.5,
|
||||
'energy_remaining': 55.2,
|
||||
'ideal_battery_range': 280.2,
|
||||
'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,
|
||||
'timestamp': 1704067200,
|
||||
}),
|
||||
'data': dict({
|
||||
'access_type': 'OWNER',
|
||||
'api_version': 67,
|
||||
|
||||
@@ -2074,7 +2074,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '24',
|
||||
'state': '18',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_battery_module_temperature_min-entry]
|
||||
@@ -2132,7 +2132,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '22.5',
|
||||
'state': '16.5',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_battery_pack_current-entry]
|
||||
@@ -2190,7 +2190,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '-0.6',
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_battery_pack_voltage-entry]
|
||||
@@ -2248,7 +2248,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '390.1',
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_battery_range-entry]
|
||||
@@ -3247,7 +3247,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '12345.6',
|
||||
'state': '20505.629',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_odometer-entry]
|
||||
@@ -3481,7 +3481,7 @@
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0.5',
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_sensors[sensor.test_power-entry]
|
||||
|
||||
@@ -80,51 +80,6 @@ async def test_coordinator_connection(
|
||||
assert hass.states.get("binary_sensor.test_status").state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_coordinator_battery_update(
|
||||
hass: HomeAssistant, mock_get_battery, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Tests that the battery coordinator handles updates."""
|
||||
|
||||
await setup_platform(hass, [Platform.SENSOR])
|
||||
|
||||
mock_get_battery.reset_mock()
|
||||
freezer.tick(WAIT)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_get_battery.assert_called_once()
|
||||
|
||||
|
||||
async def test_coordinator_battery_auth(
|
||||
hass: HomeAssistant, mock_get_battery, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Tests that the battery coordinator handles auth errors."""
|
||||
|
||||
await setup_platform(hass, [Platform.SENSOR])
|
||||
|
||||
mock_get_battery.reset_mock()
|
||||
mock_get_battery.side_effect = ERROR_AUTH
|
||||
freezer.tick(WAIT)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_get_battery.assert_called_once()
|
||||
|
||||
|
||||
async def test_coordinator_battery_error(
|
||||
hass: HomeAssistant, mock_get_battery, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
"""Tests that the battery coordinator handles client errors."""
|
||||
|
||||
await setup_platform(hass, [Platform.SENSOR])
|
||||
|
||||
mock_get_battery.reset_mock()
|
||||
mock_get_battery.side_effect = ERROR_UNKNOWN
|
||||
freezer.tick(WAIT)
|
||||
async_fire_time_changed(hass)
|
||||
await hass.async_block_till_done()
|
||||
mock_get_battery.assert_called_once()
|
||||
assert hass.states.get("sensor.test_phantom_drain").state == STATE_UNAVAILABLE
|
||||
|
||||
|
||||
async def test_coordinator_live_error(
|
||||
hass: HomeAssistant, mock_live_status, freezer: FrozenDateTimeFactory
|
||||
) -> None:
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from tesla_fleet_api.exceptions import TeslaFleetError
|
||||
|
||||
from homeassistant.config_entries import ConfigEntryState
|
||||
@@ -51,27 +50,6 @@ async def test_connection_failure(
|
||||
assert entry.state is ConfigEntryState.SETUP_RETRY
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("side_effect", "expected_state"),
|
||||
[
|
||||
(ERROR_AUTH, ConfigEntryState.SETUP_ERROR),
|
||||
(ERROR_UNKNOWN, ConfigEntryState.SETUP_ERROR),
|
||||
(ERROR_CONNECTION, ConfigEntryState.SETUP_RETRY),
|
||||
],
|
||||
)
|
||||
async def test_battery_setup_failure(
|
||||
hass: HomeAssistant,
|
||||
mock_get_battery,
|
||||
side_effect: Exception,
|
||||
expected_state: ConfigEntryState,
|
||||
) -> None:
|
||||
"""Test init with a battery API error."""
|
||||
|
||||
mock_get_battery.side_effect = side_effect
|
||||
entry = await setup_platform(hass)
|
||||
assert entry.state is expected_state
|
||||
|
||||
|
||||
async def test_products_error(hass: HomeAssistant) -> None:
|
||||
"""Test init with a fleet error on products."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user