Refactor Tessie for future PR (#120406)

* Bump tessie-api

* Refactor

* revert bump

* Fix cover

* Apply suggestions from code review

Co-authored-by: G Johansson <goran.johansson@shiftit.se>

---------

Co-authored-by: G Johansson <goran.johansson@shiftit.se>
This commit is contained in:
Brett Adams 2024-06-26 19:46:30 +10:00 committed by GitHub
parent a8bf671663
commit d4dc7d76d9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 92 additions and 71 deletions

View File

@ -11,9 +11,11 @@ from homeassistant.const import CONF_ACCESS_TOKEN, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryNotReady
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceInfo
from .const import DOMAIN, MODELS
from .coordinator import TessieStateUpdateCoordinator
from .models import TessieData
from .models import TessieData, TessieVehicleData
PLATFORMS = [
Platform.BINARY_SENSOR,
@ -40,7 +42,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo
api_key = entry.data[CONF_ACCESS_TOKEN]
try:
vehicles = await get_state_of_all_vehicles(
state_of_all_vehicles = await get_state_of_all_vehicles(
session=async_get_clientsession(hass),
api_key=api_key,
only_active=True,
@ -54,13 +56,31 @@ async def async_setup_entry(hass: HomeAssistant, entry: TessieConfigEntry) -> bo
raise ConfigEntryNotReady from e
vehicles = [
TessieStateUpdateCoordinator(
hass,
api_key=api_key,
TessieVehicleData(
vin=vehicle["vin"],
data=vehicle["last_state"],
data_coordinator=TessieStateUpdateCoordinator(
hass,
api_key=api_key,
vin=vehicle["vin"],
data=vehicle["last_state"],
),
device=DeviceInfo(
identifiers={(DOMAIN, vehicle["vin"])},
manufacturer="Tesla",
configuration_url="https://my.tessie.com/",
name=vehicle["last_state"]["display_name"],
model=MODELS.get(
vehicle["last_state"]["vehicle_config"]["car_type"],
vehicle["last_state"]["vehicle_config"]["car_type"],
),
sw_version=vehicle["last_state"]["vehicle_state"]["car_version"].split(
" "
)[0],
hw_version=vehicle["last_state"]["vehicle_config"]["driver_assist"],
serial_number=vehicle["vin"],
),
)
for vehicle in vehicles["results"]
for vehicle in state_of_all_vehicles["results"]
if vehicle["last_state"] is not None
]

View File

@ -16,8 +16,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .const import TessieState
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
@dataclass(frozen=True, kw_only=True)
@ -180,11 +180,11 @@ class TessieBinarySensorEntity(TessieEntity, BinarySensorEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
description: TessieBinarySensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, description.key)
super().__init__(vehicle, description.key)
self.entity_description = description
@property

View File

@ -19,8 +19,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
@dataclass(frozen=True, kw_only=True)
@ -67,11 +67,11 @@ class TessieButtonEntity(TessieEntity, ButtonEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
description: TessieButtonEntityDescription,
) -> None:
"""Initialize the Button."""
super().__init__(coordinator, description.key)
super().__init__(vehicle, description.key)
self.entity_description = description
async def async_press(self) -> None:

View File

@ -23,8 +23,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .const import TessieClimateKeeper
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
async def async_setup_entry(
@ -62,10 +62,10 @@ class TessieClimateEntity(TessieEntity, ClimateEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the Climate entity."""
super().__init__(coordinator, "primary")
super().__init__(vehicle, "primary")
@property
def hvac_mode(self) -> HVACMode | None:

View File

@ -23,8 +23,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .const import TessieCoverStates
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
async def async_setup_entry(
@ -53,9 +53,9 @@ class TessieWindowEntity(TessieEntity, CoverEntity):
_attr_device_class = CoverDeviceClass.WINDOW
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
def __init__(self, coordinator: TessieStateUpdateCoordinator) -> None:
def __init__(self, vehicle: TessieVehicleData) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "windows")
super().__init__(vehicle, "windows")
@property
def is_closed(self) -> bool | None:
@ -94,9 +94,9 @@ class TessieChargePortEntity(TessieEntity, CoverEntity):
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
def __init__(self, coordinator: TessieStateUpdateCoordinator) -> None:
def __init__(self, vehicle: TessieVehicleData) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "charge_state_charge_port_door_open")
super().__init__(vehicle, "charge_state_charge_port_door_open")
@property
def is_closed(self) -> bool | None:
@ -120,9 +120,9 @@ class TessieFrontTrunkEntity(TessieEntity, CoverEntity):
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN
def __init__(self, coordinator: TessieStateUpdateCoordinator) -> None:
def __init__(self, vehicle: TessieVehicleData) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "vehicle_state_ft")
super().__init__(vehicle, "vehicle_state_ft")
@property
def is_closed(self) -> bool | None:
@ -141,9 +141,9 @@ class TessieRearTrunkEntity(TessieEntity, CoverEntity):
_attr_device_class = CoverDeviceClass.DOOR
_attr_supported_features = CoverEntityFeature.OPEN | CoverEntityFeature.CLOSE
def __init__(self, coordinator: TessieStateUpdateCoordinator) -> None:
def __init__(self, vehicle: TessieVehicleData) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "vehicle_state_rt")
super().__init__(vehicle, "vehicle_state_rt")
@property
def is_closed(self) -> bool | None:

View File

@ -9,8 +9,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import TessieConfigEntry
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
async def async_setup_entry(
@ -36,10 +36,10 @@ class TessieDeviceTrackerEntity(TessieEntity, TrackerEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the device tracker."""
super().__init__(coordinator, self.key)
super().__init__(vehicle, self.key)
@property
def source_type(self) -> SourceType | str:

View File

@ -6,11 +6,11 @@ from typing import Any
from aiohttp import ClientResponseError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN, MODELS
from .const import DOMAIN
from .coordinator import TessieStateUpdateCoordinator
from .models import TessieVehicleData
class TessieEntity(CoordinatorEntity[TessieStateUpdateCoordinator]):
@ -20,28 +20,17 @@ class TessieEntity(CoordinatorEntity[TessieStateUpdateCoordinator]):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
key: str,
) -> None:
"""Initialize common aspects of a Tessie entity."""
super().__init__(coordinator)
self.vin = coordinator.vin
super().__init__(vehicle.data_coordinator)
self.vin = vehicle.vin
self.key = key
car_type = coordinator.data["vehicle_config_car_type"]
self._attr_translation_key = key
self._attr_unique_id = f"{self.vin}-{key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, self.vin)},
manufacturer="Tesla",
configuration_url="https://my.tessie.com/",
name=coordinator.data["display_name"],
model=MODELS.get(car_type, car_type),
sw_version=coordinator.data["vehicle_state_car_version"].split(" ")[0],
hw_version=coordinator.data["vehicle_config_driver_assist"],
serial_number=self.vin,
)
self._attr_unique_id = f"{vehicle.vin}-{key}"
self._attr_device_info = vehicle.device
@property
def _value(self) -> Any:

View File

@ -23,8 +23,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .const import DOMAIN, TessieChargeCableLockStates
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
async def async_setup_entry(
@ -82,10 +82,10 @@ class TessieLockEntity(TessieEntity, LockEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "vehicle_state_locked")
super().__init__(vehicle, "vehicle_state_locked")
@property
def is_locked(self) -> bool | None:
@ -110,10 +110,10 @@ class TessieSpeedLimitEntity(TessieEntity, LockEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "vehicle_state_speed_limit_mode_active")
super().__init__(vehicle, "vehicle_state_speed_limit_mode_active")
@property
def is_locked(self) -> bool | None:
@ -160,10 +160,10 @@ class TessieCableLockEntity(TessieEntity, LockEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, "charge_state_charge_port_latch")
super().__init__(vehicle, "charge_state_charge_port_latch")
@property
def is_locked(self) -> bool | None:

View File

@ -11,8 +11,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
STATES = {
"Playing": MediaPlayerState.PLAYING,
@ -39,10 +39,10 @@ class TessieMediaEntity(TessieEntity, MediaPlayerEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the media player entity."""
super().__init__(coordinator, "media")
super().__init__(vehicle, "media")
@property
def state(self) -> MediaPlayerState:

View File

@ -4,6 +4,8 @@ from __future__ import annotations
from dataclasses import dataclass
from homeassistant.helpers.device_registry import DeviceInfo
from .coordinator import TessieStateUpdateCoordinator
@ -11,4 +13,13 @@ from .coordinator import TessieStateUpdateCoordinator
class TessieData:
"""Data for the Tessie integration."""
vehicles: list[TessieStateUpdateCoordinator]
vehicles: list[TessieVehicleData]
@dataclass
class TessieVehicleData:
"""Data for a Tessie vehicle."""
data_coordinator: TessieStateUpdateCoordinator
device: DeviceInfo
vin: str

View File

@ -23,8 +23,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
@dataclass(frozen=True, kw_only=True)
@ -101,11 +101,11 @@ class TessieNumberEntity(TessieEntity, NumberEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
description: TessieNumberEntityDescription,
) -> None:
"""Initialize the Number entity."""
super().__init__(coordinator, description.key)
super().__init__(vehicle, description.key)
self.entity_description = description
@property

View File

@ -35,7 +35,8 @@ async def async_setup_entry(
TessieSeatHeaterSelectEntity(vehicle, key)
for vehicle in data.vehicles
for key in SEAT_HEATERS
if key in vehicle.data # not all vehicles have rear center or third row
if key
in vehicle.data_coordinator.data # not all vehicles have rear center or third row
)

View File

@ -34,8 +34,8 @@ from homeassistant.util.variance import ignore_variance
from . import TessieConfigEntry
from .const import TessieChargeStates
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
@callback
@ -280,11 +280,11 @@ class TessieSensorEntity(TessieEntity, SensorEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
description: TessieSensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator, description.key)
super().__init__(vehicle, description.key)
self.entity_description = description
@property

View File

@ -29,8 +29,8 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
@dataclass(frozen=True, kw_only=True)
@ -84,7 +84,7 @@ async def async_setup_entry(
TessieSwitchEntity(vehicle, description)
for vehicle in entry.runtime_data.vehicles
for description in DESCRIPTIONS
if description.key in vehicle.data
if description.key in vehicle.data_coordinator.data
),
(
TessieChargeSwitchEntity(vehicle, CHARGE_DESCRIPTION)
@ -102,11 +102,11 @@ class TessieSwitchEntity(TessieEntity, SwitchEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
description: TessieSwitchEntityDescription,
) -> None:
"""Initialize the Switch."""
super().__init__(coordinator, description.key)
super().__init__(vehicle, description.key)
self.entity_description = description
@property

View File

@ -12,8 +12,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import TessieConfigEntry
from .const import TessieUpdateStatus
from .coordinator import TessieStateUpdateCoordinator
from .entity import TessieEntity
from .models import TessieVehicleData
async def async_setup_entry(
@ -34,10 +34,10 @@ class TessieUpdateEntity(TessieEntity, UpdateEntity):
def __init__(
self,
coordinator: TessieStateUpdateCoordinator,
vehicle: TessieVehicleData,
) -> None:
"""Initialize the Update."""
super().__init__(coordinator, "update")
super().__init__(vehicle, "update")
@property
def supported_features(self) -> UpdateEntityFeature: