chore: Änderungen commited
This commit is contained in:
@@ -215,10 +215,17 @@ def get_printer_status():
|
|||||||
Liefert den aktuellen Status aller Drucker.
|
Liefert den aktuellen Status aller Drucker.
|
||||||
Dieser Endpunkt ist kompatibel mit dem Frontend printer_monitor.js
|
Dieser Endpunkt ist kompatibel mit dem Frontend printer_monitor.js
|
||||||
|
|
||||||
|
Query-Parameter:
|
||||||
|
- force_refresh: true = Cache umgehen und echte Netzwerk-Tests (default: false)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON mit Status aller Drucker
|
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:
|
try:
|
||||||
# Nur TBA Marienfelde Drucker aus Datenbank holen
|
# 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
|
'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:
|
if printer.plug_ip and tapo_manager:
|
||||||
try:
|
try:
|
||||||
# Live-Status über Tapo-Manager abrufen
|
# Live-Status über Tapo-Manager abrufen (mit Cache-Bypass bei force_refresh)
|
||||||
live_status = tapo_manager.get_printer_status(printer.id)
|
live_status = tapo_manager.get_printer_status(printer.id, force_refresh=force_refresh)
|
||||||
|
|
||||||
# Status basierend auf Tapo-Erreichbarkeit und Schaltzustand
|
# Status basierend auf Tapo-Erreichbarkeit und Schaltzustand
|
||||||
plug_reachable = live_status.get('plug_reachable', False)
|
plug_reachable = live_status.get('plug_reachable', False)
|
||||||
@@ -470,6 +477,59 @@ def control_printer_power(printer_id):
|
|||||||
"error": f"Allgemeiner Fehler: {str(e)}"
|
"error": f"Allgemeiner Fehler: {str(e)}"
|
||||||
}), 500
|
}), 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"])
|
@printers_blueprint.route("/test/socket/<int:printer_id>", methods=["GET"])
|
||||||
@login_required
|
@login_required
|
||||||
@require_permission(Permission.ADMIN)
|
@require_permission(Permission.ADMIN)
|
||||||
|
@@ -107,13 +107,14 @@ class PrinterMonitor {
|
|||||||
/**
|
/**
|
||||||
* Holt aktuelle Drucker-Status-Daten
|
* Holt aktuelle Drucker-Status-Daten
|
||||||
*/
|
*/
|
||||||
async updatePrinterStatus() {
|
async updatePrinterStatus(forceRefresh = false) {
|
||||||
if (!this.isActive) {
|
if (!this.isActive) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(`/api/printers/status`, {
|
const url = `/api/printers/status${forceRefresh ? '?force_refresh=true' : ''}`;
|
||||||
|
const response = await fetch(url, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
@@ -427,6 +428,56 @@ class PrinterMonitor {
|
|||||||
/**
|
/**
|
||||||
* Initialisiert alle Steckdosen (nur für Admins)
|
* 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() {
|
async initializeAllOutlets() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/printers/monitor/initialize-outlets', {
|
const response = await fetch('/api/printers/monitor/initialize-outlets', {
|
||||||
|
@@ -185,6 +185,23 @@ class TapoController:
|
|||||||
|
|
||||||
return False
|
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:
|
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
|
Schaltet eine TP-Link Tapo P110-Steckdose aus
|
||||||
|
@@ -54,30 +54,37 @@ class TapoStatusManager:
|
|||||||
|
|
||||||
logger.info("TapoStatusManager mit Session-Caching initialisiert")
|
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
|
Gibt den aktuellen Status eines Druckers zurück
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
printer_id: ID des Druckers
|
printer_id: ID des Druckers
|
||||||
|
force_refresh: True = Cache umgehen und echten Netzwerk-Test durchführen
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dict mit Status-Informationen
|
Dict mit Status-Informationen
|
||||||
"""
|
"""
|
||||||
with self._cache_lock:
|
if not force_refresh:
|
||||||
# Aus Cache holen wenn vorhanden und aktuell
|
with self._cache_lock:
|
||||||
if printer_id in self._status_cache:
|
# Aus Cache holen wenn vorhanden und aktuell
|
||||||
cache_data = self._status_cache[printer_id]
|
if printer_id in self._status_cache:
|
||||||
if self._is_cache_valid(printer_id):
|
cache_data = self._status_cache[printer_id]
|
||||||
return cache_data
|
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)
|
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
|
Gibt den Status aller Drucker zurück
|
||||||
|
|
||||||
|
Args:
|
||||||
|
force_refresh: True = Cache für alle Drucker umgehen
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Liste mit Status-Informationen aller Drucker
|
Liste mit Status-Informationen aller Drucker
|
||||||
"""
|
"""
|
||||||
@@ -89,7 +96,7 @@ class TapoStatusManager:
|
|||||||
|
|
||||||
# Status für jeden Drucker abrufen
|
# Status für jeden Drucker abrufen
|
||||||
for printer in printers:
|
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)
|
status_list.append(status)
|
||||||
|
|
||||||
db_session.close()
|
db_session.close()
|
||||||
@@ -660,6 +667,104 @@ class TapoStatusManager:
|
|||||||
logger.error(f"Fehler beim Bereinigen des Session-Cache: {str(e)}")
|
logger.error(f"Fehler beim Bereinigen des Session-Cache: {str(e)}")
|
||||||
return 0
|
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:
|
def _get_status_color(self, status: str) -> str:
|
||||||
"""Gibt die Farbe für einen Status zurück"""
|
"""Gibt die Farbe für einen Status zurück"""
|
||||||
colors = {
|
colors = {
|
||||||
|
Reference in New Issue
Block a user