2024-01-25 11:54:47 +00:00
|
|
|
"""Teslemetry Data Coordinator."""
|
2024-03-08 15:35:23 +00:00
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-05-27 10:37:33 +00:00
|
|
|
from datetime import datetime, timedelta
|
2025-02-09 14:50:04 +00:00
|
|
|
from typing import TYPE_CHECKING, Any
|
2024-01-25 11:54:47 +00:00
|
|
|
|
2024-03-04 17:42:56 +00:00
|
|
|
from tesla_fleet_api import EnergySpecific, VehicleSpecific
|
2024-09-24 08:32:38 +00:00
|
|
|
from tesla_fleet_api.const import TeslaEnergyPeriod, VehicleDataEndpoint
|
2024-04-08 07:44:51 +00:00
|
|
|
from tesla_fleet_api.exceptions import (
|
|
|
|
InvalidToken,
|
|
|
|
SubscriptionRequired,
|
|
|
|
TeslaFleetError,
|
|
|
|
)
|
2024-01-25 11:54:47 +00:00
|
|
|
|
|
|
|
from homeassistant.core import HomeAssistant
|
2024-05-10 08:52:33 +00:00
|
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed
|
2024-01-25 11:54:47 +00:00
|
|
|
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
|
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
if TYPE_CHECKING:
|
|
|
|
from . import TeslemetryConfigEntry
|
|
|
|
|
2024-12-10 07:35:53 +00:00
|
|
|
from .const import ENERGY_HISTORY_FIELDS, LOGGER
|
2024-10-25 09:50:37 +00:00
|
|
|
from .helpers import flatten
|
2024-01-25 11:54:47 +00:00
|
|
|
|
2024-12-24 00:59:36 +00:00
|
|
|
VEHICLE_INTERVAL = timedelta(seconds=60)
|
2024-05-27 10:37:33 +00:00
|
|
|
VEHICLE_WAIT = timedelta(minutes=15)
|
2024-05-10 08:52:33 +00:00
|
|
|
ENERGY_LIVE_INTERVAL = timedelta(seconds=30)
|
|
|
|
ENERGY_INFO_INTERVAL = timedelta(seconds=30)
|
2024-09-24 08:32:38 +00:00
|
|
|
ENERGY_HISTORY_INTERVAL = timedelta(seconds=60)
|
2024-05-10 08:52:33 +00:00
|
|
|
|
2024-03-11 21:17:42 +00:00
|
|
|
ENDPOINTS = [
|
|
|
|
VehicleDataEndpoint.CHARGE_STATE,
|
|
|
|
VehicleDataEndpoint.CLIMATE_STATE,
|
|
|
|
VehicleDataEndpoint.DRIVE_STATE,
|
|
|
|
VehicleDataEndpoint.LOCATION_DATA,
|
|
|
|
VehicleDataEndpoint.VEHICLE_STATE,
|
2024-03-24 08:29:10 +00:00
|
|
|
VehicleDataEndpoint.VEHICLE_CONFIG,
|
2024-03-11 21:17:42 +00:00
|
|
|
]
|
2024-01-25 11:54:47 +00:00
|
|
|
|
|
|
|
|
2024-05-10 08:52:33 +00:00
|
|
|
class TeslemetryVehicleDataCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|
|
|
"""Class to manage fetching data from the Teslemetry API."""
|
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
config_entry: TeslemetryConfigEntry
|
2024-05-27 10:37:33 +00:00
|
|
|
last_active: datetime
|
2024-01-25 11:54:47 +00:00
|
|
|
|
2024-03-04 17:42:56 +00:00
|
|
|
def __init__(
|
2025-02-09 14:50:04 +00:00
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: TeslemetryConfigEntry,
|
|
|
|
api: VehicleSpecific,
|
|
|
|
product: dict,
|
2024-03-04 17:42:56 +00:00
|
|
|
) -> None:
|
|
|
|
"""Initialize Teslemetry Vehicle Update Coordinator."""
|
2024-01-25 11:54:47 +00:00
|
|
|
super().__init__(
|
|
|
|
hass,
|
|
|
|
LOGGER,
|
2025-02-09 14:50:04 +00:00
|
|
|
config_entry=config_entry,
|
2024-05-10 08:52:33 +00:00
|
|
|
name="Teslemetry Vehicle",
|
|
|
|
update_interval=VEHICLE_INTERVAL,
|
2024-01-25 11:54:47 +00:00
|
|
|
)
|
|
|
|
self.api = api
|
2024-05-10 08:52:33 +00:00
|
|
|
self.data = flatten(product)
|
2024-05-27 10:37:33 +00:00
|
|
|
self.last_active = datetime.now()
|
2024-01-25 11:54:47 +00:00
|
|
|
|
|
|
|
async def _async_update_data(self) -> dict[str, Any]:
|
|
|
|
"""Update vehicle data using Teslemetry API."""
|
2024-05-27 10:37:33 +00:00
|
|
|
|
2024-01-25 11:54:47 +00:00
|
|
|
try:
|
2024-12-10 07:35:53 +00:00
|
|
|
data = (await self.api.vehicle_data(endpoints=ENDPOINTS))["response"]
|
|
|
|
except (InvalidToken, SubscriptionRequired) as e:
|
2024-04-08 07:44:51 +00:00
|
|
|
raise ConfigEntryAuthFailed from e
|
2024-01-25 11:54:47 +00:00
|
|
|
except TeslaFleetError as e:
|
|
|
|
raise UpdateFailed(e.message) from e
|
|
|
|
|
2024-05-10 08:52:33 +00:00
|
|
|
return flatten(data)
|
2024-03-04 17:42:56 +00:00
|
|
|
|
|
|
|
|
2024-05-10 08:52:33 +00:00
|
|
|
class TeslemetryEnergySiteLiveCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|
|
|
"""Class to manage fetching energy site live status from the Teslemetry API."""
|
2024-03-04 17:42:56 +00:00
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
config_entry: TeslemetryConfigEntry
|
2025-01-13 11:44:36 +00:00
|
|
|
updated_once: bool
|
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: TeslemetryConfigEntry,
|
|
|
|
api: EnergySpecific,
|
|
|
|
data: dict,
|
|
|
|
) -> None:
|
2024-05-10 08:52:33 +00:00
|
|
|
"""Initialize Teslemetry Energy Site Live coordinator."""
|
|
|
|
super().__init__(
|
|
|
|
hass,
|
|
|
|
LOGGER,
|
2025-02-09 17:51:43 +00:00
|
|
|
config_entry=config_entry,
|
2024-05-10 08:52:33 +00:00
|
|
|
name="Teslemetry Energy Site Live",
|
|
|
|
update_interval=ENERGY_LIVE_INTERVAL,
|
|
|
|
)
|
|
|
|
self.api = api
|
2024-03-04 17:42:56 +00:00
|
|
|
|
2025-01-13 11:44:36 +00:00
|
|
|
# Convert Wall Connectors from array to dict
|
|
|
|
data["wall_connectors"] = {
|
|
|
|
wc["din"]: wc for wc in (data.get("wall_connectors") or [])
|
|
|
|
}
|
|
|
|
self.data = data
|
|
|
|
|
2024-03-04 17:42:56 +00:00
|
|
|
async def _async_update_data(self) -> dict[str, Any]:
|
|
|
|
"""Update energy site data using Teslemetry API."""
|
|
|
|
|
|
|
|
try:
|
2024-05-10 08:52:33 +00:00
|
|
|
data = (await self.api.live_status())["response"]
|
2024-12-10 07:35:53 +00:00
|
|
|
except (InvalidToken, SubscriptionRequired) as e:
|
2024-04-08 07:44:51 +00:00
|
|
|
raise ConfigEntryAuthFailed from e
|
2024-03-04 17:42:56 +00:00
|
|
|
except TeslaFleetError as e:
|
|
|
|
raise UpdateFailed(e.message) from e
|
|
|
|
|
|
|
|
# Convert Wall Connectors from array to dict
|
2024-05-10 08:52:33 +00:00
|
|
|
data["wall_connectors"] = {
|
|
|
|
wc["din"]: wc for wc in (data.get("wall_connectors") or [])
|
2024-03-04 17:42:56 +00:00
|
|
|
}
|
|
|
|
|
2024-05-10 08:52:33 +00:00
|
|
|
return data
|
2024-05-10 10:38:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TeslemetryEnergySiteInfoCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|
|
|
"""Class to manage fetching energy site info from the Teslemetry API."""
|
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
config_entry: TeslemetryConfigEntry
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: TeslemetryConfigEntry,
|
|
|
|
api: EnergySpecific,
|
|
|
|
product: dict,
|
|
|
|
) -> None:
|
2024-05-10 10:38:20 +00:00
|
|
|
"""Initialize Teslemetry Energy Info coordinator."""
|
|
|
|
super().__init__(
|
|
|
|
hass,
|
|
|
|
LOGGER,
|
2025-02-09 17:51:43 +00:00
|
|
|
config_entry=config_entry,
|
2024-05-10 10:38:20 +00:00
|
|
|
name="Teslemetry Energy Site Info",
|
|
|
|
update_interval=ENERGY_INFO_INTERVAL,
|
|
|
|
)
|
|
|
|
self.api = api
|
|
|
|
self.data = product
|
|
|
|
|
|
|
|
async def _async_update_data(self) -> dict[str, Any]:
|
|
|
|
"""Update energy site data using Teslemetry API."""
|
|
|
|
|
|
|
|
try:
|
|
|
|
data = (await self.api.site_info())["response"]
|
2024-12-10 07:35:53 +00:00
|
|
|
except (InvalidToken, SubscriptionRequired) as e:
|
2024-05-10 10:38:20 +00:00
|
|
|
raise ConfigEntryAuthFailed from e
|
|
|
|
except TeslaFleetError as e:
|
|
|
|
raise UpdateFailed(e.message) from e
|
|
|
|
|
|
|
|
return flatten(data)
|
2024-09-24 08:32:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TeslemetryEnergyHistoryCoordinator(DataUpdateCoordinator[dict[str, Any]]):
|
|
|
|
"""Class to manage fetching energy site info from the Teslemetry API."""
|
|
|
|
|
2025-02-09 14:50:04 +00:00
|
|
|
config_entry: TeslemetryConfigEntry
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
hass: HomeAssistant,
|
|
|
|
config_entry: TeslemetryConfigEntry,
|
|
|
|
api: EnergySpecific,
|
|
|
|
) -> None:
|
2024-09-24 08:32:38 +00:00
|
|
|
"""Initialize Teslemetry Energy Info coordinator."""
|
|
|
|
super().__init__(
|
|
|
|
hass,
|
|
|
|
LOGGER,
|
2025-02-09 17:51:43 +00:00
|
|
|
config_entry=config_entry,
|
2024-09-24 08:32:38 +00:00
|
|
|
name=f"Teslemetry Energy History {api.energy_site_id}",
|
|
|
|
update_interval=ENERGY_HISTORY_INTERVAL,
|
|
|
|
)
|
|
|
|
self.api = api
|
|
|
|
|
|
|
|
async def _async_update_data(self) -> dict[str, Any]:
|
|
|
|
"""Update energy site data using Teslemetry API."""
|
|
|
|
|
|
|
|
try:
|
|
|
|
data = (await self.api.energy_history(TeslaEnergyPeriod.DAY))["response"]
|
2024-12-10 07:35:53 +00:00
|
|
|
except (InvalidToken, SubscriptionRequired) as e:
|
2024-09-24 08:32:38 +00:00
|
|
|
raise ConfigEntryAuthFailed from e
|
|
|
|
except TeslaFleetError as e:
|
|
|
|
raise UpdateFailed(e.message) from e
|
|
|
|
|
|
|
|
# Add all time periods together
|
|
|
|
output = {key: 0 for key in ENERGY_HISTORY_FIELDS}
|
|
|
|
for period in data.get("time_series", []):
|
|
|
|
for key in ENERGY_HISTORY_FIELDS:
|
|
|
|
output[key] += period.get(key, 0)
|
|
|
|
|
|
|
|
return output
|