chore: Änderungen commited
This commit is contained in:
@ -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)
|
||||
|
@ -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', {
|
||||
|
@ -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
|
||||
|
@ -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 = {
|
||||
|
Reference in New Issue
Block a user