Home Assistant Unofficial Reference 2024.12.1
coordinator.py
Go to the documentation of this file.
1 """Tessie Data Coordinator."""
2 
3 from datetime import timedelta
4 from http import HTTPStatus
5 import logging
6 from typing import Any
7 
8 from aiohttp import ClientResponseError
9 from tesla_fleet_api import EnergySpecific
10 from tesla_fleet_api.exceptions import InvalidToken, MissingToken, TeslaFleetError
11 from tessie_api import get_state, get_status
12 
13 from homeassistant.core import HomeAssistant
14 from homeassistant.exceptions import ConfigEntryAuthFailed
15 from homeassistant.helpers.aiohttp_client import async_get_clientsession
16 from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
17 
18 from .const import TessieStatus
19 
20 # This matches the update interval Tessie performs server side
21 TESSIE_SYNC_INTERVAL = 10
22 TESSIE_FLEET_API_SYNC_INTERVAL = timedelta(seconds=30)
23 
24 _LOGGER = logging.getLogger(__name__)
25 
26 
27 def flatten(data: dict[str, Any], parent: str | None = None) -> dict[str, Any]:
28  """Flatten the data structure."""
29  result = {}
30  for key, value in data.items():
31  if parent:
32  key = f"{parent}_{key}"
33  if isinstance(value, dict):
34  result.update(flatten(value, key))
35  else:
36  result[key] = value
37  return result
38 
39 
41  """Class to manage fetching data from the Tessie API."""
42 
43  def __init__(
44  self,
45  hass: HomeAssistant,
46  api_key: str,
47  vin: str,
48  data: dict[str, Any],
49  ) -> None:
50  """Initialize Tessie Data Update Coordinator."""
51  super().__init__(
52  hass,
53  _LOGGER,
54  name="Tessie",
55  update_interval=timedelta(seconds=TESSIE_SYNC_INTERVAL),
56  )
57  self.api_keyapi_key = api_key
58  self.vinvin = vin
59  self.sessionsession = async_get_clientsession(hass)
60  self.datadatadata = flatten(data)
61 
62  async def _async_update_data(self) -> dict[str, Any]:
63  """Update vehicle data using Tessie API."""
64  try:
65  status = await get_status(
66  session=self.sessionsession,
67  api_key=self.api_keyapi_key,
68  vin=self.vinvin,
69  )
70  if status["status"] == TessieStatus.ASLEEP:
71  # Vehicle is asleep, no need to poll for data
72  self.datadatadata["state"] = status["status"]
73  return self.datadatadata
74 
75  vehicle = await get_state(
76  session=self.sessionsession,
77  api_key=self.api_keyapi_key,
78  vin=self.vinvin,
79  use_cache=True,
80  )
81  except ClientResponseError as e:
82  if e.status == HTTPStatus.UNAUTHORIZED:
83  # Auth Token is no longer valid
84  raise ConfigEntryAuthFailed from e
85  raise
86 
87  return flatten(vehicle)
88 
89 
91  """Class to manage fetching energy site live status from the Tessie API."""
92 
93  def __init__(self, hass: HomeAssistant, api: EnergySpecific) -> None:
94  """Initialize Tessie Energy Site Live coordinator."""
95  super().__init__(
96  hass,
97  _LOGGER,
98  name="Tessie Energy Site Live",
99  update_interval=TESSIE_FLEET_API_SYNC_INTERVAL,
100  )
101  self.apiapi = api
102 
103  async def _async_update_data(self) -> dict[str, Any]:
104  """Update energy site data using Tessie API."""
105 
106  try:
107  data = (await self.apiapi.live_status())["response"]
108  except (InvalidToken, MissingToken) as e:
109  raise ConfigEntryAuthFailed from e
110  except TeslaFleetError as e:
111  raise UpdateFailed(e.message) from e
112 
113  # Convert Wall Connectors from array to dict
114  data["wall_connectors"] = {
115  wc["din"]: wc for wc in (data.get("wall_connectors") or [])
116  }
117 
118  return data
119 
120 
122  """Class to manage fetching energy site info from the Tessie API."""
123 
124  def __init__(self, hass: HomeAssistant, api: EnergySpecific) -> None:
125  """Initialize Tessie Energy Info coordinator."""
126  super().__init__(
127  hass,
128  _LOGGER,
129  name="Tessie Energy Site Info",
130  update_interval=TESSIE_FLEET_API_SYNC_INTERVAL,
131  )
132  self.apiapi = api
133 
134  async def _async_update_data(self) -> dict[str, Any]:
135  """Update energy site data using Tessie API."""
136 
137  try:
138  data = (await self.apiapi.site_info())["response"]
139  except (InvalidToken, MissingToken) as e:
140  raise ConfigEntryAuthFailed from e
141  except TeslaFleetError as e:
142  raise UpdateFailed(e.message) from e
143 
144  return flatten(data)
None __init__(self, HomeAssistant hass, EnergySpecific api)
Definition: coordinator.py:124
None __init__(self, HomeAssistant hass, EnergySpecific api)
Definition: coordinator.py:93
None __init__(self, HomeAssistant hass, str api_key, str vin, dict[str, Any] data)
Definition: coordinator.py:49
str|float get_state(dict[str, float] data, str key)
Definition: sensor.py:26
def get_status(hass, host, port)
Definition: panel.py:387
dict[str, Any] flatten(dict[str, Any] data, str|None parent=None)
Definition: coordinator.py:27
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)