core/homeassistant/components/tessie/coordinator.py

88 lines
2.8 KiB
Python
Raw Normal View History

"""Tessie Data Coordinator."""
from datetime import timedelta
from http import HTTPStatus
import logging
from typing import Any
from aiohttp import ClientResponseError
from tessie_api import get_state
from homeassistant.core import HomeAssistant
Add reauth to Tessie (#105419) * First pass at Tessie * Working POC * async_step_reauth * Config Flow tests * WIP * Add test requirement * correctly gen test requirements * 100% coverage * Remove remnants of copy paste * Add TPMS * Fix docstring * Remove redundant line * Fix some more copied docstrings * Grammar * Create reusable StrEnum * Streamline get * Add a couple more sensors * Removed need for a model * Move MODELS * Remove DOMAIN from config flow * Add translation strings * Remove unused parameter * Simplify error handling * Refactor coordinator to class * Add missing types * Add icon to shift state * Simplify setdefault Co-authored-by: J. Nick Koston <nick@koston.org> * Use walrus for async_unload_platforms Co-authored-by: J. Nick Koston <nick@koston.org> * Reformat entity init Co-authored-by: J. Nick Koston <nick@koston.org> * Remove Unique ID * Better Config Flow Tests * Fix all remaining tests * Standardise docstring * Remove redudnant test * Set TessieDataUpdateCoordinator on entity * Correct some sensors * add error types * Make shift state a ENUM sensor * Add more sensors * Fix translation string * Add precision suggestions * Move session from init to coordinator * Add api_key type * Remove api_key parameter * Meta changes * Update TessieEntity and TessieSensor translations * Goodbye translation keys * bump tessie-api to 0.0.9 * Fix only_active to be True * Per vehicle coordinator * Rework coordinator * Fix coverage * WIP * The grand rework * Add comments * Use ENUM more * Add ENUM translations * Update homeassistant/components/tessie/sensor.py Co-authored-by: J. Nick Koston <nick@koston.org> * Add entity_category * Remove reauth * Remove session * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Add property tag * Add error text * Complete config flow tests * Fix property and rename * Fix init test * Reworked coordinator tests * Add extra checks * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Update homeassistant/components/tessie/coordinator.py Co-authored-by: J. Nick Koston <nick@koston.org> * Apply suggestions from code review Co-authored-by: J. Nick Koston <nick@koston.org> * Ruff fix * Update homeassistant/components/tessie/config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Remove future ENUMs Co-authored-by: J. Nick Koston <nick@koston.org> * Ruff fix * Update homeassistant/components/tessie/config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Remove reauth and already configured strings * Lowercase sensor values for translation * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Fixed, before using lambda * Add value lambda * fix lambda * Fix config flow test * @bdraco fix for 500 errors * format * Add reauth * Reuse string in reauth * Ruff * remove redundant check * Improve error tests --------- Co-authored-by: J. Nick Koston <nick@koston.org>
2023-12-10 07:37:57 +00:00
from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import TessieStatus
# This matches the update interval Tessie performs server side
TESSIE_SYNC_INTERVAL = 10
_LOGGER = logging.getLogger(__name__)
class TessieDataUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the Tessie API."""
def __init__(
self,
hass: HomeAssistant,
api_key: str,
vin: str,
data: dict[str, Any],
) -> None:
"""Initialize Tessie Data Update Coordinator."""
super().__init__(
hass,
_LOGGER,
name="Tessie",
update_method=self.async_update_data,
update_interval=timedelta(seconds=TESSIE_SYNC_INTERVAL),
)
self.api_key = api_key
self.vin = vin
self.session = async_get_clientsession(hass)
self.data = self._flattern(data)
self.did_first_update = False
async def async_update_data(self) -> dict[str, Any]:
"""Update vehicle data using Tessie API."""
try:
vehicle = await get_state(
session=self.session,
api_key=self.api_key,
vin=self.vin,
use_cache=self.did_first_update,
)
except ClientResponseError as e:
if e.status == HTTPStatus.REQUEST_TIMEOUT:
# Vehicle is offline, only update state and dont throw error
self.data["state"] = TessieStatus.OFFLINE
return self.data
Add reauth to Tessie (#105419) * First pass at Tessie * Working POC * async_step_reauth * Config Flow tests * WIP * Add test requirement * correctly gen test requirements * 100% coverage * Remove remnants of copy paste * Add TPMS * Fix docstring * Remove redundant line * Fix some more copied docstrings * Grammar * Create reusable StrEnum * Streamline get * Add a couple more sensors * Removed need for a model * Move MODELS * Remove DOMAIN from config flow * Add translation strings * Remove unused parameter * Simplify error handling * Refactor coordinator to class * Add missing types * Add icon to shift state * Simplify setdefault Co-authored-by: J. Nick Koston <nick@koston.org> * Use walrus for async_unload_platforms Co-authored-by: J. Nick Koston <nick@koston.org> * Reformat entity init Co-authored-by: J. Nick Koston <nick@koston.org> * Remove Unique ID * Better Config Flow Tests * Fix all remaining tests * Standardise docstring * Remove redudnant test * Set TessieDataUpdateCoordinator on entity * Correct some sensors * add error types * Make shift state a ENUM sensor * Add more sensors * Fix translation string * Add precision suggestions * Move session from init to coordinator * Add api_key type * Remove api_key parameter * Meta changes * Update TessieEntity and TessieSensor translations * Goodbye translation keys * bump tessie-api to 0.0.9 * Fix only_active to be True * Per vehicle coordinator * Rework coordinator * Fix coverage * WIP * The grand rework * Add comments * Use ENUM more * Add ENUM translations * Update homeassistant/components/tessie/sensor.py Co-authored-by: J. Nick Koston <nick@koston.org> * Add entity_category * Remove reauth * Remove session * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Add property tag * Add error text * Complete config flow tests * Fix property and rename * Fix init test * Reworked coordinator tests * Add extra checks * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Update homeassistant/components/tessie/coordinator.py Co-authored-by: J. Nick Koston <nick@koston.org> * Apply suggestions from code review Co-authored-by: J. Nick Koston <nick@koston.org> * Ruff fix * Update homeassistant/components/tessie/config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Remove future ENUMs Co-authored-by: J. Nick Koston <nick@koston.org> * Ruff fix * Update homeassistant/components/tessie/config_flow.py Co-authored-by: J. Nick Koston <nick@koston.org> * Remove reauth and already configured strings * Lowercase sensor values for translation * Update homeassistant/components/tessie/__init__.py Co-authored-by: J. Nick Koston <nick@koston.org> * Fixed, before using lambda * Add value lambda * fix lambda * Fix config flow test * @bdraco fix for 500 errors * format * Add reauth * Reuse string in reauth * Ruff * remove redundant check * Improve error tests --------- Co-authored-by: J. Nick Koston <nick@koston.org>
2023-12-10 07:37:57 +00:00
if e.status == HTTPStatus.UNAUTHORIZED:
# Auth Token is no longer valid
raise ConfigEntryAuthFailed from e
raise e
self.did_first_update = True
if vehicle["state"] == TessieStatus.ONLINE:
# Vehicle is online, all data is fresh
return self._flattern(vehicle)
# Vehicle is asleep, only update state
self.data["state"] = vehicle["state"]
return self.data
def _flattern(
self, data: dict[str, Any], parent: str | None = None
) -> dict[str, Any]:
"""Flattern the data structure."""
result = {}
for key, value in data.items():
if parent:
key = f"{parent}_{key}"
if isinstance(value, dict):
result.update(self._flattern(value, key))
else:
result[key] = value
return result