From d4dc7d76d95b71295121307f72d6b501907d81a7 Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Wed, 26 Jun 2024 19:46:30 +1000 Subject: [PATCH] Refactor Tessie for future PR (#120406) * Bump tessie-api * Refactor * revert bump * Fix cover * Apply suggestions from code review Co-authored-by: G Johansson --------- Co-authored-by: G Johansson --- homeassistant/components/tessie/__init__.py | 34 +++++++++++++++---- .../components/tessie/binary_sensor.py | 6 ++-- homeassistant/components/tessie/button.py | 6 ++-- homeassistant/components/tessie/climate.py | 6 ++-- homeassistant/components/tessie/cover.py | 18 +++++----- .../components/tessie/device_tracker.py | 6 ++-- homeassistant/components/tessie/entity.py | 25 ++++---------- homeassistant/components/tessie/lock.py | 14 ++++---- .../components/tessie/media_player.py | 6 ++-- homeassistant/components/tessie/models.py | 13 ++++++- homeassistant/components/tessie/number.py | 6 ++-- homeassistant/components/tessie/select.py | 3 +- homeassistant/components/tessie/sensor.py | 6 ++-- homeassistant/components/tessie/switch.py | 8 ++--- homeassistant/components/tessie/update.py | 6 ++-- 15 files changed, 92 insertions(+), 71 deletions(-) diff --git a/homeassistant/components/tessie/__init__.py b/homeassistant/components/tessie/__init__.py index 9e7bc42fa27..37fb669e54b 100644 --- a/homeassistant/components/tessie/__init__.py +++ b/homeassistant/components/tessie/__init__.py @@ -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 ] diff --git a/homeassistant/components/tessie/binary_sensor.py b/homeassistant/components/tessie/binary_sensor.py index 2d3f1134444..eee85ce8466 100644 --- a/homeassistant/components/tessie/binary_sensor.py +++ b/homeassistant/components/tessie/binary_sensor.py @@ -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 diff --git a/homeassistant/components/tessie/button.py b/homeassistant/components/tessie/button.py index 43dadec60e6..8f80f27616b 100644 --- a/homeassistant/components/tessie/button.py +++ b/homeassistant/components/tessie/button.py @@ -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: diff --git a/homeassistant/components/tessie/climate.py b/homeassistant/components/tessie/climate.py index 2a3b77ab8ce..7676d2f071b 100644 --- a/homeassistant/components/tessie/climate.py +++ b/homeassistant/components/tessie/climate.py @@ -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: diff --git a/homeassistant/components/tessie/cover.py b/homeassistant/components/tessie/cover.py index 5be08107a29..6fdd950b809 100644 --- a/homeassistant/components/tessie/cover.py +++ b/homeassistant/components/tessie/cover.py @@ -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: diff --git a/homeassistant/components/tessie/device_tracker.py b/homeassistant/components/tessie/device_tracker.py index 382c775c200..300aae7d858 100644 --- a/homeassistant/components/tessie/device_tracker.py +++ b/homeassistant/components/tessie/device_tracker.py @@ -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: diff --git a/homeassistant/components/tessie/entity.py b/homeassistant/components/tessie/entity.py index 35d41af32f2..1b7ddcbe84c 100644 --- a/homeassistant/components/tessie/entity.py +++ b/homeassistant/components/tessie/entity.py @@ -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: diff --git a/homeassistant/components/tessie/lock.py b/homeassistant/components/tessie/lock.py index 0ea65ce4781..d73d83e399d 100644 --- a/homeassistant/components/tessie/lock.py +++ b/homeassistant/components/tessie/lock.py @@ -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: diff --git a/homeassistant/components/tessie/media_player.py b/homeassistant/components/tessie/media_player.py index f99c8ad1e1f..f3b5e266604 100644 --- a/homeassistant/components/tessie/media_player.py +++ b/homeassistant/components/tessie/media_player.py @@ -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: diff --git a/homeassistant/components/tessie/models.py b/homeassistant/components/tessie/models.py index 3919db3f6d3..e96562ff8e1 100644 --- a/homeassistant/components/tessie/models.py +++ b/homeassistant/components/tessie/models.py @@ -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 diff --git a/homeassistant/components/tessie/number.py b/homeassistant/components/tessie/number.py index 222922eba3e..56739193d7f 100644 --- a/homeassistant/components/tessie/number.py +++ b/homeassistant/components/tessie/number.py @@ -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 diff --git a/homeassistant/components/tessie/select.py b/homeassistant/components/tessie/select.py index 801d465ea2a..43af8161697 100644 --- a/homeassistant/components/tessie/select.py +++ b/homeassistant/components/tessie/select.py @@ -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 ) diff --git a/homeassistant/components/tessie/sensor.py b/homeassistant/components/tessie/sensor.py index c3023948f4c..dc910c7a03a 100644 --- a/homeassistant/components/tessie/sensor.py +++ b/homeassistant/components/tessie/sensor.py @@ -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 diff --git a/homeassistant/components/tessie/switch.py b/homeassistant/components/tessie/switch.py index 2f3902b3bd3..03bd018cd83 100644 --- a/homeassistant/components/tessie/switch.py +++ b/homeassistant/components/tessie/switch.py @@ -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 diff --git a/homeassistant/components/tessie/update.py b/homeassistant/components/tessie/update.py index 5f51a38d77d..73a01873e37 100644 --- a/homeassistant/components/tessie/update.py +++ b/homeassistant/components/tessie/update.py @@ -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: