From 1684f9f3ffd2e4e0e8dc2767a80f722153d3fb13 Mon Sep 17 00:00:00 2001 From: MarekWo Date: Mon, 23 Mar 2026 21:31:45 +0100 Subject: [PATCH] fix: disable buggy library auto-reconnect, handle reconnection ourselves meshcore 2.3.0's ConnectionManager has a bug: when auto-reconnect creates a new TCP connection, the old connection's connection_lost callback fires, triggering another reconnect cycle. Since each success resets the attempt counter, this loops forever (~1 TCP connection/second). Disabled library auto_reconnect and added reconnection logic to _on_disconnected() with 3 attempts and increasing backoff (5/10/15s). Co-Authored-By: Claude Opus 4.6 --- app/device_manager.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/app/device_manager.py b/app/device_manager.py index fa8d193..f024399 100644 --- a/app/device_manager.py +++ b/app/device_manager.py @@ -149,14 +149,19 @@ class DeviceManager: self.mc = await MeshCore.create_tcp( host=self.config.MC_TCP_HOST, port=self.config.MC_TCP_PORT, - auto_reconnect=self.config.MC_AUTO_RECONNECT, + # Disable library auto-reconnect — it has a bug where old + # connection's close callback triggers infinite reconnect loop. + # We handle reconnection ourselves in _on_disconnected(). + auto_reconnect=False, ) else: port = self._detect_serial_port() logger.info(f"Connecting via serial: {port}") self.mc = await MeshCore.create_serial( port=port, - auto_reconnect=self.config.MC_AUTO_RECONNECT, + # Disable library auto-reconnect — same bug as TCP. + # We handle reconnection ourselves in _on_disconnected(). + auto_reconnect=False, ) # Read device info @@ -953,7 +958,7 @@ class DeviceManager: logger.error(f"Error handling new contact: {e}") async def _on_disconnected(self, event): - """Handle device disconnection.""" + """Handle device disconnection with auto-reconnect.""" logger.warning("Device disconnected") self._connected = False @@ -962,6 +967,25 @@ class DeviceManager: 'connected': False, }, namespace='/chat') + # Auto-reconnect with backoff + for attempt in range(1, 4): + delay = 5 * attempt + logger.info(f"Reconnecting in {delay}s (attempt {attempt}/3)...") + await asyncio.sleep(delay) + try: + await self._connect() + if self._connected: + logger.info("Reconnected successfully") + if self.socketio: + self.socketio.emit('device_status', { + 'connected': True, + }, namespace='/chat') + return + except Exception as e: + logger.error(f"Reconnect attempt {attempt} failed: {e}") + + logger.error("Failed to reconnect after 3 attempts") + # ================================================================ # Command Methods (sync — called from Flask routes) # ================================================================