#!/usr/bin/env python3 """ Tapo Steckdosen Diagnose-Tool ============================ Dieses Script hilft bei der Diagnose von Verbindungsproblemen mit Tapo-Steckdosen. Autor: Till Tomczak Datum: 2025-06-20 """ import sys import socket import subprocess import time import os from datetime import datetime # Farben für Terminal-Ausgabe class Colors: GREEN = '\033[92m' YELLOW = '\033[93m' RED = '\033[91m' BLUE = '\033[94m' ENDC = '\033[0m' BOLD = '\033[1m' def print_header(text): """Druckt eine formatierte Überschrift""" print(f"\n{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.ENDC}") print(f"{Colors.BOLD}{Colors.BLUE}{text:^60}{Colors.ENDC}") print(f"{Colors.BOLD}{Colors.BLUE}{'=' * 60}{Colors.ENDC}\n") def print_success(text): """Druckt eine Erfolgsmeldung""" print(f"{Colors.GREEN}✅ {text}{Colors.ENDC}") def print_warning(text): """Druckt eine Warnung""" print(f"{Colors.YELLOW}⚠️ {text}{Colors.ENDC}") def print_error(text): """Druckt eine Fehlermeldung""" print(f"{Colors.RED}❌ {text}{Colors.ENDC}") def print_info(text): """Druckt eine Info-Meldung""" print(f"{Colors.BLUE}ℹ️ {text}{Colors.ENDC}") def test_port_connection(ip, port, timeout=3): """ Testet die Verbindung zu einem bestimmten Port. Args: ip: IP-Adresse port: Port-Nummer timeout: Timeout in Sekunden Returns: bool: True wenn Verbindung möglich """ try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(timeout) result = sock.connect_ex((ip, port)) sock.close() return result == 0 except Exception as e: print_error(f"Socket-Fehler: {e}") return False def test_icmp_ping(ip): """ Führt einen ICMP Ping durch. Args: ip: IP-Adresse Returns: bool: True wenn Ping erfolgreich """ try: # Windows und Linux kompatibel param = '-n' if os.name == 'nt' else '-c' command = ['ping', param, '1', '-w', '2000', ip] result = subprocess.run(command, capture_output=True, text=True, timeout=5) return result.returncode == 0 except Exception as e: print_error(f"Ping-Fehler: {e}") return False def test_dns_resolution(hostname): """ Testet die DNS-Auflösung eines Hostnamens. Args: hostname: Hostname zum Auflösen Returns: str: Aufgelöste IP oder None """ try: ip = socket.gethostbyname(hostname) return ip except Exception as e: print_error(f"DNS-Auflösung fehlgeschlagen: {e}") return None def test_tapo_connection(ip, username="admin", password="admin"): """ Testet die Tapo-Verbindung. Args: ip: IP-Adresse der Steckdose username: Tapo-Benutzername password: Tapo-Passwort Returns: dict: Ergebnis der Tests """ results = { "timestamp": datetime.now().isoformat(), "ip": ip, "tests": {} } # Test 1: ICMP Ping print_info(f"Teste ICMP Ping zu {ip}...") ping_result = test_icmp_ping(ip) results["tests"]["icmp_ping"] = ping_result if ping_result: print_success(f"ICMP Ping zu {ip} erfolgreich") else: print_warning(f"ICMP Ping zu {ip} fehlgeschlagen (kann durch Firewall blockiert sein)") # Test 2: Port 80 (HTTP) print_info(f"Teste Port 80 (HTTP) auf {ip}...") port80_result = test_port_connection(ip, 80) results["tests"]["port_80"] = port80_result if port80_result: print_success(f"Port 80 auf {ip} ist erreichbar") else: print_error(f"Port 80 auf {ip} ist NICHT erreichbar") # Test 3: Port 9999 (Tapo-spezifisch) print_info(f"Teste Port 9999 (Tapo) auf {ip}...") port9999_result = test_port_connection(ip, 9999) results["tests"]["port_9999"] = port9999_result if port9999_result: print_success(f"Port 9999 auf {ip} ist erreichbar") else: print_warning(f"Port 9999 auf {ip} ist nicht erreichbar") # Test 4: PyP100 Verbindung try: print_info("Teste PyP100 Bibliothek...") from PyP100.PyP100 import P100 print_info(f"Versuche Tapo-Handshake mit {ip}...") p100 = P100(ip, username, password) # Handshake p100.handshake() print_success("Tapo-Handshake erfolgreich") results["tests"]["tapo_handshake"] = True # Login p100.login() print_success("Tapo-Login erfolgreich") results["tests"]["tapo_login"] = True # Device Info device_info = p100.getDeviceInfo() if device_info and 'error_code' in device_info and device_info['error_code'] == 0: print_success("Tapo-Geräteinformationen erfolgreich abgerufen") results["tests"]["tapo_device_info"] = True results["device_info"] = device_info.get('result', {}) # Status anzeigen device_on = device_info.get('result', {}).get('device_on', False) print_info(f"Steckdosen-Status: {'EIN' if device_on else 'AUS'}") else: print_error("Konnte Geräteinformationen nicht abrufen") results["tests"]["tapo_device_info"] = False except ImportError: print_error("PyP100 Bibliothek nicht installiert!") print_info("Installiere mit: pip install PyP100") results["tests"]["pyp100_available"] = False except Exception as e: print_error(f"Tapo-Verbindung fehlgeschlagen: {e}") results["tests"]["tapo_connection"] = False results["error"] = str(e) return results def diagnose_network(): """Führt eine allgemeine Netzwerk-Diagnose durch""" print_header("Netzwerk-Diagnose") # Lokale IP-Adresse ermitteln try: hostname = socket.gethostname() local_ip = socket.gethostbyname(hostname) print_info(f"Lokaler Hostname: {hostname}") print_info(f"Lokale IP-Adresse: {local_ip}") except Exception as e: print_error(f"Konnte lokale IP nicht ermitteln: {e}") # Gateway ermitteln (nur Linux/Unix) if os.name != 'nt': try: result = subprocess.run(['ip', 'route', 'show'], capture_output=True, text=True) if result.returncode == 0: lines = result.stdout.strip().split('\n') for line in lines: if 'default' in line: gateway = line.split()[2] print_info(f"Standard-Gateway: {gateway}") break except: pass # DNS-Test print_info("Teste DNS-Auflösung...") google_ip = test_dns_resolution("google.com") if google_ip: print_success(f"DNS funktioniert (google.com -> {google_ip})") else: print_error("DNS-Auflösung fehlgeschlagen") def main(): """Hauptfunktion""" print_header("Tapo Steckdosen Diagnose-Tool") print_info(f"Start: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") # Argumente prüfen if len(sys.argv) < 2: print_error("Verwendung: python diagnose_tapo.py [username] [password]") print_info("Beispiel: python diagnose_tapo.py 192.168.1.100") print_info("Beispiel: python diagnose_tapo.py 192.168.1.100 admin admin") sys.exit(1) ip_address = sys.argv[1] username = sys.argv[2] if len(sys.argv) > 2 else "admin" password = sys.argv[3] if len(sys.argv) > 3 else "admin" # Netzwerk-Diagnose diagnose_network() # Tapo-Diagnose print_header(f"Teste Tapo-Steckdose: {ip_address}") results = test_tapo_connection(ip_address, username, password) # Zusammenfassung print_header("Diagnose-Zusammenfassung") successful_tests = sum(1 for test, result in results["tests"].items() if result is True) total_tests = len(results["tests"]) print_info(f"Erfolgreiche Tests: {successful_tests}/{total_tests}") # Empfehlungen if not results["tests"].get("port_80", False): print_warning("\nEmpfehlungen:") print_warning("1. Stelle sicher, dass die Steckdose eingeschaltet ist") print_warning("2. Prüfe, ob die IP-Adresse korrekt ist") print_warning("3. Stelle sicher, dass sich die Steckdose im gleichen Netzwerk befindet") print_warning("4. Prüfe Firewall-Einstellungen") print_warning("5. Versuche die Steckdose zurückzusetzen (Reset-Knopf)") if results["tests"].get("port_80", False) and not results["tests"].get("tapo_login", False): print_warning("\nAuthentifizierungsproblem:") print_warning("1. Prüfe Benutzername und Passwort") print_warning("2. Standard-Credentials sind meist 'admin'/'admin'") print_warning("3. Wurden die Credentials in der Tapo-App geändert?") print_info(f"\nEnde: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") if __name__ == "__main__": main()