diff --git a/custom_components/alexa_media/__init__.py b/custom_components/alexa_media/__init__.py index e1979aea..a4662fab 100644 --- a/custom_components/alexa_media/__init__.py +++ b/custom_components/alexa_media/__init__.py @@ -251,6 +251,7 @@ async def async_update_data(): email not in hass.data[DATA_ALEXAMEDIA]["accounts"] or "login_successful" not in login_obj.status or login_obj.session.closed + or login_obj.close_requested ): return existing_serials = _existing_serials(hass, login_obj) @@ -804,6 +805,11 @@ async def ws_close_handler(): import time email: Text = login_obj.email + if login_obj.close_requested: + _LOGGER.debug( + "%s: Close requested; will not reconnect websocket", hide_email(email) + ) + return errors: int = (hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocketerror"]) delay: int = 5 * 2 ** errors last_attempt = hass.data[DATA_ALEXAMEDIA]["accounts"][email][ @@ -839,7 +845,7 @@ async def ws_close_handler(): hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocket"] = None coordinator = hass.data[DATA_ALEXAMEDIA]["accounts"][email].get("coordinator") if coordinator: - coordinator.update_interval = scan_interval + coordinator.update_interval = timedelta(seconds=scan_interval) await coordinator.async_request_refresh() async def ws_error_handler(message): @@ -859,7 +865,9 @@ async def ws_error_handler(message): type(message), ) hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocket"] = None - if login_obj.session.closed or message == "": + if not login_obj.close_requested and ( + login_obj.session.closed or message == "" + ): hass.data[DATA_ALEXAMEDIA]["accounts"][email]["websocketerror"] = 5 _LOGGER.debug("%s: Immediate abort on EoFstream", hide_email(email)) return @@ -947,7 +955,6 @@ async def close_connections(hass, email: Text) -> None: _LOGGER.debug( "%s: Connection closed: %s", hide_email(email), login_obj.session.closed ) - await clear_configurator(hass, email) async def update_listener(hass, config_entry): diff --git a/custom_components/alexa_media/const.py b/custom_components/alexa_media/const.py index 19375722..7f49a21d 100644 --- a/custom_components/alexa_media/const.py +++ b/custom_components/alexa_media/const.py @@ -34,6 +34,8 @@ DATA_LISTENER = "listener" +EXCEPTION_TEMPLATE = "An exception of type {0} occurred. Arguments:\n{1!r}" + DEFAULT_QUEUE_DELAY = 1.5 SERVICE_CLEAR_HISTORY = "clear_history" SERVICE_UPDATE_LAST_CALLED = "update_last_called" diff --git a/custom_components/alexa_media/helpers.py b/custom_components/alexa_media/helpers.py index 583a1638..9207178a 100644 --- a/custom_components/alexa_media/helpers.py +++ b/custom_components/alexa_media/helpers.py @@ -9,13 +9,14 @@ """ import logging -from typing import Any, Callable, List, Text +from typing import Any, Callable, List, Optional, Text -from alexapy import AlexapyLoginError, hide_email +from alexapy import AlexapyLoginCloseRequested, AlexapyLoginError, hide_email from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_component import EntityComponent from . import DATA_ALEXAMEDIA +from .const import EXCEPTION_TEMPLATE _LOGGER = logging.getLogger(__name__) @@ -24,8 +25,8 @@ async def add_devices( account: Text, devices: List[EntityComponent], add_devices_callback: Callable, - include_filter: List[Text] = None, - exclude_filter: List[Text] = None, + include_filter: Optional[List[Text]] = None, + exclude_filter: Optional[List[Text]] = None, ) -> bool: """Add devices using add_devices_callback.""" include_filter = [] or include_filter @@ -55,10 +56,12 @@ async def add_devices( _LOGGER.debug( "%s: Unable to add devices: %s : %s", account, devices, message ) - except BaseException as ex: - template = "An exception of type {0} occurred." " Arguments:\n{1!r}" - message = template.format(type(ex).__name__, ex.args) - _LOGGER.debug("%s: Unable to add devices: %s", account, message) + except BaseException as ex: # pylint: disable=broad-except + _LOGGER.debug( + "%s: Unable to add devices: %s", + account, + EXCEPTION_TEMPLATE.format(type(ex).__name__, ex.args), + ) else: return True return False @@ -114,13 +117,11 @@ async def wrapper(*args, **kwargs) -> Any: except Exception as ex: # pylint: disable=broad-except if not catch_exceptions: raise - template = "An exception of type {0} occurred." " Arguments:\n{1!r}" - message = template.format(type(ex).__name__, ex.args) _LOGGER.debug( "%s.%s: failure caught due to exception: %s", func.__module__[func.__module__.find(".") + 1 :], func.__name__, - message, + EXCEPTION_TEMPLATE.format(type(ex).__name__, ex.args), ) _LOGGER.debug( "%s.%s: Try: %s/%s after waiting %s seconds result: %s", @@ -145,18 +146,24 @@ def _catch_login_errors(func) -> Callable: @functools.wraps(func) async def wrapper(*args, **kwargs) -> Any: instance = args[0] + result = None if hasattr(instance, "check_login_changes"): instance.check_login_changes() try: result = await func(*args, **kwargs) - except AlexapyLoginError as ex: # pylint: disable=broad-except - template = "An exception of type {0} occurred." " Arguments:\n{1!r}" - message = template.format(type(ex).__name__, ex.args) + except AlexapyLoginCloseRequested: + _LOGGER.debug( + "%s.%s: Ignoring attempt to access Alexa after HA shutdown", + func.__module__[func.__module__.find(".") + 1 :], + func.__name__, + ) + return None + except AlexapyLoginError as ex: _LOGGER.debug( "%s.%s: detected bad login: %s", func.__module__[func.__module__.find(".") + 1 :], func.__name__, - message, + EXCEPTION_TEMPLATE.format(type(ex).__name__, ex.args), ) instance = args[0] if hasattr(instance, "_login"): diff --git a/custom_components/alexa_media/manifest.json b/custom_components/alexa_media/manifest.json index 12f49295..ca74dd55 100644 --- a/custom_components/alexa_media/manifest.json +++ b/custom_components/alexa_media/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://github.com/custom-components/alexa_media_player/wiki", "dependencies": ["configurator"], "codeowners": ["@keatontaylor", "@alandtse"], - "requirements": ["alexapy==1.10.7"] + "requirements": ["alexapy==1.10.8"] }