From e11b4564f04c1e87e2a49faeb9c2518dac5d3325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gro=C3=9Fklo=C3=9F?= Date: Fri, 26 Dec 2025 20:10:14 +0100 Subject: [PATCH] Track sleep state and adjust data freshness checks for improved recovery logic --- main.py | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/main.py b/main.py index 3bcec55..6799bdd 100644 --- a/main.py +++ b/main.py @@ -155,6 +155,7 @@ class GadgetbridgeMQTT: # New: Track data freshness for watchdog self.last_data_timestamp = 0 + self.is_sleeping = False # Track sleep state to skip stale checks during sleep # Register signal handlers for graceful shutdown signal.signal(signal.SIGTERM, self._signal_handler) @@ -404,7 +405,10 @@ class GadgetbridgeMQTT: row = cursor.fetchone() if row: data["heart_rate"] = row[0] - self.last_data_timestamp = row[1] # <--- NEW: Update timestamp + # Only update timestamp if DB has newer data than our last recovery + # This prevents the recovery loop when DB timestamp is stale + if row[1] > self.last_data_timestamp: + self.last_data_timestamp = row[1] except Exception as e: logger.debug(f"Heart rate query failed: {e}") @@ -496,6 +500,9 @@ class GadgetbridgeMQTT: resting_hr=resting_hr, ) data["is_awake"] = is_awake + + # Update sleep state for watchdog (use longer stale threshold during sleep) + self.is_sleeping = not is_awake stage_names = { 0: "not_sleep", @@ -518,10 +525,12 @@ class GadgetbridgeMQTT: data["sleep_stage"] = "not_sleep" if is_awake else "unknown" data["sleep_stage_code"] = 0 else: + # No sleep data - user is awake data["is_awake"] = True data["in_sleep_session"] = False data["sleep_stage"] = "not_sleep" data["sleep_stage_code"] = 0 + self.is_sleeping = False except Exception as e: logger.debug(f"Sleep query failed: {e}") @@ -598,9 +607,14 @@ class GadgetbridgeMQTT: # Use retain=True so HA gets values on restart self.mqtt_client.publish(topic, str(value), qos=1, retain=True) + # Log key metrics including sleep status + sleep_info = f"sleep={data.get('sleep_duration', 0)}h" if 'sleep_duration' in data else "sleep=N/A" + awake_info = f"awake={data.get('is_awake', 'N/A')}" + logger.info(f"Published: steps={data.get('daily_steps', 'N/A')}, " f"hr={data.get('heart_rate', 'N/A')}, " - f"battery={data.get('battery_level', 'N/A')}%") + f"battery={data.get('battery_level', 'N/A')}%, " + f"{sleep_info}, {awake_info}") def process_database(self): """Read database and publish data""" @@ -636,21 +650,27 @@ class GadgetbridgeMQTT: def check_and_recover_connection(self): """ WATCHDOG: Checks if data is stale (>20 mins) and forces Bluetooth restart if so. + + During sleep, the band syncs data less frequently, so we use a longer + threshold (60 mins) to avoid false recovery triggers. """ if self.last_data_timestamp == 0: - return # No data seen yet, skip check - + return # No data seen yet, skip check + + # Use longer threshold during sleep (band syncs less frequently) + threshold = STALE_THRESHOLD_SECONDS * 3 if self.is_sleeping else STALE_THRESHOLD_SECONDS + current_ts = int(time.time()) time_diff = current_ts - self.last_data_timestamp - if time_diff > STALE_THRESHOLD_SECONDS: - logger.warning(f"Data stale ({time_diff}s > {STALE_THRESHOLD_SECONDS}s). Triggering recovery...") + if time_diff > threshold: + logger.warning(f"Data stale ({time_diff}s > {threshold}s). Triggering recovery...") if self.device_mac: # 1. Disconnect and wait trigger_bluetooth_reconnect(self.device_mac) # 2. Reset timestamp so we don't loop immediately - self.last_data_timestamp = current_ts + self.last_data_timestamp = current_ts else: logger.warning("Cannot recover: No device MAC available")