🔧 Aktualisierung der Tapo-Steckdosen-Integration: Umstellung auf zentralen tapo_controller für Statusprüfungen und Verbindungs-Tests. Verbesserung der Fehlerbehandlung und Protokollierung. Anpassungen in der Dokumentation und Umbenennung von Funktionen zur besseren Lesbarkeit. 🛠️

This commit is contained in:
2025-06-05 11:13:43 +02:00
parent 502d63bc20
commit 0a1b24c4ef
27 changed files with 320 additions and 196 deletions

View File

@@ -1,6 +1,6 @@
"""
TP-Link Tapo P110 Zentraler Controller für MYP Platform
Sammelt alle operativen Tapo-Steckdosen-Funktionalitäten an einem Ort.
tp-link tapo p110 zentraler controller für myp platform
sammelt alle operativen tapo-steckdosen-funktionalitäten an einem ort.
"""
import time
@@ -15,24 +15,24 @@ from models import get_db_session, Printer, PlugStatusLog
from utils.logging_config import get_logger
from utils.settings import TAPO_USERNAME, TAPO_PASSWORD, DEFAULT_TAPO_IPS, TAPO_TIMEOUT, TAPO_RETRY_COUNT
# TP-Link Tapo P110 Unterstützung prüfen
# tp-link tapo p110 unterstützung prüfen
try:
from PyP100 import PyP100
TAPO_AVAILABLE = True
except ImportError:
TAPO_AVAILABLE = False
# Logger initialisieren
# logger initialisieren
logger = get_logger("tapo_controller")
class TapoController:
"""
Zentraler Controller für alle TP-Link Tapo P110 Operationen.
zentraler controller für alle tp-link tapo p110 operationen.
"""
def __init__(self):
"""Initialisiere den Tapo Controller."""
"""initialisiere den tapo controller."""
self.username = TAPO_USERNAME
self.password = TAPO_PASSWORD
self.timeout = TAPO_TIMEOUT
@@ -40,107 +40,107 @@ class TapoController:
self.auto_discovered = False
if not TAPO_AVAILABLE:
logger.error("❌ PyP100-Modul nicht installiert - Tapo-Funktionalität eingeschränkt")
logger.error("❌ PyP100-modul nicht installiert - tapo-funktionalität eingeschränkt")
else:
logger.info("Tapo Controller initialisiert")
logger.info("tapo controller initialisiert")
def toggle_plug(self, ip: str, state: bool, username: str = None, password: str = None) -> bool:
"""
Schaltet eine TP-Link Tapo P100/P110-Steckdose ein oder aus.
schaltet eine tp-link tapo p100/p110-steckdose ein oder aus.
Args:
ip: IP-Adresse der Steckdose
state: True = Ein, False = Aus
username: Benutzername (optional, nutzt Standard wenn nicht angegeben)
password: Passwort (optional, nutzt Standard wenn nicht angegeben)
args:
ip: ip-adresse der steckdose
state: true = ein, false = aus
username: benutzername (optional, nutzt standard wenn nicht angegeben)
password: passwort (optional, nutzt standard wenn nicht angegeben)
Returns:
bool: True wenn erfolgreich geschaltet
returns:
bool: true wenn erfolgreich geschaltet
"""
if not TAPO_AVAILABLE:
logger.error("❌ PyP100-Modul nicht installiert - Steckdose kann nicht geschaltet werden")
logger.error("❌ PyP100-modul nicht installiert - steckdose kann nicht geschaltet werden")
return False
# IMMER globale Anmeldedaten verwenden
# immer globale anmeldedaten verwenden
username = self.username
password = self.password
logger.debug(f"🔧 Verwende globale Tapo-Anmeldedaten für {ip}")
logger.debug(f"🔧 verwende globale tapo-anmeldedaten für {ip}")
for attempt in range(self.retry_count):
try:
# P100-Verbindung herstellen
# p100-verbindung herstellen
p100 = PyP100.P100(ip, username, password)
p100.handshake()
p100.login()
# Steckdose schalten
# steckdose schalten
if state:
p100.turnOn()
logger.info(f"Tapo-Steckdose {ip} erfolgreich eingeschaltet")
logger.info(f"tapo-steckdose {ip} erfolgreich eingeschaltet")
else:
p100.turnOff()
logger.info(f"Tapo-Steckdose {ip} erfolgreich ausgeschaltet")
logger.info(f"tapo-steckdose {ip} erfolgreich ausgeschaltet")
return True
except Exception as e:
action = "ein" if state else "aus"
logger.warning(f"⚠️ Versuch {attempt+1}/{self.retry_count} fehlgeschlagen beim {action}schalten von {ip}: {str(e)}")
logger.warning(f"⚠️ versuch {attempt+1}/{self.retry_count} fehlgeschlagen beim {action}schalten von {ip}: {str(e)}")
if attempt < self.retry_count - 1:
time.sleep(1) # Kurze Pause vor erneutem Versuch
time.sleep(1) # kurze pause vor erneutem versuch
else:
logger.error(f"Fehler beim {action}schalten der Tapo-Steckdose {ip}: {str(e)}")
logger.error(f"fehler beim {action}schalten der tapo-steckdose {ip}: {str(e)}")
return False
def turn_off(self, ip: str, username: str = None, password: str = None, printer_id: int = None) -> bool:
"""
Schaltet eine TP-Link Tapo P110-Steckdose aus.
schaltet eine tp-link tapo p110-steckdose aus.
Args:
ip: IP-Adresse der Steckdose
username: Benutzername (optional)
password: Passwort (optional)
printer_id: ID des zugehörigen Druckers für Logging (optional)
args:
ip: ip-adresse der steckdose
username: benutzername (optional)
password: passwort (optional)
printer_id: id des zugehörigen druckers für logging (optional)
Returns:
bool: True wenn erfolgreich ausgeschaltet
returns:
bool: true wenn erfolgreich ausgeschaltet
"""
if not TAPO_AVAILABLE:
logger.error("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdose nicht schalten")
self._log_plug_status(printer_id, "disconnected", ip, error_message="PyP100-Modul nicht verfügbar")
logger.error("⚠️ PyP100-modul nicht verfügbar - kann tapo-steckdose nicht schalten")
self._log_plug_status(printer_id, "disconnected", ip, error_message="PyP100-modul nicht verfügbar")
return False
# IMMER globale Anmeldedaten verwenden
# immer globale anmeldedaten verwenden
username = self.username
password = self.password
start_time = time.time()
try:
# TP-Link Tapo P100 Verbindung herstellen
# tp-link tapo p100 verbindung herstellen
p100 = PyP100.P100(ip, username, password)
p100.handshake()
p100.login()
# Steckdose ausschalten
# steckdose ausschalten
p100.turnOff()
response_time = int((time.time() - start_time) * 1000) # in Millisekunden
logger.debug(f"Tapo-Steckdose {ip} erfolgreich ausgeschaltet")
response_time = int((time.time() - start_time) * 1000) # in millisekunden
logger.debug(f"tapo-steckdose {ip} erfolgreich ausgeschaltet")
# Logging: Erfolgreich ausgeschaltet
# logging: erfolgreich ausgeschaltet
self._log_plug_status(printer_id, "off", ip, response_time_ms=response_time)
return True
except Exception as e:
response_time = int((time.time() - start_time) * 1000)
logger.debug(f"⚠️ Fehler beim Ausschalten der Tapo-Steckdose {ip}: {str(e)}")
logger.debug(f"⚠️ fehler beim ausschalten der tapo-steckdose {ip}: {str(e)}")
# Logging: Fehlgeschlagener Versuch
# logging: fehlgeschlagener versuch
self._log_plug_status(printer_id, "disconnected", ip,
response_time_ms=response_time,
error_message=str(e))
@@ -150,83 +150,83 @@ class TapoController:
def check_outlet_status(self, ip: str, username: str = None, password: str = None,
printer_id: int = None) -> Tuple[bool, str]:
"""
Überprüft den Status einer TP-Link Tapo P110-Steckdose.
überprüft den status einer tp-link tapo p110-steckdose.
Args:
ip: IP-Adresse der Steckdose
username: Benutzername (optional)
password: Passwort (optional)
printer_id: ID des zugehörigen Druckers für Logging (optional)
args:
ip: ip-adresse der steckdose
username: benutzername (optional)
password: passwort (optional)
printer_id: id des zugehörigen druckers für logging (optional)
Returns:
Tuple[bool, str]: (Erreichbar, Status) - Status: "on", "off", "unknown"
returns:
tuple[bool, str]: (erreichbar, status) - status: "on", "off", "unknown"
"""
if not TAPO_AVAILABLE:
logger.debug("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdosen-Status nicht abfragen")
logger.debug("⚠️ PyP100-modul nicht verfügbar - kann tapo-steckdosen-status nicht abfragen")
self._log_plug_status(printer_id, "disconnected", ip,
error_message="PyP100-Modul nicht verfügbar",
notes="Status-Check fehlgeschlagen")
error_message="PyP100-modul nicht verfügbar",
notes="status-check fehlgeschlagen")
return False, "unknown"
# IMMER globale Anmeldedaten verwenden
# immer globale anmeldedaten verwenden
username = self.username
password = self.password
start_time = time.time()
try:
# TP-Link Tapo P100 Verbindung herstellen
# tp-link tapo p100 verbindung herstellen
p100 = PyP100.P100(ip, username, password)
p100.handshake()
p100.login()
# Geräteinformationen abrufen
# geräteinformationen abrufen
device_info = p100.getDeviceInfo()
# Status auswerten
# status auswerten
device_on = device_info.get('device_on', False)
status = "on" if device_on else "off"
response_time = int((time.time() - start_time) * 1000)
logger.debug(f"Tapo-Steckdose {ip}: Status = {status}")
logger.debug(f"tapo-steckdose {ip}: status = {status}")
# Erweiterte Informationen sammeln
# erweiterte informationen sammeln
extra_info = self._collect_device_info(p100, device_info)
# Logging: Erfolgreicher Status-Check
# logging: erfolgreicher status-check
self._log_plug_status(printer_id, status, ip,
response_time_ms=response_time,
power_consumption=extra_info.get('power_consumption'),
voltage=extra_info.get('voltage'),
current=extra_info.get('current'),
firmware_version=extra_info.get('firmware_version'),
notes="Automatischer Status-Check")
notes="automatischer status-check")
return True, status
except Exception as e:
response_time = int((time.time() - start_time) * 1000)
logger.debug(f"⚠️ Fehler bei Tapo-Steckdosen-Status-Check {ip}: {str(e)}")
logger.debug(f"⚠️ fehler bei tapo-steckdosen-status-check {ip}: {str(e)}")
# Logging: Fehlgeschlagener Status-Check
# logging: fehlgeschlagener status-check
self._log_plug_status(printer_id, "disconnected", ip,
response_time_ms=response_time,
error_message=str(e),
notes="Status-Check fehlgeschlagen")
notes="status-check fehlgeschlagen")
return False, "unknown"
def test_connection(self, ip: str, username: str = None, password: str = None) -> dict:
"""
Testet die Verbindung zu einer TP-Link Tapo P110-Steckdose.
testet die verbindung zu einer tp-link tapo p110-steckdose.
Args:
ip: IP-Adresse der Steckdose
username: Benutzername (optional)
password: Passwort (optional)
args:
ip: ip-adresse der steckdose
username: benutzername (optional)
password: passwort (optional)
Returns:
dict: Ergebnis mit Status und Informationen
returns:
dict: ergebnis mit status und informationen
"""
result = {
"success": False,
@@ -236,58 +236,58 @@ class TapoController:
}
if not TAPO_AVAILABLE:
result["message"] = "PyP100-Modul nicht verfügbar"
result["message"] = "PyP100-modul nicht verfügbar"
result["error"] = "ModuleNotFound"
logger.error("PyP100-Modul nicht verfügbar - kann Tapo-Steckdosen nicht testen")
logger.error("PyP100-modul nicht verfügbar - kann tapo-steckdosen nicht testen")
return result
# Verwende globale Anmeldedaten falls nicht angegeben
# verwende globale anmeldedaten falls nicht angegeben
if not username or not password:
username = self.username
password = self.password
logger.debug(f"Verwende globale Tapo-Anmeldedaten für {ip}")
logger.debug(f"verwende globale tapo-anmeldedaten für {ip}")
try:
# TP-Link Tapo P100 Verbindung herstellen
# tp-link tapo p100 verbindung herstellen
p100 = PyP100.P100(ip, username, password)
p100.handshake()
p100.login()
# Geräteinformationen abrufen
# geräteinformationen abrufen
device_info = p100.getDeviceInfo()
result["success"] = True
result["message"] = "Verbindung erfolgreich"
result["message"] = "verbindung erfolgreich"
result["device_info"] = device_info
logger.info(f"Tapo-Verbindung zu {ip} erfolgreich: {device_info.get('nickname', 'Unbekannt')}")
logger.info(f"tapo-verbindung zu {ip} erfolgreich: {device_info.get('nickname', 'unbekannt')}")
except Exception as e:
result["success"] = False
result["message"] = f"Verbindungsfehler: {str(e)}"
result["message"] = f"verbindungsfehler: {str(e)}"
result["error"] = str(e)
logger.error(f"Fehler bei Tapo-Test zu {ip}: {str(e)}")
logger.error(f"fehler bei tapo-test zu {ip}: {str(e)}")
return result
def ping_address(self, ip: str, timeout: int = 3) -> bool:
"""
Führt einen Konnektivitätstest zu einer IP-Adresse durch.
Verwendet TCP-Verbindung statt Ping für bessere Kompatibilität.
führt einen konnektivitätstest zu einer ip-adresse durch.
verwendet tcp-verbindung statt ping für bessere kompatibilität.
Args:
ip: Zu testende IP-Adresse
timeout: Timeout in Sekunden
args:
ip: zu testende ip-adresse
timeout: timeout in sekunden
Returns:
bool: True wenn Verbindung erfolgreich
returns:
bool: true wenn verbindung erfolgreich
"""
try:
# IP-Adresse validieren
# ip-adresse validieren
ipaddress.ip_address(ip.strip())
# Standard-Ports für Tapo-Steckdosen testen
test_ports = [9999, 80, 443] # Tapo-Standard, HTTP, HTTPS
# standard-ports für tapo-steckdosen testen
test_ports = [9999, 80, 443] # tapo-standard, http, https
for port in test_ports:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@@ -296,87 +296,87 @@ class TapoController:
sock.close()
if result == 0:
logger.debug(f"Verbindung zu {ip}:{port} erfolgreich")
logger.debug(f"verbindung zu {ip}:{port} erfolgreich")
return True
logger.debug(f"Keine Verbindung zu {ip} auf Standard-Ports möglich")
logger.debug(f"keine verbindung zu {ip} auf standard-ports möglich")
return False
except Exception as e:
logger.debug(f"Fehler beim Verbindungstest zu {ip}: {str(e)}")
logger.debug(f"fehler beim verbindungstest zu {ip}: {str(e)}")
return False
def auto_discover_outlets(self) -> Dict[str, bool]:
"""
Automatische Erkennung und Konfiguration von TP-Link Tapo P110-Steckdosen im Netzwerk.
automatische erkennung und konfiguration von tp-link tapo p110-steckdosen im netzwerk.
Returns:
Dict[str, bool]: Ergebnis der Steckdosenerkennung mit IP als Schlüssel
returns:
dict[str, bool]: ergebnis der steckdosenerkennung mit ip als schlüssel
"""
if self.auto_discovered:
logger.info("🔍 Tapo-Steckdosen wurden bereits erkannt")
logger.info("🔍 tapo-steckdosen wurden bereits erkannt")
return {}
logger.info("🔍 Starte automatische Tapo-Steckdosenerkennung...")
logger.info("🔍 starte automatische tapo-steckdosenerkennung...")
results = {}
start_time = time.time()
# Standard-IPs aus der Konfiguration testen
logger.info(f"🔄 Teste {len(DEFAULT_TAPO_IPS)} Standard-IPs aus der Konfiguration")
# standard-ips aus der konfiguration testen
logger.info(f"🔄 teste {len(DEFAULT_TAPO_IPS)} standard-ips aus der konfiguration")
for i, ip in enumerate(DEFAULT_TAPO_IPS):
try:
logger.info(f"🔍 Teste IP {i+1}/{len(DEFAULT_TAPO_IPS)}: {ip}")
logger.info(f"🔍 teste ip {i+1}/{len(DEFAULT_TAPO_IPS)}: {ip}")
# Schneller Ping-Test
# schneller ping-test
if self.ping_address(ip, timeout=2):
logger.info(f"Steckdose mit IP {ip} ist erreichbar")
logger.info(f"steckdose mit ip {ip} ist erreichbar")
# Tapo-Verbindung testen
# tapo-verbindung testen
test_result = self.test_connection(ip)
if test_result["success"]:
device_info = test_result["device_info"]
nickname = device_info.get('nickname', f"Tapo P110 ({ip})")
nickname = device_info.get('nickname', f"tapo p110 ({ip})")
state = "on" if device_info.get('device_on', False) else "off"
logger.info(f"Tapo-Steckdose '{nickname}' ({ip}) gefunden - Status: {state}")
logger.info(f"tapo-steckdose '{nickname}' ({ip}) gefunden - status: {state}")
results[ip] = True
# Steckdose in Datenbank speichern/aktualisieren
# steckdose in datenbank speichern/aktualisieren
try:
self._ensure_outlet_in_database(ip, nickname)
except Exception as db_error:
logger.warning(f"⚠️ Fehler beim Speichern in DB für {ip}: {str(db_error)}")
logger.warning(f"⚠️ fehler beim speichern in db für {ip}: {str(db_error)}")
else:
logger.debug(f"IP {ip} ist erreichbar, aber keine Tapo-Steckdose")
logger.debug(f"ip {ip} ist erreichbar, aber keine tapo-steckdose")
results[ip] = False
else:
logger.debug(f"IP {ip} nicht erreichbar")
logger.debug(f"ip {ip} nicht erreichbar")
results[ip] = False
except Exception as e:
logger.warning(f"Fehler bei Steckdosen-Erkennung für IP {ip}: {str(e)}")
logger.warning(f"fehler bei steckdosen-erkennung für ip {ip}: {str(e)}")
results[ip] = False
continue
# Erfolgsstatistik
# erfolgsstatistik
success_count = sum(1 for success in results.values() if success)
elapsed_time = time.time() - start_time
logger.info(f"Steckdosen-Erkennung abgeschlossen: {success_count}/{len(results)} Steckdosen gefunden in {elapsed_time:.1f}s")
logger.info(f"steckdosen-erkennung abgeschlossen: {success_count}/{len(results)} steckdosen gefunden in {elapsed_time:.1f}s")
self.auto_discovered = True
return results
def initialize_all_outlets(self) -> Dict[str, bool]:
"""
Schaltet alle gespeicherten Steckdosen aus (einheitlicher Startzustand).
schaltet alle gespeicherten steckdosen aus (einheitlicher startzustand).
Returns:
Dict[str, bool]: Ergebnis der Initialisierung pro Drucker
returns:
dict[str, bool]: ergebnis der initialisierung pro drucker
"""
logger.info("🚀 Starte Steckdosen-Initialisierung...")
logger.info("🚀 starte steckdosen-initialisierung...")
results = {}
try:
@@ -384,11 +384,11 @@ class TapoController:
printers = db_session.query(Printer).filter(Printer.active == True).all()
if not printers:
logger.warning("⚠️ Keine aktiven Drucker zur Initialisierung gefunden")
logger.warning("⚠️ keine aktiven drucker zur initialisierung gefunden")
db_session.close()
return results
# Alle Steckdosen ausschalten
# alle steckdosen ausschalten
for printer in printers:
try:
if printer.plug_ip:
@@ -400,39 +400,39 @@ class TapoController:
results[printer.name] = success
if success:
logger.info(f"{printer.name}: Steckdose ausgeschaltet")
logger.info(f"{printer.name}: steckdose ausgeschaltet")
printer.status = "offline"
printer.last_checked = datetime.now()
else:
logger.warning(f"{printer.name}: Steckdose konnte nicht ausgeschaltet werden")
logger.warning(f"{printer.name}: steckdose konnte nicht ausgeschaltet werden")
else:
logger.warning(f"⚠️ {printer.name}: Keine Steckdosen-IP konfiguriert")
logger.warning(f"⚠️ {printer.name}: keine steckdosen-ip konfiguriert")
results[printer.name] = False
except Exception as e:
logger.error(f"Fehler bei Initialisierung von {printer.name}: {str(e)}")
logger.error(f"fehler bei initialisierung von {printer.name}: {str(e)}")
results[printer.name] = False
# Änderungen speichern
# änderungen speichern
db_session.commit()
db_session.close()
success_count = sum(1 for success in results.values() if success)
total_count = len(results)
logger.info(f"🎯 Steckdosen-Initialisierung abgeschlossen: {success_count}/{total_count} erfolgreich")
logger.info(f"🎯 steckdosen-initialisierung abgeschlossen: {success_count}/{total_count} erfolgreich")
except Exception as e:
logger.error(f"Kritischer Fehler bei Steckdosen-Initialisierung: {str(e)}")
logger.error(f"kritischer fehler bei steckdosen-initialisierung: {str(e)}")
return results
def get_all_outlet_status(self) -> Dict[str, Dict[str, Any]]:
"""
Holt den Status aller konfigurierten Tapo-Steckdosen.
holt den status aller konfigurierten tapo-steckdosen.
Returns:
Dict[str, Dict]: Status aller Steckdosen mit IP als Schlüssel
returns:
dict[str, dict]: status aller steckdosen mit ip als schlüssel
"""
status_dict = {}
@@ -444,13 +444,13 @@ class TapoController:
).all()
if not printers:
logger.info(" Keine Drucker mit Tapo-Steckdosen konfiguriert")
logger.info(" keine drucker mit tapo-steckdosen konfiguriert")
db_session.close()
return status_dict
logger.info(f"🔍 Prüfe Status von {len(printers)} Tapo-Steckdosen...")
logger.info(f"🔍 prüfe status von {len(printers)} tapo-steckdosen...")
# Parallel-Status-Prüfung
# parallel-status-prüfung
with ThreadPoolExecutor(max_workers=min(len(printers), 8)) as executor:
future_to_printer = {
executor.submit(
@@ -474,7 +474,7 @@ class TapoController:
"last_checked": datetime.now().isoformat()
}
except Exception as e:
logger.error(f"Fehler bei Status-Check für {printer.name}: {str(e)}")
logger.error(f"fehler bei status-check für {printer.name}: {str(e)}")
status_dict[printer.plug_ip] = {
"printer_name": printer.name,
"printer_id": printer.id,
@@ -486,31 +486,31 @@ class TapoController:
}
db_session.close()
logger.info(f"Status-Update abgeschlossen für {len(status_dict)} Steckdosen")
logger.info(f"status-update abgeschlossen für {len(status_dict)} steckdosen")
except Exception as e:
logger.error(f"Kritischer Fehler beim Abrufen des Steckdosen-Status: {str(e)}")
logger.error(f"kritischer fehler beim abrufen des steckdosen-status: {str(e)}")
return status_dict
def _collect_device_info(self, p100: PyP100.P100, device_info: dict) -> dict:
"""
Sammelt erweiterte Geräteinformationen von der Tapo-Steckdose.
sammelt erweiterte geräteinformationen von der tapo-steckdose.
Args:
p100: PyP100-Instanz
device_info: Basis-Geräteinformationen
args:
p100: pyp100-instanz
device_info: basis-geräteinformationen
Returns:
dict: Erweiterte Informationen
returns:
dict: erweiterte informationen
"""
extra_info = {}
try:
# Firmware-Version
# firmware-version
extra_info['firmware_version'] = device_info.get('fw_ver', None)
# Versuche Energiedaten zu holen (nur P110)
# versuche energiedaten zu holen (nur p110)
try:
energy_usage = p100.getEnergyUsage()
if energy_usage:
@@ -518,22 +518,22 @@ class TapoController:
extra_info['voltage'] = energy_usage.get('voltage', None)
extra_info['current'] = energy_usage.get('current', None)
except:
pass # P100 unterstützt keine Energiedaten
pass # p100 unterstützt keine energiedaten
except Exception as e:
logger.debug(f"Fehler beim Sammeln erweiterter Geräteinformationen: {str(e)}")
logger.debug(f"fehler beim sammeln erweiterter geräteinformationen: {str(e)}")
return extra_info
def _log_plug_status(self, printer_id: int, status: str, ip_address: str, **kwargs):
"""
Protokolliert Steckdosen-Status in der Datenbank.
protokolliert steckdosen-status in der datenbank.
Args:
printer_id: ID des Druckers
status: Status der Steckdose
ip_address: IP-Adresse der Steckdose
**kwargs: Zusätzliche Parameter für das Logging
args:
printer_id: id des druckers
status: status der steckdose
ip_address: ip-adresse der steckdose
**kwargs: zusätzliche parameter für das logging
"""
if not printer_id:
return
@@ -547,57 +547,57 @@ class TapoController:
**kwargs
)
except Exception as e:
logger.warning(f"Fehler beim Loggen des Steckdosen-Status: {e}")
logger.warning(f"fehler beim loggen des steckdosen-status: {e}")
def _ensure_outlet_in_database(self, ip_address: str, nickname: str = None) -> bool:
"""
Stellt sicher, dass eine erkannte Tapo-Steckdose in der Datenbank existiert.
stellt sicher, dass eine erkannte tapo-steckdose in der datenbank existiert.
Args:
ip_address: IP-Adresse der Steckdose
nickname: Name der Steckdose (optional)
args:
ip_address: ip-adresse der steckdose
nickname: name der steckdose (optional)
Returns:
bool: True wenn erfolgreich gespeichert/aktualisiert
returns:
bool: true wenn erfolgreich gespeichert/aktualisiert
"""
try:
db_session = get_db_session()
# Prüfen, ob Drucker mit dieser IP bereits existiert
# prüfen, ob drucker mit dieser ip bereits existiert
existing_printer = db_session.query(Printer).filter(
Printer.plug_ip == ip_address
).first()
if existing_printer:
# Drucker aktualisieren
# drucker aktualisieren
if not existing_printer.plug_username or not existing_printer.plug_password:
existing_printer.plug_username = self.username
existing_printer.plug_password = self.password
logger.info(f"Drucker {existing_printer.name} mit Tapo-Anmeldedaten aktualisiert")
logger.info(f"drucker {existing_printer.name} mit tapo-anmeldedaten aktualisiert")
if nickname and existing_printer.name != nickname and "Tapo P110" not in existing_printer.name:
old_name = existing_printer.name
existing_printer.name = nickname
logger.info(f"Drucker {old_name} umbenannt zu {nickname}")
logger.info(f"drucker {old_name} umbenannt zu {nickname}")
# Drucker als aktiv markieren
# drucker als aktiv markieren
if not existing_printer.active:
existing_printer.active = True
logger.info(f"Drucker {existing_printer.name} als aktiv markiert")
logger.info(f"drucker {existing_printer.name} als aktiv markiert")
existing_printer.last_checked = datetime.now()
db_session.commit()
db_session.close()
return True
else:
# Neuen Drucker erstellen
printer_name = nickname or f"Tapo P110 ({ip_address})"
# neuen drucker erstellen
printer_name = nickname or f"tapo p110 ({ip_address})"
mac_address = f"tapo:{ip_address.replace('.', '-')}"
new_printer = Printer(
name=printer_name,
model="TP-Link Tapo P110",
location="Automatisch erkannt",
location="automatisch erkannt",
ip_address=ip_address,
mac_address=mac_address,
plug_ip=ip_address,
@@ -610,12 +610,12 @@ class TapoController:
db_session.add(new_printer)
db_session.commit()
logger.info(f"Neuer Drucker '{printer_name}' mit Tapo-Steckdose {ip_address} erstellt")
logger.info(f"neuer drucker '{printer_name}' mit tapo-steckdose {ip_address} erstellt")
db_session.close()
return True
except Exception as e:
logger.error(f"Fehler beim Speichern der Tapo-Steckdose {ip_address}: {str(e)}")
logger.error(f"fehler beim speichern der tapo-steckdose {ip_address}: {str(e)}")
try:
db_session.rollback()
db_session.close()
@@ -624,32 +624,32 @@ class TapoController:
return False
# Globale Instanz für einfachen Zugriff
# globale instanz für einfachen zugriff
tapo_controller = TapoController()
# Convenience-Funktionen für Rückwärtskompatibilität
# convenience-funktionen für rückwärtskompatibilität
def toggle_plug(ip: str, state: bool, username: str = None, password: str = None) -> bool:
"""Schaltet eine Tapo-Steckdose ein/aus."""
"""schaltet eine tapo-steckdose ein/aus."""
return tapo_controller.toggle_plug(ip, state, username, password)
def test_tapo_connection(ip: str, username: str = None, password: str = None) -> dict:
"""Testet die Verbindung zu einer Tapo-Steckdose."""
"""testet die verbindung zu einer tapo-steckdose."""
return tapo_controller.test_connection(ip, username, password)
def check_outlet_status(ip: str, username: str = None, password: str = None,
printer_id: int = None) -> Tuple[bool, str]:
"""Prüft den Status einer Tapo-Steckdose."""
"""prüft den status einer tapo-steckdose."""
return tapo_controller.check_outlet_status(ip, username, password, printer_id)
def auto_discover_tapo_outlets() -> Dict[str, bool]:
"""Führt automatische Erkennung von Tapo-Steckdosen durch."""
"""führt automatische erkennung von tapo-steckdosen durch."""
return tapo_controller.auto_discover_outlets()
def initialize_all_outlets() -> Dict[str, bool]:
"""Initialisiert alle Tapo-Steckdosen (schaltet sie aus)."""
"""initialisiert alle tapo-steckdosen (schaltet sie aus)."""
return tapo_controller.initialize_all_outlets()