From 666f362ebb93ce4a0a6759342d168f0f555615bf Mon Sep 17 00:00:00 2001 From: albaintor <118518828+albaintor@users.noreply.github.com> Date: Wed, 26 Nov 2025 20:37:31 +0100 Subject: [PATCH 1/2] Added connection retry when the network is unreachable --- src/tv.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/tv.py b/src/tv.py index 8d99c0e..6e292a8 100644 --- a/src/tv.py +++ b/src/tv.py @@ -57,6 +57,7 @@ _LOG = logging.getLogger(__name__) CONNECTION_TIMEOUT: float = 10.0 +ERROR_OS_WAIT: float = 0.5 """Android TV device connection timeout in seconds.""" BACKOFF_MAX: int = 30 """Maximum backoff duration in seconds.""" @@ -455,8 +456,19 @@ async def connect(self, max_timeout: int | None = None) -> bool: ) self.events.emit(Events.CONNECTING, self._identifier) request_start = time.time() - async with timeout(CONNECTION_TIMEOUT): - await self._atv.async_connect() + try: + async with timeout(CONNECTION_TIMEOUT): + await self._atv.async_connect() + except CannotConnect as ex: + if isinstance(ex.__cause__, OSError): + _LOG.warning( + "[%s] Network may not be ready yet %s : retry (%s)", self.log_id, self._identifier, ex + ) + await asyncio.sleep(ERROR_OS_WAIT) + async with timeout(CONNECTION_TIMEOUT): + await self._atv.async_connect() + else: + raise ex success = True self._connection_attempts = 0 self._reconnect_delay = MIN_RECONNECT_DELAY From a0b3e50a46c6abcb7344b74267ac8c1a00f9187f Mon Sep 17 00:00:00 2001 From: albaintor <118518828+albaintor@users.noreply.github.com> Date: Sat, 29 Nov 2025 09:38:57 +0100 Subject: [PATCH 2/2] Error code narrowed down to 101 Network unreachable --- src/tv.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tv.py b/src/tv.py index 6e292a8..0961c9a 100644 --- a/src/tv.py +++ b/src/tv.py @@ -15,7 +15,7 @@ from asyncio import AbstractEventLoop, Lock, timeout from enum import IntEnum from functools import wraps -from typing import Any, Awaitable, Callable, Concatenate, Coroutine, ParamSpec, TypeVar +from typing import Any, Awaitable, Callable, Concatenate, Coroutine, ParamSpec, TypeVar, cast import pychromecast import ucapi @@ -460,7 +460,8 @@ async def connect(self, max_timeout: int | None = None) -> bool: async with timeout(CONNECTION_TIMEOUT): await self._atv.async_connect() except CannotConnect as ex: - if isinstance(ex.__cause__, OSError): + # OSError(101, 'Network is unreachable') then wait ERROR_OS_WAIT and try again + if isinstance(ex.__cause__, OSError) and cast(OSError, ex).errno == 101: _LOG.warning( "[%s] Network may not be ready yet %s : retry (%s)", self.log_id, self._identifier, ex )