steckdose timeout
This commit is contained in:
parent
2ab091b90c
commit
9502a9b3af
121
backend/app.py
121
backend/app.py
@ -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}")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user