core/homeassistant/components/teslemetry/coordinator.py

99 lines
3.2 KiB
Python

"""Teslemetry Data Coordinator."""
from datetime import timedelta
from typing import Any
from tesla_fleet_api import EnergySpecific, VehicleSpecific
from tesla_fleet_api.exceptions import TeslaFleetError, VehicleOffline
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import LOGGER, TeslemetryState
SYNC_INTERVAL = 60
class TeslemetryDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
"""Base class for Teslemetry Data Coordinators."""
name: str
def __init__(
self, hass: HomeAssistant, api: VehicleSpecific | EnergySpecific
) -> None:
"""Initialize Teslemetry Vehicle Update Coordinator."""
super().__init__(
hass,
LOGGER,
name=self.name,
update_interval=timedelta(seconds=SYNC_INTERVAL),
)
self.api = api
class TeslemetryVehicleDataCoordinator(TeslemetryDataCoordinator):
"""Class to manage fetching data from the Teslemetry API."""
name = "Teslemetry Vehicle"
async def async_config_entry_first_refresh(self) -> None:
"""Perform first refresh."""
try:
response = await self.api.wake_up()
if response["response"]["state"] != TeslemetryState.ONLINE:
# The first refresh will fail, so retry later
raise ConfigEntryNotReady("Vehicle is not online")
except TeslaFleetError as e:
# The first refresh will also fail, so retry later
raise ConfigEntryNotReady from e
await super().async_config_entry_first_refresh()
async def _async_update_data(self) -> dict[str, Any]:
"""Update vehicle data using Teslemetry API."""
try:
data = await self.api.vehicle_data()
except VehicleOffline:
self.data["state"] = TeslemetryState.OFFLINE
return self.data
except TeslaFleetError as e:
raise UpdateFailed(e.message) from e
return self._flatten(data["response"])
def _flatten(
self, data: dict[str, Any], parent: str | None = None
) -> dict[str, Any]:
"""Flatten the data structure."""
result = {}
for key, value in data.items():
if parent:
key = f"{parent}_{key}"
if isinstance(value, dict):
result.update(self._flatten(value, key))
else:
result[key] = value
return result
class TeslemetryEnergyDataCoordinator(TeslemetryDataCoordinator):
"""Class to manage fetching data from the Teslemetry API."""
name = "Teslemetry Energy Site"
async def _async_update_data(self) -> dict[str, Any]:
"""Update energy site data using Teslemetry API."""
try:
data = await self.api.live_status()
except TeslaFleetError as e:
raise UpdateFailed(e.message) from e
# Convert Wall Connectors from array to dict
data["response"]["wall_connectors"] = {
wc["din"]: wc for wc in data["response"].get("wall_connectors", [])
}
return data["response"]