Es scheint, dass Sie eine Reihe von Dateien und Verzeichnissen in einem Backend-Projekt bearbeitet haben. Hier ist eine Zusammenfassung der Änderungen:

This commit is contained in:
Tomczak
2025-06-19 11:49:24 +02:00
parent c16bcca9e6
commit 9bf89f8ddb
389 changed files with 6135 additions and 2886 deletions

View File

@@ -13,7 +13,7 @@ import signal
import pickle
import hashlib
from datetime import datetime, timedelta
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, abort, send_from_directory
from flask import Flask, render_template, request, jsonify, redirect, url_for, session, abort, send_from_directory, flash
from flask_login import LoginManager, current_user, logout_user, login_required
from flask_wtf import CSRFProtect
from flask_wtf.csrf import CSRFError
@@ -932,15 +932,15 @@ def admin():
def printers_page():
"""Zeigt die Übersichtsseite für Drucker an mit Server-Side Rendering."""
try:
from utils.hardware_integration import printer_monitor
from utils.hardware_integration import get_tapo_controller
from models import get_db_session, Printer
# Drucker-Daten server-side laden
db_session = get_db_session()
all_printers = db_session.query(Printer).filter(Printer.active == True).all()
# Live-Status für alle Drucker abrufen
status_data = printer_monitor.get_live_printer_status()
# Live-Status direkt über TapoController abrufen
tapo_controller = get_tapo_controller()
# Drucker-Daten mit Status anreichern
printers_with_status = []
@@ -956,30 +956,100 @@ def printers_page():
'status': 'offline'
}
# Status aus LiveData hinzufügen
if printer.id in status_data:
live_data = status_data[printer.id]
printer_info.update({
'plug_status': live_data.get('plug_status', 'unknown'),
'plug_reachable': live_data.get('plug_reachable', False),
'can_control': live_data.get('can_control', False),
'last_checked': live_data.get('last_checked'),
'error': live_data.get('error')
})
# Status-Display für UI
if live_data.get('plug_status') in printer_monitor.STATUS_DISPLAY:
printer_info['status_display'] = printer_monitor.STATUS_DISPLAY[live_data.get('plug_status')]
# Status direkt über TapoController prüfen und in DB persistieren
if printer.plug_ip:
try:
reachable, plug_status = tapo_controller.check_outlet_status(
printer.plug_ip, printer_id=printer.id
)
# Drucker-Status basierend auf Steckdosen-Status aktualisieren
if not reachable:
# Nicht erreichbar = offline
printer.status = 'offline'
status_text = 'Offline'
status_color = 'red'
elif plug_status == 'on':
# Steckdose an = belegt
printer.status = 'busy'
status_text = 'Belegt'
status_color = 'green'
elif plug_status == 'off':
# Steckdose aus = verfügbar
printer.status = 'idle'
status_text = 'Verfügbar'
status_color = 'gray'
else:
# Unbekannter Status = offline
printer.status = 'offline'
status_text = 'Unbekannt'
status_color = 'red'
# Zeitstempel aktualisieren und in DB speichern
printer.last_checked = datetime.now()
printer.updated_at = datetime.now()
# Status-Änderung protokollieren (nur bei tatsächlicher Änderung)
from models import PlugStatusLog
current_db_status = printer.status
log_status = 'connected' if reachable else 'disconnected'
if plug_status == 'on':
log_status = 'on'
elif plug_status == 'off':
log_status = 'off'
# Nur loggen wenn sich der Status geändert hat (vereinfachte Prüfung)
try:
PlugStatusLog.log_status_change(
printer_id=printer.id,
status=log_status,
source='system',
ip_address=printer.plug_ip,
notes="Automatische Status-Prüfung beim Laden der Drucker-Seite"
)
app_logger.debug(f"📊 Auto-Status protokolliert: Drucker {printer.id} -> {log_status}")
except Exception as log_error:
app_logger.error(f"❌ Fehler beim Auto-Protokollieren: {str(log_error)}")
printer_info.update({
'plug_status': plug_status,
'plug_reachable': reachable,
'can_control': reachable,
'status': printer.status,
'last_checked': datetime.now().isoformat()
})
# Status-Display für UI
printer_info['status_display'] = {
'text': status_text,
'color': status_color
}
except Exception as e:
printer_info.update({
'plug_status': 'unknown',
'plug_reachable': False,
'can_control': False,
'error': str(e),
'status_display': {'text': 'Fehler', 'color': 'red'}
})
else:
printer_info.update({
'plug_status': 'unknown',
'plug_status': 'no_plug',
'plug_reachable': False,
'can_control': False,
'status_display': {'text': 'Unbekannt', 'color': 'gray', 'icon': 'question'}
'status_display': {'text': 'Keine Steckdose', 'color': 'gray'}
})
printers_with_status.append(printer_info)
# Alle Status-Updates in die Datenbank committen
try:
db_session.commit()
app_logger.debug(f"✅ Status-Updates für {len(printers_with_status)} Drucker erfolgreich gespeichert")
except Exception as commit_error:
app_logger.error(f"❌ Fehler beim Speichern der Status-Updates: {str(commit_error)}")
db_session.rollback()
# Einzigartige Werte für Filter
models = list(set([p['model'] for p in printers_with_status if p['model'] != 'Unbekannt']))
locations = list(set([p['location'] for p in printers_with_status if p['location'] != 'Unbekannt']))
@@ -1006,7 +1076,8 @@ def printers_page():
def printer_control():
"""Server-Side Drucker-Steuerung ohne JavaScript."""
try:
from utils.hardware_integration import printer_monitor
from utils.hardware_integration import get_tapo_controller
from models import get_db_session, Printer
printer_id = request.form.get('printer_id')
action = request.form.get('action') # 'on' oder 'off'
@@ -1019,16 +1090,123 @@ def printer_control():
flash('Ungültige Aktion. Nur "on" oder "off" erlaubt.', 'error')
return redirect(url_for('printers_page'))
# Drucker steuern
success, message = printer_monitor.control_plug(int(printer_id), action)
# Drucker aus Datenbank laden
db_session = get_db_session()
printer = db_session.query(Printer).filter(Printer.id == int(printer_id)).first()
if not printer:
flash('Drucker nicht gefunden', 'error')
db_session.close()
return redirect(url_for('printers_page'))
if not printer.plug_ip:
flash('Keine Steckdose für diesen Drucker konfiguriert', 'error')
db_session.close()
return redirect(url_for('printers_page'))
# Erst Erreichbarkeit der Steckdose prüfen
tapo_controller = get_tapo_controller()
# Prüfe ob Steckdose erreichbar ist
if not tapo_controller.is_plug_reachable(printer.plug_ip):
# Steckdose nicht erreichbar = Drucker offline
printer.status = 'offline'
printer.last_checked = datetime.now()
printer.updated_at = datetime.now()
# Status-Änderung protokollieren
from models import PlugStatusLog
try:
PlugStatusLog.log_status_change(
printer_id=int(printer_id),
status='disconnected',
source='system',
user_id=current_user.id,
ip_address=printer.plug_ip,
error_message=f"Steckdose {printer.plug_ip} nicht erreichbar",
notes=f"Erreichbarkeitsprüfung durch {current_user.name} fehlgeschlagen"
)
app_logger.debug(f"📊 Offline-Status protokolliert: Drucker {printer_id} -> disconnected")
except Exception as log_error:
app_logger.error(f"❌ Fehler beim Protokollieren des Offline-Status: {str(log_error)}")
db_session.commit()
flash(f'Steckdose nicht erreichbar - Drucker als offline markiert', 'error')
app_logger.warning(f"⚠️ Steckdose {printer.plug_ip} für Drucker {printer_id} nicht erreichbar")
db_session.close()
return redirect(url_for('printers_page'))
# Steckdose erreichbar - Steuerung ausführen
state = action == 'on'
success = tapo_controller.toggle_plug(printer.plug_ip, state)
if success:
# Drucker-Status basierend auf Steckdosen-Aktion aktualisieren
if action == 'on':
# Steckdose an = Drucker belegt (busy)
printer.status = 'busy'
status_text = "belegt"
plug_status = 'on'
else:
# Steckdose aus = Drucker verfügbar (idle)
printer.status = 'idle'
status_text = "verfügbar"
plug_status = 'off'
# Zeitstempel der letzten Überprüfung aktualisieren
printer.last_checked = datetime.now()
printer.updated_at = datetime.now()
# Status-Änderung in PlugStatusLog protokollieren mit Energiedaten
from models import PlugStatusLog
try:
# Energiedaten abrufen falls verfügbar
energy_data = {}
try:
reachable, current_status = tapo_controller.check_outlet_status(printer.plug_ip, printer_id=int(printer_id))
if reachable:
# Versuche Energiedaten zu holen (falls P110)
extra_info = tapo_controller._get_extra_device_info(printer.plug_ip)
if extra_info:
energy_data = {
'power_consumption': extra_info.get('power_consumption'),
'voltage': extra_info.get('voltage'),
'current': extra_info.get('current'),
'firmware_version': extra_info.get('firmware_version')
}
except Exception as energy_error:
app_logger.debug(f"⚡ Energiedaten für {printer.plug_ip} nicht verfügbar: {str(energy_error)}")
action_text = "eingeschaltet" if action == 'on' else "ausgeschaltet"
PlugStatusLog.log_status_change(
printer_id=int(printer_id),
status=plug_status,
source='manual',
user_id=current_user.id,
ip_address=printer.plug_ip,
power_consumption=energy_data.get('power_consumption'),
voltage=energy_data.get('voltage'),
current=energy_data.get('current'),
firmware_version=energy_data.get('firmware_version'),
notes=f"Manuell {action_text} durch {current_user.name}"
)
app_logger.debug(f"📊 Status-Änderung mit Energiedaten protokolliert: Drucker {printer_id} -> {plug_status}")
except Exception as log_error:
app_logger.error(f"❌ Fehler beim Protokollieren der Status-Änderung: {str(log_error)}")
# Änderungen in Datenbank speichern
db_session.commit()
action_text = "eingeschaltet" if action == 'on' else "ausgeschaltet"
flash(f'Drucker erfolgreich {action_text}', 'success')
app_logger.info(f"✅ Drucker {printer_id} erfolgreich {action_text} durch {current_user.name}")
flash(f'Drucker erfolgreich {action_text} - Status: {status_text}', 'success')
app_logger.info(f"✅ Drucker {printer_id} erfolgreich {action_text} durch {current_user.name} - Status: {status_text}")
else:
flash(f'Fehler bei Drucker-Steuerung: {message}', 'error')
app_logger.error(f"Fehler bei Drucker {printer_id} Steuerung: {message}")
action_text = "einschalten" if action == 'on' else "ausschalten"
flash(f'Fehler beim {action_text} der Steckdose', 'error')
app_logger.error(f"❌ Fehler beim {action_text} von Drucker {printer_id}")
db_session.close()
return redirect(url_for('printers_page'))