diff --git a/backend/app/database/myp.db-shm b/backend/app/database/myp.db-shm index 14d0afe6..d11765ba 100644 Binary files a/backend/app/database/myp.db-shm and b/backend/app/database/myp.db-shm differ diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index d3bce18e..f51b2ba6 100644 Binary files a/backend/app/database/myp.db-wal and b/backend/app/database/myp.db-wal differ diff --git a/backend/app/utils/printer_monitor.py b/backend/app/utils/printer_monitor.py index ea723f30..5c569749 100644 --- a/backend/app/utils/printer_monitor.py +++ b/backend/app/utils/printer_monitor.py @@ -497,6 +497,7 @@ class PrinterMonitor: def auto_discover_tapo_outlets(self) -> Dict[str, bool]: """ Automatische Erkennung und Konfiguration von TP-Link Tapo P110-Steckdosen im Netzwerk. + Robuste Version mit Timeout-Behandlung und Fehler-Resilience. Returns: Dict[str, bool]: Ergebnis der Steckdosenerkennung mit IP als Schlüssel @@ -507,39 +508,68 @@ class PrinterMonitor: monitor_logger.info("🔍 Starte automatische Tapo-Steckdosenerkennung...") results = {} + start_time = time.time() # 1. Zuerst die Standard-IPs aus der Konfiguration testen monitor_logger.info(f"🔄 Teste {len(DEFAULT_TAPO_IPS)} Standard-IPs aus der Konfiguration") - for ip in DEFAULT_TAPO_IPS: + for i, ip in enumerate(DEFAULT_TAPO_IPS): try: - # TCP-Verbindungstest für Grundkonnektivität - ping_success = self._ping_address(ip, timeout=3) + # Fortschrittsmeldung + monitor_logger.info(f"🔍 Teste IP {i+1}/{len(DEFAULT_TAPO_IPS)}: {ip}") + + # Reduzierte Timeouts für schnellere Erkennung + ping_success = self._ping_address(ip, timeout=2) if ping_success: monitor_logger.info(f"✅ Steckdose mit IP {ip} ist erreichbar") - # Tapo-Verbindung testen + # Tapo-Verbindung testen mit Timeout-Schutz if TAPO_AVAILABLE: try: - from PyP100 import PyP100 - p100 = PyP100.P100(ip, TAPO_USERNAME, TAPO_PASSWORD) - p100.handshake() - p100.login() - device_info = p100.getDeviceInfo() + # Timeout für Tapo-Verbindung + import signal - # Steckdose gefunden und verbunden - nickname = device_info.get('nickname', f"Tapo P110 ({ip})") - state = "on" if device_info.get('device_on', False) else "off" + def timeout_handler(signum, frame): + raise TimeoutError("Tapo-Verbindung Timeout") - monitor_logger.info(f"✅ Tapo-Steckdose '{nickname}' ({ip}) gefunden - Status: {state}") - results[ip] = True + # Nur unter Unix/Linux verfügbar + if hasattr(signal, 'SIGALRM'): + signal.signal(signal.SIGALRM, timeout_handler) + signal.alarm(5) # 5 Sekunden Timeout - # Steckdose in Datenbank speichern/aktualisieren - self._ensure_tapo_in_database(ip, nickname) - - except Exception as e: - monitor_logger.debug(f"❌ IP {ip} ist erreichbar, aber keine Tapo-Steckdose: {str(e)}") + try: + from PyP100 import PyP100 + p100 = PyP100.P100(ip, TAPO_USERNAME, TAPO_PASSWORD) + p100.handshake() + p100.login() + device_info = p100.getDeviceInfo() + + # Timeout zurücksetzen + if hasattr(signal, 'SIGALRM'): + signal.alarm(0) + + # Steckdose gefunden und verbunden + nickname = device_info.get('nickname', f"Tapo P110 ({ip})") + state = "on" if device_info.get('device_on', False) else "off" + + monitor_logger.info(f"✅ Tapo-Steckdose '{nickname}' ({ip}) gefunden - Status: {state}") + results[ip] = True + + # Steckdose in Datenbank speichern/aktualisieren (nicht-blockierend) + try: + self._ensure_tapo_in_database(ip, nickname) + except Exception as db_error: + monitor_logger.warning(f"⚠️ Fehler beim Speichern in DB für {ip}: {str(db_error)}") + + except (TimeoutError, Exception) as tapo_error: + if hasattr(signal, 'SIGALRM'): + signal.alarm(0) # Timeout zurücksetzen + monitor_logger.debug(f"❌ IP {ip} ist erreichbar, aber keine Tapo-Steckdose oder Timeout: {str(tapo_error)}") + results[ip] = False + + except Exception as outer_error: + monitor_logger.debug(f"❌ Fehler bei Tapo-Test für {ip}: {str(outer_error)}") results[ip] = False else: monitor_logger.warning("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Verbindung nicht testen") @@ -549,12 +579,16 @@ class PrinterMonitor: results[ip] = False except Exception as e: - monitor_logger.error(f"❌ Fehler bei Steckdosen-Erkennung für IP {ip}: {str(e)}") + monitor_logger.warning(f"❌ Fehler bei Steckdosen-Erkennung für IP {ip}: {str(e)}") results[ip] = False + # Weiter mit nächster IP - nicht abbrechen + continue # Erfolgsstatistik berechnen success_count = sum(1 for success in results.values() if success) - monitor_logger.info(f"✅ Steckdosen-Erkennung abgeschlossen: {success_count}/{len(results)} Steckdosen gefunden") + elapsed_time = time.time() - start_time + + monitor_logger.info(f"✅ Steckdosen-Erkennung abgeschlossen: {success_count}/{len(results)} Steckdosen gefunden in {elapsed_time:.1f}s") # Markieren, dass automatische Erkennung durchgeführt wurde self.auto_discovered_tapo = True