steckdose timeout

This commit is contained in:
root 2025-03-13 09:56:03 +01:00
parent 2ab091b90c
commit 9502a9b3af

View File

@ -654,8 +654,17 @@ def get_socket_uptime_events(socket_id=None, limit=100):
return [dict(row) for row in rows] return [dict(row) for row in rows]
def check_socket_connection(socket_id): def check_socket_connection(socket_id, timeout=8):
"""Überprüft die Verbindung zu einer Steckdose und aktualisiert den Status""" """
Überprüft die Verbindung zu einer Steckdose und aktualisiert den Status.
Args:
socket_id: ID der Steckdose
timeout: Timeout in Sekunden, nach dem die Verbindung als fehlgeschlagen gilt
Returns:
True wenn die Steckdose online ist, sonst False
"""
socket = get_socket_by_id(socket_id) socket = get_socket_by_id(socket_id)
if not socket or not socket['ip_address']: if not socket or not socket['ip_address']:
return False return False
@ -664,7 +673,8 @@ def check_socket_connection(socket_id):
last_seen = socket.get('last_seen') last_seen = socket.get('last_seen')
try: try:
device = get_socket_device(socket['ip_address']) # Verwende den Timeout-Parameter für die Geräteverbindung
device = get_socket_device(socket['ip_address'], timeout=timeout)
if device: if device:
# Verbindung erfolgreich # Verbindung erfolgreich
if previous_status != 'online': if previous_status != 'online':
@ -672,14 +682,18 @@ def check_socket_connection(socket_id):
duration = None duration = None
if previous_status == 'offline' and last_seen: if previous_status == 'offline' and last_seen:
# Berechne die Dauer des Ausfalls # Berechne die Dauer des Ausfalls
offline_since = datetime.datetime.fromisoformat(last_seen) try:
now = datetime.datetime.utcnow() offline_since = datetime.datetime.fromisoformat(last_seen)
duration = int((now - offline_since).total_seconds()) now = datetime.datetime.utcnow()
duration = int((now - offline_since).total_seconds())
except (ValueError, TypeError):
# Wenn das Datum nicht geparst werden kann
duration = None
log_socket_connection_event(socket_id, 'online', duration) log_socket_connection_event(socket_id, 'online', duration)
return True return True
else: else:
# Keine Verbindung möglich # Keine Verbindung möglich oder Timeout
if previous_status != 'offline': if previous_status != 'offline':
# Status hat sich von online/unknown auf offline geändert # Status hat sich von online/unknown auf offline geändert
log_socket_connection_event(socket_id, 'offline') log_socket_connection_event(socket_id, 'offline')
@ -691,20 +705,66 @@ def check_socket_connection(socket_id):
return False return False
# Steckdosen-Steuerung mit PyP100 # Steckdosen-Steuerung mit PyP100
def get_socket_device(ip_address): def get_socket_device(ip_address, timeout=8):
"""
Stellt eine Verbindung zu einer Tapo P100-Steckdose her, mit einem konfigurierbaren Timeout.
Args:
ip_address: IP-Adresse der Steckdose
timeout: Timeout in Sekunden, nach dem die Verbindung als fehlgeschlagen gilt
Returns:
Das PyP100-Geräteobjekt bei erfolgreicher Verbindung, sonst None
"""
try: try:
device = PyP100.P100(ip_address, TAPO_USERNAME, TAPO_PASSWORD) # Nutze Threading mit Timeout für die Verbindung
device.handshake() # Erstellt die erforderlichen Cookies import threading
device.login() # Sendet Anmeldedaten und erstellt AES-Schlüssel import queue
app.logger.info(f"PyP100 Verbindung zu {ip_address} hergestellt")
return device result_queue = queue.Queue()
def connect_with_timeout():
try:
device = PyP100.P100(ip_address, TAPO_USERNAME, TAPO_PASSWORD)
device.handshake() # Erstellt die erforderlichen Cookies
device.login() # Sendet Anmeldedaten und erstellt AES-Schlüssel
result_queue.put(device)
except Exception as e:
app.logger.error(f"Fehler bei der Anmeldung an P100-Gerät {ip_address}: {e}")
result_queue.put(None)
# Starte den Verbindungsversuch in einem Thread
connect_thread = threading.Thread(target=connect_with_timeout)
connect_thread.daemon = True
connect_thread.start()
# Warte mit Timeout auf das Ergebnis
try:
device = result_queue.get(timeout=timeout)
if device:
app.logger.info(f"PyP100 Verbindung zu {ip_address} hergestellt")
return device
except queue.Empty:
app.logger.error(f"Timeout bei der Verbindung zu {ip_address} nach {timeout} Sekunden")
return None
except Exception as e: except Exception as e:
app.logger.error(f"Fehler bei der Anmeldung an P100-Gerät {ip_address}: {e}") app.logger.error(f"Unerwarteter Fehler bei der Anmeldung an P100-Gerät {ip_address}: {e}")
return None return None
def turn_on_socket(ip_address): def turn_on_socket(ip_address, timeout=8):
"""
Schaltet eine Steckdose ein mit konfiguriertem Timeout.
Args:
ip_address: IP-Adresse der Steckdose
timeout: Timeout in Sekunden für die Verbindung
Returns:
True bei Erfolg, False bei Fehlern oder Timeout
"""
try: try:
device = get_socket_device(ip_address) device = get_socket_device(ip_address, timeout=timeout)
if device: if device:
device.turnOn() device.turnOn()
app.logger.info(f"P100-Steckdose {ip_address} eingeschaltet") app.logger.info(f"P100-Steckdose {ip_address} eingeschaltet")
@ -714,9 +774,19 @@ def turn_on_socket(ip_address):
app.logger.error(f"Fehler beim Einschalten der P100-Steckdose {ip_address}: {e}") app.logger.error(f"Fehler beim Einschalten der P100-Steckdose {ip_address}: {e}")
return False return False
def turn_off_socket(ip_address): def turn_off_socket(ip_address, timeout=8):
"""
Schaltet eine Steckdose aus mit konfiguriertem Timeout.
Args:
ip_address: IP-Adresse der Steckdose
timeout: Timeout in Sekunden für die Verbindung
Returns:
True bei Erfolg, False bei Fehlern oder Timeout
"""
try: try:
device = get_socket_device(ip_address) device = get_socket_device(ip_address, timeout=timeout)
if device: if device:
device.turnOff() device.turnOff()
app.logger.info(f"P100-Steckdose {ip_address} ausgeschaltet") app.logger.info(f"P100-Steckdose {ip_address} ausgeschaltet")
@ -1405,16 +1475,18 @@ def check_jobs():
app.logger.info(f"{len(expired_jobs)} abgelaufene Jobs überprüft, {handled_jobs} Steckdosen aktualisiert.") app.logger.info(f"{len(expired_jobs)} abgelaufene Jobs überprüft, {handled_jobs} Steckdosen aktualisiert.")
def check_socket_connections(): def check_socket_connections():
"""Überprüft periodisch die Verbindung zu allen Steckdosen.""" """Überprüft periodisch die Verbindung zu allen Steckdosen mit 8-Sekunden-Timeout."""
with app.app_context(): with app.app_context():
sockets = get_all_sockets() sockets = get_all_sockets()
app.logger.info(f"Überprüfe Verbindungsstatus von {len(sockets)} Steckdosen") app.logger.info(f"Überprüfe Verbindungsstatus von {len(sockets)} Steckdosen")
online_count = 0 online_count = 0
offline_count = 0 offline_count = 0
skipped_count = 0
for socket in sockets: for socket in sockets:
if not socket['ip_address']: if not socket['ip_address']:
skipped_count += 1
continue # Überspringe Steckdosen ohne IP-Adresse continue # Überspringe Steckdosen ohne IP-Adresse
is_online = check_socket_connection(socket['id']) is_online = check_socket_connection(socket['id'])
@ -1422,16 +1494,17 @@ def check_socket_connections():
online_count += 1 online_count += 1
else: else:
offline_count += 1 offline_count += 1
app.logger.warning(f"Steckdose {socket['name']} ({socket['ip_address']}) ist nicht erreichbar")
app.logger.info(f"Verbindungsüberprüfung abgeschlossen: {online_count} online, {offline_count} offline") app.logger.info(f"Verbindungsüberprüfung abgeschlossen: {online_count} online, {offline_count} offline, {skipped_count} übersprungen")
# Hintergrund-Thread für das Job-Polling und Steckdosen-Monitoring # Hintergrund-Thread für das Job-Polling und Steckdosen-Monitoring
def background_job_checker(): def background_job_checker():
"""Hintergrund-Thread, der regelmäßig abgelaufene Jobs und Steckdosenverbindungen überprüft.""" """Hintergrund-Thread, der regelmäßig abgelaufene Jobs und Steckdosenverbindungen überprüft."""
app.logger.info("Starte Hintergrund-Thread für Job-Überprüfung und Steckdosen-Monitoring") app.logger.info("Starte Hintergrund-Thread für Job-Überprüfung und Steckdosen-Monitoring")
# Standardintervall für Socket-Überprüfungen (5 Minuten) # Standardintervall für Socket-Überprüfungen (2 Minuten)
socket_check_interval = int(os.environ.get('SOCKET_CHECK_INTERVAL', '300')) socket_check_interval = int(os.environ.get('SOCKET_CHECK_INTERVAL', '120'))
last_socket_check = 0 last_socket_check = 0
while True: while True:
@ -1439,11 +1512,13 @@ def background_job_checker():
# Überprüfe Jobs bei jedem Durchlauf # Überprüfe Jobs bei jedem Durchlauf
check_jobs() check_jobs()
# Überprüfe Steckdosen nur in längeren Intervallen # Überprüfe Steckdosen in regelmäßigen Intervallen
current_time = time.time() current_time = time.time()
if current_time - last_socket_check >= socket_check_interval: if current_time - last_socket_check >= socket_check_interval:
# Socket-Überprüfung mit 8-Sekunden-Timeout pro Gerät
check_socket_connections() check_socket_connections()
last_socket_check = current_time last_socket_check = current_time
app.logger.info(f"Nächste Socket-Überprüfung in {socket_check_interval} Sekunden")
except Exception as e: except Exception as e:
app.logger.error(f"Fehler im Hintergrund-Thread: {e}") app.logger.error(f"Fehler im Hintergrund-Thread: {e}")