Automatische Initialisierung der Tapo-Steckdosen implementiert

- Steckdosen werden automatisch aus SOCKET_DEVICES Umgebungsvariable initialisiert
- Drucker werden als "Printer X" benannt, wobei X die Nummer der Steckdose ist
- Alle Steckdosen werden beim Start in den AUS-Zustand versetzt
- Verbesserte Fehlerbehandlung beim Ausschalten der Steckdosen mit mehreren Versuchen

🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root 2025-03-12 11:23:06 +01:00
parent 47143d29a5
commit faf0736dbd

View File

@ -32,6 +32,7 @@ app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
# Steckdosen-Konfiguration
TAPO_USERNAME = os.environ.get('TAPO_USERNAME')
TAPO_PASSWORD = os.environ.get('TAPO_PASSWORD')
# SOCKET_DEVICES Format: {"192.168.1.100": {"number": "1"}, "192.168.1.101": {"number": "2"}, ...}
SOCKET_DEVICES = json.loads(os.environ.get('SOCKET_DEVICES', '{}'))
# Logging
@ -107,9 +108,46 @@ def init_db():
db.commit()
# Initialisiere die Datenbank beim Starten der Anwendung
# Initialisierung der Steckdosen
def init_sockets():
"""
Initialisiert die Steckdosen-Einträge in der Datenbank basierend auf SOCKET_DEVICES Umgebungsvariable.
Stellt sicher, dass alle Steckdosen zu Beginn ausgeschaltet sind.
"""
app.logger.info("Initialisiere Steckdosen aus Umgebungsvariablen")
db = get_db()
# Alle IP-Adressen aus der Datenbank abrufen
existing_ips = {row['ip_address']: row['id'] for row in db.execute('SELECT id, ip_address FROM socket').fetchall() if row['ip_address']}
for ip_address, device_config in SOCKET_DEVICES.items():
socket_number = device_config.get('number', '0')
name = f"Printer {socket_number}"
description = f"3D-Drucker mit SmartPlug (IP: {ip_address})"
if ip_address in existing_ips:
# Steckdose existiert bereits, nichts zu tun
app.logger.info(f"Steckdose mit IP {ip_address} existiert bereits in der Datenbank")
socket_id = existing_ips[ip_address]
else:
# Steckdose erstellen, wenn sie noch nicht existiert
socket = create_socket(name=name, description=description, ip_address=ip_address, status=0)
socket_id = socket['id']
app.logger.info(f"Neue Steckdose angelegt: {name} mit IP {ip_address}")
# Steckdose ausschalten, um sicherzustellen, dass alle Steckdosen im AUS-Zustand starten
try:
turn_off_socket(ip_address)
app.logger.info(f"Steckdose {ip_address} wurde beim Start ausgeschaltet")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {ip_address}: {e}")
# Initialisiere die Datenbank und Steckdosen beim Starten der Anwendung
with app.app_context():
init_db()
# Nur initialisieren, wenn Steckdosen konfiguriert sind
if SOCKET_DEVICES:
init_sockets()
app.teardown_appcontext(close_db)
@ -752,10 +790,22 @@ def abort_job(job_id):
# Steckdose ausschalten, falls IP-Adresse hinterlegt ist
if socket['ip_address']:
try:
turn_off_socket(socket['ip_address'])
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose: {e}")
# Mehrmals versuchen, die Steckdose auszuschalten, um sicherzustellen, dass sie wirklich aus ist
max_attempts = 3
for attempt in range(1, max_attempts + 1):
try:
success = turn_off_socket(socket['ip_address'])
if success:
app.logger.info(f"Steckdose {socket['ip_address']} für abgebrochenen Job {job['id']} ausgeschaltet (Versuch {attempt}).")
break
app.logger.warning(f"Konnte Steckdose {socket['ip_address']} nicht ausschalten (Versuch {attempt}/{max_attempts}).")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e} (Versuch {attempt}/{max_attempts})")
# Nur wenn es nicht der letzte Versuch war, kurz warten und neu versuchen
if attempt < max_attempts:
import time
time.sleep(1)
return jsonify(job_to_dict(updated_job))
@ -784,10 +834,22 @@ def finish_job(job_id):
# Steckdose ausschalten, falls IP-Adresse hinterlegt ist
if socket['ip_address']:
try:
turn_off_socket(socket['ip_address'])
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose: {e}")
# Mehrmals versuchen, die Steckdose auszuschalten, um sicherzustellen, dass sie wirklich aus ist
max_attempts = 3
for attempt in range(1, max_attempts + 1):
try:
success = turn_off_socket(socket['ip_address'])
if success:
app.logger.info(f"Steckdose {socket['ip_address']} für beendeten Job {job['id']} ausgeschaltet (Versuch {attempt}).")
break
app.logger.warning(f"Konnte Steckdose {socket['ip_address']} nicht ausschalten (Versuch {attempt}/{max_attempts}).")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e} (Versuch {attempt}/{max_attempts})")
# Nur wenn es nicht der letzte Versuch war, kurz warten und neu versuchen
if attempt < max_attempts:
import time
time.sleep(1)
return jsonify(job_to_dict(updated_job))
@ -849,11 +911,22 @@ def job_remaining_time(job_id):
# Steckdose ausschalten, falls IP-Adresse hinterlegt ist
if socket['ip_address']:
try:
turn_off_socket(socket['ip_address'])
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} automatisch ausgeschaltet.")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e}")
# Mehrmals versuchen, die Steckdose auszuschalten, um sicherzustellen, dass sie wirklich aus ist
max_attempts = 3
for attempt in range(1, max_attempts + 1):
try:
success = turn_off_socket(socket['ip_address'])
if success:
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} automatisch ausgeschaltet (Versuch {attempt}).")
break
app.logger.warning(f"Konnte Steckdose {socket['ip_address']} nicht ausschalten (Versuch {attempt}/{max_attempts}).")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e} (Versuch {attempt}/{max_attempts})")
# Nur wenn es nicht der letzte Versuch war, kurz warten und neu versuchen
if attempt < max_attempts:
import time
time.sleep(1)
return jsonify({
'remaining_minutes': remaining,
@ -977,11 +1050,22 @@ def check_jobs():
# Steckdose ausschalten, falls IP-Adresse hinterlegt ist
if socket['ip_address']:
try:
turn_off_socket(socket['ip_address'])
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} ausgeschaltet.")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e}")
# Mehrmals versuchen, die Steckdose auszuschalten, um sicherzustellen, dass sie wirklich aus ist
max_attempts = 3
for attempt in range(1, max_attempts + 1):
try:
success = turn_off_socket(socket['ip_address'])
if success:
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} ausgeschaltet (Versuch {attempt}).")
break
app.logger.warning(f"Konnte Steckdose {socket['ip_address']} nicht ausschalten (Versuch {attempt}/{max_attempts}).")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e} (Versuch {attempt}/{max_attempts})")
# Nur wenn es nicht der letzte Versuch war, kurz warten und neu versuchen
if attempt < max_attempts:
import time
time.sleep(1)
app.logger.info(f"{len(expired_jobs)} abgelaufene Jobs überprüft und Steckdosen aktualisiert.")
@ -1006,11 +1090,22 @@ def job_status(job_id):
# Steckdose ausschalten, falls IP-Adresse hinterlegt ist
if socket['ip_address']:
try:
turn_off_socket(socket['ip_address'])
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} automatisch ausgeschaltet.")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e}")
# Mehrmals versuchen, die Steckdose auszuschalten, um sicherzustellen, dass sie wirklich aus ist
max_attempts = 3
for attempt in range(1, max_attempts + 1):
try:
success = turn_off_socket(socket['ip_address'])
if success:
app.logger.info(f"Steckdose {socket['ip_address']} für abgelaufenen Job {job['id']} automatisch ausgeschaltet (Versuch {attempt}).")
break
app.logger.warning(f"Konnte Steckdose {socket['ip_address']} nicht ausschalten (Versuch {attempt}/{max_attempts}).")
except Exception as e:
app.logger.error(f"Fehler beim Ausschalten der Steckdose {socket['ip_address']}: {e} (Versuch {attempt}/{max_attempts})")
# Nur wenn es nicht der letzte Versuch war, kurz warten und neu versuchen
if attempt < max_attempts:
import time
time.sleep(1)
job_status = 'aborted' if job['aborted'] else ('completed' if remaining == 0 else 'active')