From 0cf29f0f842da299df7da743c7219be3de869ebd Mon Sep 17 00:00:00 2001 From: Mark Adkins Date: Sun, 16 Apr 2023 08:04:18 -0400 Subject: [PATCH] Fix SharkIQ token expiration (#89357) --- .../components/sharkiq/update_coordinator.py | 10 +++++++++- tests/components/sharkiq/test_vacuum.py | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/sharkiq/update_coordinator.py b/homeassistant/components/sharkiq/update_coordinator.py index 2afeb574f92..87f5aafe7a4 100644 --- a/homeassistant/components/sharkiq/update_coordinator.py +++ b/homeassistant/components/sharkiq/update_coordinator.py @@ -2,6 +2,7 @@ from __future__ import annotations import asyncio +from datetime import datetime, timedelta from async_timeout import timeout from sharkiq import ( @@ -60,6 +61,13 @@ class SharkIqUpdateCoordinator(DataUpdateCoordinator[bool]): async def _async_update_data(self) -> bool: """Update data device by device.""" try: + if self.ayla_api.token_expiring_soon: + await self.ayla_api.async_refresh_auth() + elif datetime.now() > self.ayla_api.auth_expiration - timedelta( + seconds=600 + ): + await self.ayla_api.async_refresh_auth() + all_vacuums = await self.ayla_api.async_list_devices() self._online_dsns = { v["dsn"] @@ -78,7 +86,7 @@ class SharkIqUpdateCoordinator(DataUpdateCoordinator[bool]): LOGGER.debug("Bad auth state. Attempting re-auth", exc_info=err) raise ConfigEntryAuthFailed from err except Exception as err: - LOGGER.exception("Unexpected error updating SharkIQ") + LOGGER.exception("Unexpected error updating SharkIQ. Attempting re-auth") raise UpdateFailed(err) from err return True diff --git a/tests/components/sharkiq/test_vacuum.py b/tests/components/sharkiq/test_vacuum.py index 84bda73e957..cfd62c9deaf 100644 --- a/tests/components/sharkiq/test_vacuum.py +++ b/tests/components/sharkiq/test_vacuum.py @@ -3,6 +3,7 @@ from __future__ import annotations from collections.abc import Iterable from copy import deepcopy +from datetime import datetime, timedelta import enum from typing import Any from unittest.mock import patch @@ -72,9 +73,14 @@ EXPECTED_FEATURES = ( class MockAyla(AylaApi): """Mocked AylaApi that doesn't do anything.""" + desired_expiry = False + async def async_sign_in(self): """Instead of signing in, just return.""" + async def async_refresh_auth(self): + """Instead of refreshing auth, just return.""" + async def async_sign_out(self): """Instead of signing out, just return.""" @@ -92,6 +98,18 @@ class MockAyla(AylaApi): async def async_request(self, http_method: str, url: str, **kwargs): """Don't make an HTTP request.""" + @property + def token_expiring_soon(self) -> bool: + """Toggling Property for Token Expiration Flag.""" + # Alternate expiry flag for each test + self.desired_expiry = not self.desired_expiry + return self.desired_expiry + + @property + def auth_expiration(self) -> datetime: + """Sample expiration timestamp that is always 1200 seconds behind now().""" + return datetime.now() - timedelta(seconds=1200) + class MockShark(SharkIqVacuum): """Mocked SharkIqVacuum that won't hit the API."""