From 4bf5f13233c2f2f5882159bc03e3f17970c5593a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20Gro=C3=9Fklo=C3=9F?= Date: Sun, 7 Dec 2025 15:41:03 +0100 Subject: [PATCH] Add signal handlers, retry logic, and improved boot script --- __pycache__/main.cpython-314.pyc | Bin 21515 -> 22855 bytes __pycache__/setup.cpython-314.pyc | Bin 0 -> 9828 bytes main.py | 76 +++++++++++++++++++----------- setup.py | 11 +++++ 4 files changed, 59 insertions(+), 28 deletions(-) create mode 100644 __pycache__/setup.cpython-314.pyc diff --git a/__pycache__/main.cpython-314.pyc b/__pycache__/main.cpython-314.pyc index 7a247823f21ea8a781bb77be43ea7b14c611e9fc..9c23aa84eb09d9df2ac22287a7a24f510a2255ed 100644 GIT binary patch delta 3659 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 literal 0 HcmV?d00001 diff --git a/main.py b/main.py index c1db5ad..605e8c0 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,7 @@ import logging import sys import time import re +import signal from datetime import datetime, timedelta from pathlib import Path @@ -92,6 +93,16 @@ class GadgetbridgeMQTT: self.mqtt_client = None self.last_publish_time = 0 self.last_db_mtime = 0 + self.running = True + + # Register signal handlers for graceful shutdown + signal.signal(signal.SIGTERM, self._signal_handler) + signal.signal(signal.SIGINT, self._signal_handler) + + def _signal_handler(self, signum, frame): + """Handle shutdown signals gracefully""" + logger.info(f"Received signal {signum}. Shutting down...") + self.running = False def connect_mqtt(self): """Connect to MQTT broker""" @@ -365,39 +376,47 @@ class GadgetbridgeMQTT: discovery_published = False try: - while True: + while self.running: current_time = time.time() # Check if it's time to trigger sync and publish if current_time - self.last_publish_time >= interval: - logger.info("Triggering Gadgetbridge sync...") - trigger_gadgetbridge_sync() - - # Wait for export to complete - time.sleep(10) - - # Find latest database - self.db_path = find_latest_db(export_dir) - - if self.db_path: - logger.info(f"Using database: {os.path.basename(self.db_path)}") + try: + logger.info("Triggering Gadgetbridge sync...") + trigger_gadgetbridge_sync() - # Publish discovery on first successful read - if not discovery_published: - # Need to read device name first - try: - conn = sqlite3.connect(self.db_path, timeout=5.0) - cursor = conn.cursor() - self.device_name = self.get_device_alias(cursor) - conn.close() - except: - pass - self.publish_discovery() - discovery_published = True + # Wait for export to complete + time.sleep(10) - self.process_database() - else: - logger.warning(f"No database found in {export_dir}") + # Find latest database with retry + self.db_path = find_latest_db(export_dir) + if not self.db_path: + logger.warning(f"No database found, retrying in 3s...") + time.sleep(3) + self.db_path = find_latest_db(export_dir) + + if self.db_path: + logger.info(f"Using database: {os.path.basename(self.db_path)}") + + # Publish discovery on first successful read + if not discovery_published: + # Need to read device name first + try: + conn = sqlite3.connect(self.db_path, timeout=5.0) + cursor = conn.cursor() + self.device_name = self.get_device_alias(cursor) + conn.close() + except: + pass + self.publish_discovery() + discovery_published = True + + self.process_database() + else: + logger.warning(f"No database found in {export_dir}") + + except Exception as e: + logger.error(f"Sync cycle failed: {e}") self.last_publish_time = current_time logger.info(f"Next publish in {interval}s...") @@ -405,8 +424,9 @@ class GadgetbridgeMQTT: time.sleep(10) # Check every 10 seconds except KeyboardInterrupt: - logger.info("Shutting down...") + logger.info("Interrupted by user") finally: + logger.info("Cleaning up...") self.disconnect_mqtt() diff --git a/setup.py b/setup.py index da0af22..75814ad 100644 --- a/setup.py +++ b/setup.py @@ -121,9 +121,20 @@ termux-wake-lock # Wait for system to fully boot sleep 30 +# Kill any existing process +pkill -f gadgetbridge_mqtt.py 2>/dev/null + # Start the MQTT publisher in background cd ~ python ~/scripts/gadgetbridge_mqtt.py >> ~/gb_mqtt.log 2>&1 & + +# Verify it started +sleep 2 +if pgrep -f gadgetbridge_mqtt.py > /dev/null; then + echo "$(date): Gadgetbridge MQTT started successfully" >> ~/gb_mqtt.log +else + echo "$(date): ERROR - Failed to start" >> ~/gb_mqtt.log +fi """ with open(boot_script, "w") as f: