Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """Tessie integration."""
2 
3 import asyncio
4 from http import HTTPStatus
5 import logging
6 
7 from aiohttp import ClientError, ClientResponseError
8 from tesla_fleet_api import EnergySpecific, Tessie
9 from tesla_fleet_api.const import Scope
10 from tesla_fleet_api.exceptions import TeslaFleetError
11 from tessie_api import get_state_of_all_vehicles
12 
13 from homeassistant.config_entries import ConfigEntry
14 from homeassistant.const import CONF_ACCESS_TOKEN, Platform
15 from homeassistant.core import HomeAssistant
16 from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
17 from homeassistant.helpers.aiohttp_client import async_get_clientsession
18 from homeassistant.helpers.device_registry import DeviceInfo
19 
20 from .const import DOMAIN, MODELS
21 from .coordinator import (
22  TessieEnergySiteInfoCoordinator,
23  TessieEnergySiteLiveCoordinator,
24  TessieStateUpdateCoordinator,
25 )
26 from .models import TessieData, TessieEnergyData, TessieVehicleData
27 
28 PLATFORMS = [
29  Platform.BINARY_SENSOR,
30  Platform.BUTTON,
31  Platform.CLIMATE,
32  Platform.COVER,
33  Platform.DEVICE_TRACKER,
34  Platform.LOCK,
35  Platform.MEDIA_PLAYER,
36  Platform.NUMBER,
37  Platform.SELECT,
38  Platform.SENSOR,
39  Platform.SWITCH,
40  Platform.UPDATE,
41 ]
42 
43 _LOGGER = logging.getLogger(__name__)
44 
45 type TessieConfigEntry = ConfigEntry[TessieData]
46 
47 
48 async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bool:
49  """Set up Tessie config."""
50  api_key = entry.data[CONF_ACCESS_TOKEN]
51  session = async_get_clientsession(hass)
52 
53  try:
54  state_of_all_vehicles = await get_state_of_all_vehicles(
55  session=session,
56  api_key=api_key,
57  only_active=True,
58  )
59  except ClientResponseError as e:
60  if e.status == HTTPStatus.UNAUTHORIZED:
61  raise ConfigEntryAuthFailed from e
62  _LOGGER.error("Setup failed, unable to connect to Tessie: %s", e)
63  return False
64  except ClientError as e:
65  raise ConfigEntryNotReady from e
66 
67  vehicles = [
69  vin=vehicle["vin"],
70  data_coordinator=TessieStateUpdateCoordinator(
71  hass,
72  api_key=api_key,
73  vin=vehicle["vin"],
74  data=vehicle["last_state"],
75  ),
76  device=DeviceInfo(
77  identifiers={(DOMAIN, vehicle["vin"])},
78  manufacturer="Tesla",
79  configuration_url="https://my.tessie.com/",
80  name=vehicle["last_state"]["display_name"],
81  model=MODELS.get(
82  vehicle["last_state"]["vehicle_config"]["car_type"],
83  vehicle["last_state"]["vehicle_config"]["car_type"],
84  ),
85  sw_version=vehicle["last_state"]["vehicle_state"]["car_version"].split(
86  " "
87  )[0],
88  hw_version=vehicle["last_state"]["vehicle_config"]["driver_assist"],
89  serial_number=vehicle["vin"],
90  ),
91  )
92  for vehicle in state_of_all_vehicles["results"]
93  if vehicle["last_state"] is not None
94  ]
95 
96  # Energy Sites
97  tessie = Tessie(session, api_key)
98  energysites: list[TessieEnergyData] = []
99 
100  try:
101  scopes = await tessie.scopes()
102  except TeslaFleetError as e:
103  raise ConfigEntryNotReady from e
104 
105  if Scope.ENERGY_DEVICE_DATA in scopes:
106  try:
107  products = (await tessie.products())["response"]
108  except TeslaFleetError as e:
109  raise ConfigEntryNotReady from e
110 
111  for product in products:
112  if "energy_site_id" in product:
113  site_id = product["energy_site_id"]
114  if not (
115  product["components"]["battery"]
116  or product["components"]["solar"]
117  or "wall_connectors" in product["components"]
118  ):
119  _LOGGER.debug(
120  "Skipping Energy Site %s as it has no components",
121  site_id,
122  )
123  continue
124 
125  api = EnergySpecific(tessie.energy, site_id)
126  energysites.append(
128  api=api,
129  id=site_id,
130  live_coordinator=TessieEnergySiteLiveCoordinator(hass, api),
131  info_coordinator=TessieEnergySiteInfoCoordinator(hass, api),
132  device=DeviceInfo(
133  identifiers={(DOMAIN, str(site_id))},
134  manufacturer="Tesla",
135  name=product.get("site_name", "Energy Site"),
136  ),
137  )
138  )
139 
140  # Populate coordinator data before forwarding to platforms
141  await asyncio.gather(
142  *(
143  energysite.live_coordinator.async_config_entry_first_refresh()
144  for energysite in energysites
145  ),
146  *(
147  energysite.info_coordinator.async_config_entry_first_refresh()
148  for energysite in energysites
149  ),
150  )
151 
152  entry.runtime_data = TessieData(vehicles, energysites)
153  await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
154 
155  return True
156 
157 
158 async def async_unload_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bool:
159  """Unload Tessie Config."""
160  return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
bool async_unload_entry(HomeAssistant hass, TessieConfigEntry entry)
Definition: __init__.py:158
bool async_setup_entry(HomeAssistant hass, TessieConfigEntry entry)
Definition: __init__.py:48
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)