From 25e6fc1cee45f976069069481ce575dae0e87258 Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Tue, 24 Mar 2026 02:17:13 +0100
Subject: [PATCH] fix: use ping health check on resume instead of force-disconnect
---
lib/services/mqtt_service.dart | 42 +++++++++++++++++++++++++++---------------
1 files changed, 27 insertions(+), 15 deletions(-)
diff --git a/lib/services/mqtt_service.dart b/lib/services/mqtt_service.dart
index 35464de..4891638 100644
--- a/lib/services/mqtt_service.dart
+++ b/lib/services/mqtt_service.dart
@@ -515,22 +515,34 @@
switch (state) {
case AppLifecycleState.resumed:
if (_intentionalClose) break;
- // iOS kills the TCP socket during suspend. The MQTT client may still
- // think it's connected until the next ping timeout (30s+). Force a
- // fresh connection to avoid the "dead but looks alive" state.
- final client = _client;
- if (client != null && client.connectionStatus?.state == MqttConnectionState.connected) {
- // Verify the connection is actually alive by checking disconnect state
- // If auto-reconnect already fired, this is a no-op
- _mqttLog('MQTT: app resumed, verifying connection...');
- // Force disconnect + reconnect to get a clean state
- client.autoReconnect = false;
- client.disconnect();
- _client = null;
- _setStatus(ConnectionStatus.reconnecting);
- Future.delayed(const Duration(milliseconds: 500), () => connect());
- } else if (_status != ConnectionStatus.connected) {
+ _mqttLog('MQTT: app resumed, status=$_status');
+ if (_status != ConnectionStatus.connected) {
+ // Already knows it's disconnected — just reconnect
connect();
+ } else {
+ // Thinks it's connected — verify by sending a ping command.
+ // If the connection is dead, the publish will fail or we won't
+ // get a pong back. Set a watchdog timer.
+ _mqttLog('MQTT: sending health check...');
+ _publish('pailot/control/in', {
+ 'type': 'command',
+ 'command': 'ping',
+ 'msgId': DateTime.now().millisecondsSinceEpoch.toString(),
+ 'ts': DateTime.now().millisecondsSinceEpoch,
+ }, MqttQos.atLeastOnce);
+ // If no pong within 3s, force reconnect
+ Future.delayed(const Duration(seconds: 3), () {
+ if (_status == ConnectionStatus.connected) {
+ // Check if client is still actually connected
+ final client = _client;
+ if (client == null || client.connectionStatus?.state != MqttConnectionState.connected) {
+ _mqttLog('MQTT: health check failed, reconnecting...');
+ _client = null;
+ _setStatus(ConnectionStatus.reconnecting);
+ connect();
+ }
+ }
+ });
}
case AppLifecycleState.paused:
break;
--
Gitblit v1.3.1