1
0
mirror of https://github.com/home-assistant/core.git synced 2026-04-02 00:20:30 +01:00

Add command compatibility scaffold for Tessie migration (#166458)

This commit is contained in:
Brett Adams
2026-04-01 05:52:09 +10:00
committed by GitHub
parent 962d5386c7
commit 7d145cd3b8
4 changed files with 52 additions and 27 deletions

View File

@@ -2,21 +2,20 @@
from abc import abstractmethod
from collections.abc import Awaitable, Callable
from inspect import isawaitable
from typing import Any
from aiohttp import ClientError
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import DOMAIN, TRANSLATED_ERRORS
from .const import DOMAIN
from .coordinator import (
TessieEnergyHistoryCoordinator,
TessieEnergySiteInfoCoordinator,
TessieEnergySiteLiveCoordinator,
TessieStateUpdateCoordinator,
)
from .helpers import handle_command, handle_legacy_command
from .models import TessieEnergyData, TessieVehicleData
@@ -93,30 +92,24 @@ class TessieEntity(TessieBaseEntity):
self.async_write_ha_state()
async def run(
self, func: Callable[..., Awaitable[dict[str, Any]]], **kargs: Any
self,
command: Callable[..., Awaitable[dict[str, Any]]] | Awaitable[dict[str, Any]],
**kargs: Any,
) -> None:
"""Run a tessie_api function and handle exceptions."""
try:
response = await func(
"""Run a legacy tessie_api command function or awaitable Vehicle command."""
if isawaitable(command):
await handle_command(command)
return
await handle_legacy_command(
command(
session=self._session,
vin=self.vin,
api_key=self._api_key,
**kargs,
)
except ClientError as e:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_connect",
) from e
if response["result"] is False:
name: str = getattr(self, "name", self.entity_id)
reason: str = response.get("reason", "unknown")
translation_key = TRANSLATED_ERRORS.get(reason, "command_failed")
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key=translation_key,
translation_placeholders={"name": name, "message": reason},
)
),
name=getattr(self, "name", self.entity_id),
)
def _async_update_attrs(self) -> None:
"""Update the attributes of the entity."""

View File

@@ -1,17 +1,19 @@
"""Tessie helper functions."""
from collections.abc import Awaitable
from typing import Any
from aiohttp import ClientError
from tesla_fleet_api.exceptions import TeslaFleetError
from homeassistant.exceptions import HomeAssistantError
from . import _LOGGER
from .const import DOMAIN
from .const import DOMAIN, TRANSLATED_ERRORS
async def handle_command(command) -> dict[str, Any]:
"""Handle a command."""
async def handle_command(command: Awaitable[dict[str, Any]]) -> dict[str, Any]:
"""Handle an awaitable Vehicle/EnergySite command."""
try:
result = await command
except TeslaFleetError as e:
@@ -22,3 +24,22 @@ async def handle_command(command) -> dict[str, Any]:
) from e
_LOGGER.debug("Command result: %s", result)
return result
async def handle_legacy_command(command: Awaitable[dict[str, Any]], name: str) -> None:
"""Handle a legacy tessie_api command result."""
try:
response = await command
except ClientError as e:
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key="cannot_connect",
) from e
if response["result"] is False:
reason: str = response.get("reason", "unknown")
translation_key = TRANSLATED_ERRORS.get(reason, "command_failed")
raise HomeAssistantError(
translation_domain=DOMAIN,
translation_key=translation_key,
translation_placeholders={"name": name, "message": reason},
)

View File

@@ -4,7 +4,7 @@ from __future__ import annotations
from dataclasses import dataclass
from tesla_fleet_api.tessie import EnergySite
from tesla_fleet_api.tessie import EnergySite, Vehicle
from homeassistant.helpers.device_registry import DeviceInfo
@@ -43,3 +43,4 @@ class TessieVehicleData:
data_coordinator: TessieStateUpdateCoordinator
device: DeviceInfo
vin: str
api: Vehicle | None = None

View File

@@ -68,3 +68,13 @@ async def test_scopes_error(hass: HomeAssistant) -> None:
):
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.SETUP_RETRY
async def test_vehicle_api_handle_is_optional(hass: HomeAssistant) -> None:
"""Test runtime vehicle API handle defaults to None during scaffold stage."""
entry = await setup_platform(hass)
assert entry.state is ConfigEntryState.LOADED
vehicles = entry.runtime_data.vehicles
assert vehicles
assert all(vehicle.api is None for vehicle in vehicles)