-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[bug] Android looses connection and won't reconnect #40
Comments
I'll try to figure out a fix : inside your wrapper I will add a reconnect task. It seems that the right way to reconnect is to call init() ? |
Please wait with changing the logic. There's already an automatic reconnect task in the androidtvremote2 library, plus the additional connection reset workaround in the wrapper. Also the connection is re-established after the Remote Two wakes up from standby.
I also require a bit more information:
|
Hi, I think I found the culprit : from the logs I can see a bug in the ucapi library (line number 755): async def _broadcast_ws_event(
self, msg: str, msg_data: dict[str, Any], category: uc.EventCategory
) -> None:
...
for websocket in self._clients:
... Should be replaced with : for websocket in self._clients.copy() because the list can change (a client may disconnect and reconnect while iterating) After that I had to relaunch the driver as you can see in the logs because I had the red banner error message at each press EDIT : here is the corresponding logs on the remote side, although it won't be helpful I think. There is -1 hour in those logs compared to the driver timestamps. So driver error at 18:50 -> remote error at 17:46 |
I have patched the method from the driver, we'll see if this is the only rootcause : async def patched_broadcast_ws_event(
self, msg: str, msg_data: dict[str, Any], category: uc.EventCategory
) -> None:
...
for websocket in self._clients.copy():
if _LOG.isEnabledFor(logging.DEBUG):
_LOG.debug("[%s] ->: %s", websocket.remote_address, data_log)
try:
await websocket.send(data_dump)
except websockets.exceptions.WebSocketException:
pass
async def main():
...
IntegrationAPI._broadcast_ws_event = patched_broadcast_ws_event
await api.init("driver.json", setup_flow.driver_setup_handler)
# Patched method |
Hi, I have made another test this time with the driver from the remote and I still have the problem.
The driver is in a dead state since a while and it seems to come from this event : or previous ones : During that time I think that the remote had general connection issues (multiple error messages : no connection to the docks, appletv...). Except that the other drivers recovered their connections, although I didn't see any disconnection event from wifi TO RESOLVE THE PROBLEM : I had to reboot the remote and it worked again. |
I checked after the logic, not sure about my analysis : the problem seems to occur when the remote itself has connections issues (wifi lost at line 4467 at 19:06:45 and then connection seems unstable) and takes some time to get connection back. This is another problem why there is this instability. Error raised from remote.py:208 async def _async_idle_disconnect(self) -> None:
await asyncio.sleep(16)
LOGGER.debug("Closing idle connection")
if self.transport and not self.transport.is_closing():
self.transport.close()
if not self.on_con_lost.done():
self.on_con_lost.set_result(Exception("Closed idle connection")) Which is caught by async_connect in androidtv_remote.py:228: async def async_connect(self) -> None:
...
if on_con_lost.done():
con_lost_exc = on_con_lost.result()
LOGGER.debug(
"Couldn't connect to %s:%s. Error: %s",
self.host,
self._api_port,
con_lost_exc,
)
if isinstance(con_lost_exc, ssl.SSLError):
raise InvalidAuth("Need to pair again") from con_lost_exc
raise ConnectionClosed("Connection closed") from con_lost_exc Something is wrong or that I don't understand : the on_con_lost callback is local in the async_connect method within androidtv_remote.py : so it is only caught during connection, not after. Why isn't it a global callback that triggers a reconnect call ? This would explain why the following exception is not handled : |
I think I nailed it: the raise ConnectionClosed("Connection closed") from async_connect is not caught by _async_reconnect task. So the task will crash async def _async_reconnect(
self, invalid_auth_callback: Callable | None = None
) -> None:
while self._remote_message_protocol:
exc = await self._remote_message_protocol.on_con_lost
self._on_is_available_updated(False)
LOGGER.debug("Disconnected from %s. Error: %s", self.host, exc)
delay_seconds = 0.1
LOGGER.debug(
"Trying to reconnect to %s in %s seconds", self.host, delay_seconds
)
while self._remote_message_protocol:
await asyncio.sleep(delay_seconds)
try:
await self.async_connect()
self._on_is_available_updated(True)
break
except (CannotConnect, ConnectionClosed) as exc:
delay_seconds = min(2 * delay_seconds, 30)
LOGGER.debug(
"Couldn't reconnect to %s. Will retry in %s seconds. Error: %s",
self.host,
delay_seconds,
exc,
)
except InvalidAuth as exc:
LOGGER.debug(
"Couldn't reconnect to %s. Won't retry. Error: %s",
self.host,
exc,
)
if invalid_auth_callback:
invalid_auth_callback()
return |
I made a local copy of the androidtvremote2 library and made the change, will see if it resolves the issue Anyway the same consequence : "androidtvremote2:Connection lost. Error: None" line 732 This is not exactly the same chain of errors but maybe the same cause : the "Trying to reconnect " doesn't seem to be executed and then no more reconnection attempts.. so I guess that the reconnection task crashed |
Thanks for the logs and futher analysis. I'll look into it this week. Just saw the following while quickly glancing over the logs:
I'll fix this in the integration wrapper. This can only happen when running it as an external integration. On the Remote itself it's a single connection with the core service only and never disconnects (unless there's something seriously wrong). |
Hi Markus, indeed the second issue should occur only on external integrations About the main problem, there may be some tuning around timeout, but this is not the only cause as in the previous logs the reconnection will never occur. I may be wrong but I think that adding the ConnectionClosed in the try/catch in _async_reconnect would resolve the problem. |
Hi again, I had the same issue again new logs here : And the same exception : |
Hi, following mails exchange with Marton, this problem is confirmed to be a side effect of disconnections due to wifi dropouts (due to AP handoff not handled correctly) : my setup is a wifi mesh (tplink) which is incompatible with the remote two. I had to setup a third party wifi router (not mesh) and now I don't have any disconnections and the problem didn't occur again. |
Hi @zehnm , I submitted a PR to androidtvremote2 project : tronikos/androidtvremote2#21 |
Hi again, the PR has been merged and a new release is available : can you update the androidtv integration with this new release : https://github.com/tronikos/androidtvremote2/releases/tag/v0.0.15 Thank you |
Description
Following the last updates, it addressed the commands not handled when the transport stream is down.
However I still have disconnections issues which are not handled automatically : I mean that the driver won't try to reconnect by itself
When this happens, this message is raised :
2024/04/07 18:49:44,stdout,ERROR:tv:[SHIELD Salon] Cannot send command: Disconnected from device
In the code there should be a reconnection task when this occurs : an exception ucapi.StatusCodes.SERVICE_UNAVAILABLE is raised instead.
How to Reproduce
Expected behavior
Automatic reconnection
Integration version
No response
Additional context
No response
The text was updated successfully, but these errors were encountered: