chore: Änderungen commited

This commit is contained in:
2025-06-16 08:49:18 +02:00
parent 4491156902
commit 18126335ac
5 changed files with 249 additions and 16 deletions

View File

@ -215,10 +215,17 @@ def get_printer_status():
Liefert den aktuellen Status aller Drucker.
Dieser Endpunkt ist kompatibel mit dem Frontend printer_monitor.js
Query-Parameter:
- force_refresh: true = Cache umgehen und echte Netzwerk-Tests (default: false)
Returns:
JSON mit Status aller Drucker
"""
printers_logger.info(f"🔄 Status-Abfrage von Benutzer {current_user.name} (ID: {current_user.id})")
# Force-Refresh Parameter prüfen
force_refresh = request.args.get('force_refresh', 'false').lower() == 'true'
refresh_type = "Force-Refresh" if force_refresh else "Normal"
printers_logger.info(f"🔄 {refresh_type} Status-Abfrage von Benutzer {current_user.name} (ID: {current_user.id})")
try:
# Nur TBA Marienfelde Drucker aus Datenbank holen
@ -260,11 +267,11 @@ def get_printer_status():
'created_at': printer.created_at.isoformat() if printer.created_at else None
}
# LIVE TAPO-STATUS ABRUFEN (Kernlogik)
# LIVE TAPO-STATUS ABRUFEN (Kernlogik mit Force-Refresh)
if printer.plug_ip and tapo_manager:
try:
# Live-Status über Tapo-Manager abrufen
live_status = tapo_manager.get_printer_status(printer.id)
# Live-Status über Tapo-Manager abrufen (mit Cache-Bypass bei force_refresh)
live_status = tapo_manager.get_printer_status(printer.id, force_refresh=force_refresh)
# Status basierend auf Tapo-Erreichbarkeit und Schaltzustand
plug_reachable = live_status.get('plug_reachable', False)
@ -470,6 +477,59 @@ def control_printer_power(printer_id):
"error": f"Allgemeiner Fehler: {str(e)}"
}), 500
@printers_blueprint.route("/force-refresh", methods=["POST"])
@login_required
@measure_execution_time(logger=printers_logger, task_name="API-Force-Refresh-Alle-Drucker")
def force_refresh_all_printer_status():
"""
Forciert komplette Netzwerk-Neuprüfung aller Drucker-Status.
Invalidiert alle Caches und führt echte Netzwerk-Tests durch.
Für Verwendung nach Netzwerkwechseln oder bei Cache-Problemen.
Returns:
JSON mit Force-Refresh-Ergebnissen
"""
printers_logger.info(f"🔄 Force-Refresh aller Drucker von Benutzer {current_user.name} (ID: {current_user.id})")
try:
# Tapo Status Manager für Force-Refresh verwenden
from utils.tapo_status_manager import tapo_status_manager
# Force-Network-Refresh durchführen
refresh_results = tapo_status_manager.force_network_refresh()
if refresh_results.get("success", False):
printers_logger.info(f"✅ Force-Refresh erfolgreich: {refresh_results.get('printers_refreshed', 0)} Drucker aktualisiert")
return jsonify({
"success": True,
"message": "Alle Drucker-Status erfolgreich aktualisiert",
"refresh_results": refresh_results,
"performed_by": {
"id": current_user.id,
"name": current_user.name
},
"timestamp": datetime.now().isoformat()
})
else:
printers_logger.error(f"❌ Force-Refresh fehlgeschlagen: {refresh_results.get('error', 'Unbekannter Fehler')}")
return jsonify({
"success": False,
"error": "Force-Refresh fehlgeschlagen",
"details": refresh_results,
"timestamp": datetime.now().isoformat()
}), 500
except Exception as e:
printers_logger.error(f"❌ Allgemeiner Fehler bei Force-Refresh: {str(e)}")
return jsonify({
"success": False,
"error": f"Fehler beim Force-Refresh: {str(e)}",
"timestamp": datetime.now().isoformat()
}), 500
@printers_blueprint.route("/test/socket/<int:printer_id>", methods=["GET"])
@login_required
@require_permission(Permission.ADMIN)

View File

@ -107,13 +107,14 @@ class PrinterMonitor {
/**
* Holt aktuelle Drucker-Status-Daten
*/
async updatePrinterStatus() {
async updatePrinterStatus(forceRefresh = false) {
if (!this.isActive) {
return;
}
try {
const response = await fetch(`/api/printers/status`, {
const url = `/api/printers/status${forceRefresh ? '?force_refresh=true' : ''}`;
const response = await fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
@ -427,6 +428,56 @@ class PrinterMonitor {
/**
* Initialisiert alle Steckdosen (nur für Admins)
*/
async forceNetworkRefresh() {
try {
console.log('🔄 Starte Force-Network-Refresh...');
const response = await fetch('/api/printers/force-refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest'
}
});
if (response.ok) {
const data = await response.json();
if (data.success) {
console.log('✅ Force-Network-Refresh erfolgreich:', data.refresh_results);
// Benachrichtige über Force-Refresh
this.notifyCallbacks({
type: 'force_refresh',
results: data.refresh_results,
message: data.message,
timestamp: new Date().toISOString()
});
// Direkt mit neuen Daten aktualisieren (ohne Cache)
await this.updatePrinterStatus(true);
return data;
} else {
throw new Error(data.error || 'Force-Refresh fehlgeschlagen');
}
} else {
throw new Error(`HTTP ${response.status}`);
}
} catch (error) {
console.error('❌ Fehler bei Force-Network-Refresh:', error);
this.notifyCallbacks({
type: 'error',
message: `Force-Refresh fehlgeschlagen: ${error.message}`,
timestamp: new Date().toISOString()
});
throw error;
}
}
async initializeAllOutlets() {
try {
const response = await fetch('/api/printers/monitor/initialize-outlets', {

View File

@ -185,6 +185,23 @@ class TapoController:
return False
def clear_cache(self) -> bool:
"""
Leert alle Caches des TapoControllers
Returns:
bool: True wenn erfolgreich
"""
try:
# Hier können Cache-Daten geleert werden falls vorhanden
# Aktuell verwendet TapoController keinen expliziten Cache,
# aber diese Methode wird für Konsistenz bereitgestellt
tapo_logger.debug("TapoController Cache geleert (keine Cache-Daten vorhanden)")
return True
except Exception as e:
tapo_logger.error(f"Fehler beim Leeren des TapoController Cache: {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

View File

@ -54,30 +54,37 @@ class TapoStatusManager:
logger.info("TapoStatusManager mit Session-Caching initialisiert")
def get_printer_status(self, printer_id: int) -> Dict[str, any]:
def get_printer_status(self, printer_id: int, force_refresh: bool = False) -> Dict[str, any]:
"""
Gibt den aktuellen Status eines Druckers zurück
Args:
printer_id: ID des Druckers
force_refresh: True = Cache umgehen und echten Netzwerk-Test durchführen
Returns:
Dict mit Status-Informationen
"""
with self._cache_lock:
# Aus Cache holen wenn vorhanden und aktuell
if printer_id in self._status_cache:
cache_data = self._status_cache[printer_id]
if self._is_cache_valid(printer_id):
return cache_data
if not force_refresh:
with self._cache_lock:
# Aus Cache holen wenn vorhanden und aktuell
if printer_id in self._status_cache:
cache_data = self._status_cache[printer_id]
if self._is_cache_valid(printer_id):
return cache_data
# Neuen Status abrufen
# Neuen Status abrufen (mit Cache-Invalidierung bei force_refresh)
if force_refresh:
self.invalidate_cache(printer_id)
return self._fetch_printer_status(printer_id)
def get_all_printer_status(self) -> List[Dict[str, any]]:
def get_all_printer_status(self, force_refresh: bool = False) -> List[Dict[str, any]]:
"""
Gibt den Status aller Drucker zurück
Args:
force_refresh: True = Cache für alle Drucker umgehen
Returns:
Liste mit Status-Informationen aller Drucker
"""
@ -89,7 +96,7 @@ class TapoStatusManager:
# Status für jeden Drucker abrufen
for printer in printers:
status = self.get_printer_status(printer.id)
status = self.get_printer_status(printer.id, force_refresh=force_refresh)
status_list.append(status)
db_session.close()
@ -660,6 +667,104 @@ class TapoStatusManager:
logger.error(f"Fehler beim Bereinigen des Session-Cache: {str(e)}")
return 0
def invalidate_cache(self, printer_id: int = None) -> bool:
"""
Invalidiert Cache für spezifischen Drucker oder alle
Args:
printer_id: Optional - spezifischer Drucker, None = alle Drucker
Returns:
bool: True wenn erfolgreich
"""
try:
with self._cache_lock:
if printer_id is not None:
# Spezifischen Drucker-Cache löschen
self._status_cache.pop(printer_id, None)
self._last_check.pop(printer_id, None)
logger.debug(f"Cache für Drucker {printer_id} invalidiert")
else:
# Alle Caches löschen
self._status_cache.clear()
self._last_check.clear()
logger.info("Kompletter Status-Cache invalidiert")
return True
except Exception as e:
logger.error(f"Fehler beim Invalidieren des Cache: {str(e)}")
return False
def invalidate_all_caches(self) -> bool:
"""
Invalidiert alle Cache-Systeme (Status + Session)
Verwendet bei Netzwerkwechseln oder Force-Refresh
Returns:
bool: True wenn erfolgreich
"""
try:
# Status-Cache invalidieren
self.invalidate_cache()
# Session-Cache invalidieren
self.clear_session_cache()
logger.info("Alle Caches invalidiert (Status + Session)")
return True
except Exception as e:
logger.error(f"Fehler beim Invalidieren aller Caches: {str(e)}")
return False
def force_network_refresh(self) -> Dict[str, any]:
"""
Forciert komplette Netzwerk-Neuprüfung aller Drucker
Invalidiert alle Caches und führt echte Netzwerk-Tests durch
Returns:
Dict mit Refresh-Ergebnissen
"""
try:
logger.info("Starte Force-Network-Refresh für alle Drucker")
# Alle Caches invalidieren
self.invalidate_all_caches()
# Tapo-Controller Cache leeren falls vorhanden
try:
from utils.hardware_integration import tapo_controller
if tapo_controller and hasattr(tapo_controller, 'clear_cache'):
tapo_controller.clear_cache()
logger.debug("Tapo-Controller Cache geleert")
except Exception as e:
logger.warning(f"Tapo-Controller Cache konnte nicht geleert werden: {str(e)}")
# Frischen Status für alle Drucker abrufen
fresh_status = self.get_all_printer_status(force_refresh=True)
# Ergebnisse zusammenfassen
results = {
"success": True,
"timestamp": datetime.now().isoformat(),
"printers_refreshed": len(fresh_status),
"printers": fresh_status,
"message": f"Netzwerk-Status für {len(fresh_status)} Drucker erfolgreich aktualisiert"
}
logger.info(f"Force-Network-Refresh abgeschlossen: {len(fresh_status)} Drucker aktualisiert")
return results
except Exception as e:
logger.error(f"Fehler beim Force-Network-Refresh: {str(e)}")
return {
"success": False,
"error": str(e),
"timestamp": datetime.now().isoformat(),
"message": "Fehler beim Aktualisieren der Netzwerk-Status"
}
def _get_status_color(self, status: str) -> str:
"""Gibt die Farbe für einen Status zurück"""
colors = {