# Steckdosen-Startup-Initialisierung ## Übersicht Dieses Dokument beschreibt die implementierte Lösung für die automatische Initialisierung aller Tapo-Steckdosen beim Systemstart. Die Lösung stellt sicher, dass alle im Netzwerk erreichbaren Steckdosen beim Start des MYP-Systems in einen einheitlichen Zustand versetzt werden: **AUS = FREI**. ## Zielsetzung **Alle Steckdosen müssen via Scheduler zu Beginn in den selben Zustand versetzt werden (aus = frei), wenn sie im Netzwerk verfügbar / erreichbar sind.** ## Implementierung ### 1. Erweiterte Job Scheduler Klasse **Datei:** `utils/job_scheduler.py` Die `BackgroundTaskScheduler` Klasse wurde um eine neue Methode erweitert: ```python def initialize_all_outlets_on_startup(self) -> Dict[str, bool]: """ Initialisiert alle konfigurierten Steckdosen beim Systemstart. Schaltet alle im Netzwerk erreichbaren Tapo-Steckdosen aus, um einen einheitlichen Startzustand (aus = frei) zu gewährleisten. Returns: Dict[str, bool]: Ergebnis der Initialisierung pro Drucker """ ``` #### Funktionsweise: 1. **Einmalige Ausführung:** Flag `_outlets_initialized` verhindert mehrfache Initialisierung 2. **Datenbankabfrage:** Lädt alle aktiven Drucker mit Steckdosen-Konfiguration 3. **Netzwerk-Check:** Prüft Erreichbarkeit jeder Steckdose via Ping 4. **Status-Prüfung:** Ermittelt aktuellen Steckdosen-Status (an/aus) 5. **Intelligente Schaltung:** Schaltet nur die Steckdosen aus, die aktuell eingeschaltet sind 6. **Datenbank-Update:** Aktualisiert Drucker-Status in der Datenbank 7. **Umfassendes Logging:** Detaillierte Protokollierung aller Aktionen ### 2. Erweiterte Hardware-Integration **Datei:** `utils/hardware_integration.py` Die `DruckerSteuerung` Klasse wurde um folgende Methoden erweitert: ```python def ping_address(self, ip: str, timeout: int = 5) -> bool: """Prüft die Netzwerk-Erreichbarkeit einer IP-Adresse.""" def turn_off(self, ip: str, username: str = None, password: str = None, printer_id: int = None) -> bool: """Schaltet eine Tapo-Steckdose aus.""" def turn_on(self, ip: str, username: str = None, password: str = None, printer_id: int = None) -> bool: """Schaltet eine Tapo-Steckdose ein.""" ``` #### Funktionen: - **Netzwerk-Testing:** Socket-basierte Erreichbarkeitsprüfung - **Tapo-Steuerung:** Native PyP100/PyP110 Bibliothek-Integration - **Fehlerbehandlung:** Robuste Exception-Behandlung - **Simulation-Modus:** Fallback wenn Tapo-Bibliotheken nicht verfügbar ### 3. App-Startup-Integration **Datei:** `app.py` Die Steckdosen-Initialisierung wurde in den App-Startup-Prozess integriert. ## Ablauf beim Systemstart ### 1. System-Boot ``` [STARTUP] 🚀 Starte MYP System [STARTUP] Initialisiere Datenbank... [STARTUP] ✅ Datenbank initialisiert [STARTUP] Prüfe Initial-Admin... [STARTUP] ✅ Admin-Benutzer geprüft [STARTUP] Initialisiere statische Drucker... [STARTUP] ✅ Statische Drucker konfiguriert [STARTUP] Starte Queue Manager... [STARTUP] ✅ Queue Manager gestartet [STARTUP] Starte Job Scheduler... [STARTUP] ✅ Job Scheduler gestartet ``` ### 2. Steckdosen-Initialisierung ``` [STARTUP] Initialisiere Steckdosen (alle auf 'aus' = frei)... [scheduler] 🚀 Starte Steckdosen-Initialisierung beim Systemstart... [scheduler] 🔍 Prüfe 5 konfigurierte Steckdosen... [scheduler] 🔌 Verarbeite Drucker_1 (192.168.0.100)... [scheduler] 📡 192.168.0.100: ✅ erreichbar [scheduler] ✓ Drucker_1: Bereits ausgeschaltet - keine Aktion nötig [scheduler] 🔌 Verarbeite Drucker_2 (192.168.0.101)... [scheduler] 📡 192.168.0.101: ✅ erreichbar [scheduler] 🔄 Drucker_2: Schalte Steckdose von 'an' auf 'aus' um... [scheduler] ✅ Drucker_2: Erfolgreich ausgeschaltet ``` ### 3. Abschluss-Zusammenfassung ``` ============================================================ 🎯 STECKDOSEN-INITIALISIERUNG ABGESCHLOSSEN 📊 Gesamt: 5 Steckdosen ✅ Erfolgreich: 3 📡 Nicht erreichbar: 1 ❌ Fehlgeschlagen: 1 ⚡ 3/5 Steckdosen erfolgreich initialisiert ============================================================ [STARTUP] ⚡ 3/5 Steckdosen erfolgreich initialisiert ``` ## Technische Details ### Netzwerk-Erreichbarkeitsprüfung ```python def ping_address(self, ip: str, timeout: int = 5) -> bool: try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) result = sock.connect_ex((ip, 80)) sock.close() return (result == 0) except Exception as e: return False ``` - **Methode:** Socket-basierte Verbindungsprüfung auf Port 80 - **Timeout:** Standardmäßig 5 Sekunden (für Startup angepasst auf 3 Sekunden) - **Zuverlässigkeit:** Erkennt sowohl Netzwerk- als auch Geräteverfügbarkeit ### Tapo-Steckdosen-Steuerung ```python def turn_off(self, ip: str, username: str = None, password: str = None, printer_id: int = None) -> bool: try: p100 = PyP100(ip, self.tapo_username, self.tapo_password) p100.handshake() p100.login() p100.turnOff() return True except Exception as e: return False ``` - **Protokoll:** Native TP-Link Tapo P100/P110 API - **Authentifizierung:** Standard admin/admin Credentials - **Fehlerbehandlung:** Robuste Exception-Behandlung mit detailliertem Logging ## Fehlerbehandlung ### 1. Netzwerk-Fehler - **Nicht erreichbare Steckdosen** werden übersprungen - **Timeout-Schutz** verhindert hängende Operationen - **Detailliertes Logging** für Netzwerk-Diagnose ### 2. Hardware-Fehler - **Tapo-Verbindungsfehler** werden protokolliert aber nicht kritisch behandelt - **Simulation-Modus** wenn PyP100-Bibliothek nicht verfügbar - **Graceful Degradation** bei partiellen Fehlern ### 3. Datenbank-Fehler - **Rollback-Mechanismus** bei Datenbank-Fehlern - **Transaktionale Sicherheit** durch Context Manager - **Fehler-Recovery** ohne System-Crash ## Monitoring und Logging ### Log-Kategorien 1. **Debug-Level:** Detaillierte Netzwerk- und Hardware-Operationen 2. **Info-Level:** Erfolgreiche Aktionen und Zusammenfassungen 3. **Warning-Level:** Nicht-kritische Fehler (nicht erreichbare Geräte) 4. **Error-Level:** Kritische Fehler die Intervention erfordern ### Log-Dateien - **Scheduler-Log:** `logs/scheduler/scheduler.log` - **Hardware-Log:** `logs/hardware_integration/hardware_integration.log` - **App-Startup-Log:** `logs/startup/startup.log` ## Konfiguration ### Datenbank-Schema Die Initialisierung basiert auf der `Printer` Tabelle: ```sql SELECT * FROM printers WHERE active = 1 AND plug_ip IS NOT NULL; ``` **Erforderliche Felder:** - `id`: Drucker-ID - `name`: Drucker-Name - `plug_ip`: IP-Adresse der Tapo-Steckdose - `active`: Aktiv-Status (muss TRUE sein) ### Tapo-Credentials ```python # Standard-Zugangsdaten in hardware_integration.py self.tapo_username = "admin" self.tapo_password = "admin" ``` ## Sicherheit ### 1. Einmalige Ausführung - **Flag-basierte Kontrolle:** `_outlets_initialized` verhindert mehrfache Ausführung - **Race-Condition-Schutz:** Thread-sichere Implementierung ### 2. Netzwerk-Sicherheit - **Timeout-Schutz:** Verhindert hängende Verbindungen - **Local-Network-Only:** Funktioniert nur in lokalen Netzwerken - **Keine externe Kommunikation** ### 3. Fehler-Isolation - **Non-Critical-Errors:** Einzelne Fehler stoppen nicht das System - **Graceful-Degradation:** System funktioniert auch bei partiellen Fehlern --- **Implementiert von:** Till Tomczak - Mercedes-Benz TBA Marienfelde **Datum:** 2025-06-19 **Version:** 1.0.0