"Refactor job scheduler and printer monitor for improved performance (feat)"
This commit is contained in:
parent
962d395017
commit
fe94a3b58c
@ -3498,8 +3498,40 @@ def toggle_printer_power(printer_id):
|
|||||||
return jsonify({"error": "Administratorrechte erforderlich"}), 403
|
return jsonify({"error": "Administratorrechte erforderlich"}), 403
|
||||||
|
|
||||||
try:
|
try:
|
||||||
data = request.get_json()
|
# Robuste JSON-Datenverarbeitung
|
||||||
state = data.get("state", True) # Standard: einschalten
|
data = {}
|
||||||
|
try:
|
||||||
|
if request.is_json and request.get_json():
|
||||||
|
data = request.get_json()
|
||||||
|
elif request.form:
|
||||||
|
# Fallback für Form-Daten
|
||||||
|
data = request.form.to_dict()
|
||||||
|
except Exception as json_error:
|
||||||
|
printers_logger.warning(f"Fehler beim Parsen der JSON-Daten für Drucker {printer_id}: {str(json_error)}")
|
||||||
|
# Verwende Standard-Werte wenn JSON-Parsing fehlschlägt
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
# Standard-Zustand ermitteln (Toggle-Verhalten)
|
||||||
|
db_session = get_db_session()
|
||||||
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
|
|
||||||
|
if not printer:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# Aktuellen Status ermitteln für Toggle-Verhalten
|
||||||
|
current_status = getattr(printer, 'status', 'offline')
|
||||||
|
current_active = getattr(printer, 'active', False)
|
||||||
|
|
||||||
|
# Zielzustand bestimmen
|
||||||
|
if 'state' in data:
|
||||||
|
# Expliziter Zustand angegeben
|
||||||
|
state = bool(data.get("state", True))
|
||||||
|
else:
|
||||||
|
# Toggle-Verhalten: Umschalten basierend auf aktuellem Status
|
||||||
|
state = not (current_status == "available" and current_active)
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
# Steckdose schalten
|
# Steckdose schalten
|
||||||
from utils.job_scheduler import toggle_plug
|
from utils.job_scheduler import toggle_plug
|
||||||
@ -3507,20 +3539,31 @@ def toggle_printer_power(printer_id):
|
|||||||
|
|
||||||
if success:
|
if success:
|
||||||
action = "eingeschaltet" if state else "ausgeschaltet"
|
action = "eingeschaltet" if state else "ausgeschaltet"
|
||||||
|
printers_logger.info(f"Drucker {printer.name} (ID: {printer_id}) erfolgreich {action} von Admin {current_user.name}")
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"success": True,
|
"success": True,
|
||||||
"message": f"Drucker erfolgreich {action}",
|
"message": f"Drucker erfolgreich {action}",
|
||||||
"printer_id": printer_id,
|
"printer_id": printer_id,
|
||||||
"state": state
|
"printer_name": printer.name,
|
||||||
|
"state": state,
|
||||||
|
"action": action
|
||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
|
printers_logger.error(f"Fehler beim Schalten der Steckdose für Drucker {printer_id}")
|
||||||
return jsonify({
|
return jsonify({
|
||||||
"error": "Fehler beim Schalten der Steckdose"
|
"success": False,
|
||||||
|
"error": "Fehler beim Schalten der Steckdose",
|
||||||
|
"printer_id": printer_id
|
||||||
}), 500
|
}), 500
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
printers_logger.error(f"Fehler beim Schalten von Drucker {printer_id}: {str(e)}")
|
printers_logger.error(f"Fehler beim Schalten von Drucker {printer_id}: {str(e)}")
|
||||||
return jsonify({"error": "Interner Serverfehler"}), 500
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"error": "Interner Serverfehler",
|
||||||
|
"details": str(e)
|
||||||
|
}), 500
|
||||||
|
|
||||||
@app.route("/api/admin/printers/<int:printer_id>/test-tapo", methods=["POST"])
|
@app.route("/api/admin/printers/<int:printer_id>/test-tapo", methods=["POST"])
|
||||||
@login_required
|
@login_required
|
||||||
@ -6293,6 +6336,7 @@ if __name__ == "__main__":
|
|||||||
app_logger.error(f"❌ Fehler beim Shutdown: {str(e)}")
|
app_logger.error(f"❌ Fehler beim Shutdown: {str(e)}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
# Signal-Handler registrieren (Windows-kompatibel)
|
# Signal-Handler registrieren (Windows-kompatibel)
|
||||||
if os.name == 'nt': # Windows
|
if os.name == 'nt': # Windows
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
signal.signal(signal.SIGINT, signal_handler)
|
||||||
@ -6696,3 +6740,270 @@ def cleanup_temp_files():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
app_logger.error(f"Fehler beim Aufräumen temporärer Dateien: {str(e)}")
|
app_logger.error(f"Fehler beim Aufräumen temporärer Dateien: {str(e)}")
|
||||||
return jsonify({'error': f'Fehler beim Aufräumen: {str(e)}'}), 500
|
return jsonify({'error': f'Fehler beim Aufräumen: {str(e)}'}), 500
|
||||||
|
|
||||||
|
# ===== FEHLENDE DRUCKER-SPEZIFISCHE API-ENDPOINTS =====
|
||||||
|
|
||||||
|
@app.route("/api/printers/<int:printer_id>/jobs", methods=["GET"])
|
||||||
|
@login_required
|
||||||
|
def get_printer_jobs(printer_id):
|
||||||
|
"""Gibt alle Jobs für einen spezifischen Drucker zurück."""
|
||||||
|
try:
|
||||||
|
db_session = get_db_session()
|
||||||
|
|
||||||
|
# Prüfen ob Drucker existiert
|
||||||
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
|
if not printer:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# Jobs für diesen Drucker abrufen
|
||||||
|
jobs = db_session.query(Job).filter(Job.printer_id == printer_id).order_by(Job.created_at.desc()).all()
|
||||||
|
|
||||||
|
jobs_data = []
|
||||||
|
for job in jobs:
|
||||||
|
job_data = {
|
||||||
|
"id": job.id,
|
||||||
|
"title": job.title,
|
||||||
|
"status": job.status,
|
||||||
|
"priority": job.priority,
|
||||||
|
"created_at": job.created_at.isoformat() if job.created_at else None,
|
||||||
|
"scheduled_time": job.scheduled_time.isoformat() if job.scheduled_time else None,
|
||||||
|
"started_at": job.started_at.isoformat() if job.started_at else None,
|
||||||
|
"finished_at": job.finished_at.isoformat() if job.finished_at else None,
|
||||||
|
"estimated_duration": job.estimated_duration,
|
||||||
|
"user_id": job.user_id,
|
||||||
|
"printer_id": job.printer_id,
|
||||||
|
"printer_name": printer.name
|
||||||
|
}
|
||||||
|
jobs_data.append(job_data)
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"jobs": jobs_data,
|
||||||
|
"total": len(jobs_data),
|
||||||
|
"printer": {
|
||||||
|
"id": printer.id,
|
||||||
|
"name": printer.name,
|
||||||
|
"status": printer.status
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
printers_logger.error(f"Fehler beim Abrufen der Jobs für Drucker {printer_id}: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
|
||||||
|
@app.route("/api/printers/<int:printer_id>/stats", methods=["GET"])
|
||||||
|
@login_required
|
||||||
|
def get_printer_stats(printer_id):
|
||||||
|
"""Gibt Statistiken für einen spezifischen Drucker zurück."""
|
||||||
|
try:
|
||||||
|
db_session = get_db_session()
|
||||||
|
|
||||||
|
# Prüfen ob Drucker existiert
|
||||||
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
|
if not printer:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# Statistiken berechnen
|
||||||
|
total_jobs = db_session.query(Job).filter(Job.printer_id == printer_id).count()
|
||||||
|
completed_jobs = db_session.query(Job).filter(
|
||||||
|
Job.printer_id == printer_id,
|
||||||
|
Job.status == "completed"
|
||||||
|
).count()
|
||||||
|
failed_jobs = db_session.query(Job).filter(
|
||||||
|
Job.printer_id == printer_id,
|
||||||
|
Job.status == "failed"
|
||||||
|
).count()
|
||||||
|
active_jobs = db_session.query(Job).filter(
|
||||||
|
Job.printer_id == printer_id,
|
||||||
|
Job.status.in_(["scheduled", "running"])
|
||||||
|
).count()
|
||||||
|
|
||||||
|
# Durchschnittliche Job-Dauer berechnen
|
||||||
|
avg_duration_result = db_session.query(func.avg(Job.estimated_duration)).filter(
|
||||||
|
Job.printer_id == printer_id,
|
||||||
|
Job.status == "completed",
|
||||||
|
Job.estimated_duration.isnot(None)
|
||||||
|
).scalar()
|
||||||
|
|
||||||
|
avg_duration = round(avg_duration_result, 2) if avg_duration_result else 0
|
||||||
|
|
||||||
|
# Erfolgsrate berechnen
|
||||||
|
success_rate = round((completed_jobs / total_jobs * 100), 2) if total_jobs > 0 else 0
|
||||||
|
|
||||||
|
# Letzte Aktivität
|
||||||
|
last_job = db_session.query(Job).filter(Job.printer_id == printer_id).order_by(Job.created_at.desc()).first()
|
||||||
|
last_activity = last_job.created_at.isoformat() if last_job and last_job.created_at else None
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
stats_data = {
|
||||||
|
"printer": {
|
||||||
|
"id": printer.id,
|
||||||
|
"name": printer.name,
|
||||||
|
"status": printer.status,
|
||||||
|
"location": printer.location
|
||||||
|
},
|
||||||
|
"jobs": {
|
||||||
|
"total": total_jobs,
|
||||||
|
"completed": completed_jobs,
|
||||||
|
"failed": failed_jobs,
|
||||||
|
"active": active_jobs,
|
||||||
|
"success_rate": success_rate
|
||||||
|
},
|
||||||
|
"performance": {
|
||||||
|
"average_duration": avg_duration,
|
||||||
|
"last_activity": last_activity
|
||||||
|
},
|
||||||
|
"generated_at": datetime.now().isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsonify(stats_data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
printers_logger.error(f"Fehler beim Abrufen der Statistiken für Drucker {printer_id}: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
|
||||||
|
@app.route("/api/printers/<int:printer_id>/test", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
def test_printer_connection(printer_id):
|
||||||
|
"""Testet die Verbindung zu einem spezifischen Drucker."""
|
||||||
|
try:
|
||||||
|
db_session = get_db_session()
|
||||||
|
|
||||||
|
# Prüfen ob Drucker existiert
|
||||||
|
printer = db_session.query(Printer).get(printer_id)
|
||||||
|
if not printer:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({"error": "Drucker nicht gefunden"}), 404
|
||||||
|
|
||||||
|
# IP-Adresse für Test ermitteln
|
||||||
|
ip_to_test = printer.plug_ip if printer.plug_ip else getattr(printer, 'ip_address', None)
|
||||||
|
|
||||||
|
if not ip_to_test:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"error": "Keine IP-Adresse für Drucker konfiguriert",
|
||||||
|
"printer": {
|
||||||
|
"id": printer.id,
|
||||||
|
"name": printer.name
|
||||||
|
}
|
||||||
|
}), 400
|
||||||
|
|
||||||
|
# Verbindungstest durchführen
|
||||||
|
printers_logger.info(f"Teste Verbindung zu Drucker {printer.name} (ID: {printer_id}) auf IP {ip_to_test}")
|
||||||
|
|
||||||
|
status, active = check_printer_status(ip_to_test, timeout=10)
|
||||||
|
|
||||||
|
# Status in Datenbank aktualisieren
|
||||||
|
printer.status = "available" if status == "online" else "offline"
|
||||||
|
if hasattr(printer, 'active'):
|
||||||
|
printer.active = active
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
test_result = {
|
||||||
|
"success": status == "online",
|
||||||
|
"status": status,
|
||||||
|
"active": active,
|
||||||
|
"ip_address": ip_to_test,
|
||||||
|
"printer": {
|
||||||
|
"id": printer.id,
|
||||||
|
"name": printer.name,
|
||||||
|
"location": printer.location,
|
||||||
|
"model": printer.model
|
||||||
|
},
|
||||||
|
"test_time": datetime.now().isoformat(),
|
||||||
|
"message": f"Drucker ist {'online und erreichbar' if status == 'online' else 'offline oder nicht erreichbar'}"
|
||||||
|
}
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
printers_logger.info(f"Verbindungstest für Drucker {printer.name}: {status}")
|
||||||
|
|
||||||
|
return jsonify(test_result)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
printers_logger.error(f"Fehler beim Testen der Verbindung zu Drucker {printer_id}: {str(e)}")
|
||||||
|
return jsonify({
|
||||||
|
"success": False,
|
||||||
|
"error": "Interner Serverfehler beim Verbindungstest",
|
||||||
|
"details": str(e)
|
||||||
|
}), 500
|
||||||
|
|
||||||
|
# ===== ADMIN-SPEZIFISCHE DRUCKER-ENDPOINTS =====
|
||||||
|
|
||||||
|
@app.route("/api/admin/printers/create", methods=["POST"])
|
||||||
|
@login_required
|
||||||
|
@admin_required
|
||||||
|
def admin_create_printer_api():
|
||||||
|
"""Admin-Endpoint zum Erstellen neuer Drucker."""
|
||||||
|
try:
|
||||||
|
data = request.get_json()
|
||||||
|
|
||||||
|
if not data:
|
||||||
|
return jsonify({"error": "Keine Daten empfangen"}), 400
|
||||||
|
|
||||||
|
# Pflichtfelder prüfen
|
||||||
|
required_fields = ["name", "plug_ip"]
|
||||||
|
for field in required_fields:
|
||||||
|
if field not in data or not data[field]:
|
||||||
|
return jsonify({"error": f"Feld '{field}' ist erforderlich"}), 400
|
||||||
|
|
||||||
|
db_session = get_db_session()
|
||||||
|
|
||||||
|
# Prüfen, ob bereits ein Drucker mit diesem Namen existiert
|
||||||
|
existing_printer = db_session.query(Printer).filter(Printer.name == data["name"]).first()
|
||||||
|
if existing_printer:
|
||||||
|
db_session.close()
|
||||||
|
return jsonify({"error": "Ein Drucker mit diesem Namen existiert bereits"}), 400
|
||||||
|
|
||||||
|
# Neuen Drucker erstellen
|
||||||
|
new_printer = Printer(
|
||||||
|
name=data["name"],
|
||||||
|
model=data.get("model", ""),
|
||||||
|
location=data.get("location", ""),
|
||||||
|
mac_address=data.get("mac_address", ""),
|
||||||
|
plug_ip=data["plug_ip"],
|
||||||
|
status="offline",
|
||||||
|
active=True,
|
||||||
|
created_at=datetime.now()
|
||||||
|
)
|
||||||
|
|
||||||
|
db_session.add(new_printer)
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
# Sofortiger Status-Check
|
||||||
|
if new_printer.plug_ip:
|
||||||
|
status, active = check_printer_status(new_printer.plug_ip)
|
||||||
|
new_printer.status = "available" if status == "online" else "offline"
|
||||||
|
new_printer.active = active
|
||||||
|
db_session.commit()
|
||||||
|
|
||||||
|
printer_data = {
|
||||||
|
"id": new_printer.id,
|
||||||
|
"name": new_printer.name,
|
||||||
|
"model": new_printer.model,
|
||||||
|
"location": new_printer.location,
|
||||||
|
"mac_address": new_printer.mac_address,
|
||||||
|
"plug_ip": new_printer.plug_ip,
|
||||||
|
"status": new_printer.status,
|
||||||
|
"active": new_printer.active,
|
||||||
|
"created_at": new_printer.created_at.isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
db_session.close()
|
||||||
|
|
||||||
|
printers_logger.info(f"Admin {current_user.name} hat Drucker '{new_printer.name}' erstellt")
|
||||||
|
|
||||||
|
return jsonify({
|
||||||
|
"success": True,
|
||||||
|
"message": "Drucker erfolgreich erstellt",
|
||||||
|
"printer": printer_data
|
||||||
|
}), 201
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
printers_logger.error(f"Fehler beim Erstellen eines Druckers durch Admin: {str(e)}")
|
||||||
|
return jsonify({"error": "Interner Serverfehler"}), 500
|
||||||
|
@ -1 +1,207 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
SOFORT-TEST für TP-Link Tapo P110-Steckdosen
|
||||||
|
Testet die Verbindung mit echten Anmeldedaten und findet alle verfügbaren Steckdosen.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
# Tapo-Anmeldedaten (HARDKODIERT)
|
||||||
|
TAPO_USERNAME = "till.tomczak@mercedes-benz.com"
|
||||||
|
TAPO_PASSWORD = "744563017196"
|
||||||
|
|
||||||
|
# IP-Bereiche zum Testen
|
||||||
|
IP_RANGES_TO_SCAN = [
|
||||||
|
"192.168.1.{}",
|
||||||
|
"192.168.0.{}",
|
||||||
|
"10.0.0.{}",
|
||||||
|
"172.16.0.{}"
|
||||||
|
]
|
||||||
|
|
||||||
|
def log_message(message, level="INFO"):
|
||||||
|
"""Logge eine Nachricht mit Zeitstempel"""
|
||||||
|
timestamp = datetime.now().strftime("%H:%M:%S")
|
||||||
|
print(f"[{timestamp}] [{level}] {message}")
|
||||||
|
|
||||||
|
def test_ping(ip_address):
|
||||||
|
"""Teste ob eine IP erreichbar ist"""
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
['ping', '-n', '1', '-w', '1000', ip_address],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=2
|
||||||
|
)
|
||||||
|
return result.returncode == 0
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_tapo_connection(ip_address):
|
||||||
|
"""Teste Tapo-Verbindung zu einer IP"""
|
||||||
|
try:
|
||||||
|
from PyP100 import PyP110
|
||||||
|
|
||||||
|
log_message(f"Teste Tapo-Verbindung zu {ip_address}...")
|
||||||
|
p110 = PyP110.P110(ip_address, TAPO_USERNAME, TAPO_PASSWORD)
|
||||||
|
p110.handshake() # Authentifizierung
|
||||||
|
p110.login() # Login
|
||||||
|
|
||||||
|
# Geräteinformationen abrufen
|
||||||
|
device_info = p110.getDeviceInfo()
|
||||||
|
|
||||||
|
log_message(f"✅ ERFOLG: {ip_address} ist eine Tapo-Steckdose!")
|
||||||
|
log_message(f" 📛 Name: {device_info.get('nickname', 'Unbekannt')}")
|
||||||
|
log_message(f" ⚡ Status: {'EIN' if device_info.get('device_on', False) else 'AUS'}")
|
||||||
|
|
||||||
|
if 'on_time' in device_info:
|
||||||
|
on_time = device_info.get('on_time', 0)
|
||||||
|
hours, minutes = divmod(on_time // 60, 60)
|
||||||
|
log_message(f" ⏱️ Betriebszeit: {hours}h {minutes}m")
|
||||||
|
|
||||||
|
return True, device_info
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
error_msg = str(e).lower()
|
||||||
|
if "login" in error_msg or "credentials" in error_msg:
|
||||||
|
log_message(f"❌ {ip_address}: Falsche Anmeldedaten")
|
||||||
|
elif "timeout" in error_msg:
|
||||||
|
log_message(f"❌ {ip_address}: Timeout")
|
||||||
|
elif "connect" in error_msg or "unreachable" in error_msg:
|
||||||
|
log_message(f"❌ {ip_address}: Nicht erreichbar")
|
||||||
|
else:
|
||||||
|
log_message(f"❌ {ip_address}: {str(e)}")
|
||||||
|
return False, None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Hauptfunktion: Scanne Netzwerk nach Tapo-Steckdosen"""
|
||||||
|
log_message("🚀 SOFORT-TEST: TP-Link Tapo P110-Steckdosen")
|
||||||
|
log_message(f"👤 Benutzername: {TAPO_USERNAME}")
|
||||||
|
log_message(f"🔐 Passwort: {'*' * len(TAPO_PASSWORD)}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# PyP100 Import testen
|
||||||
|
try:
|
||||||
|
from PyP100 import PyP110
|
||||||
|
log_message("✅ PyP100-Modul erfolgreich importiert")
|
||||||
|
except ImportError:
|
||||||
|
log_message("❌ FEHLER: PyP100-Modul nicht gefunden!", "ERROR")
|
||||||
|
log_message(" Installiere mit: pip install PyP100", "ERROR")
|
||||||
|
return
|
||||||
|
|
||||||
|
print()
|
||||||
|
log_message("🔍 Scanne Netzwerk nach erreichbaren Geräten...")
|
||||||
|
|
||||||
|
# Erst bekannte IP-Adressen testen
|
||||||
|
known_ips = [
|
||||||
|
"192.168.1.100", "192.168.1.101", "192.168.1.102",
|
||||||
|
"192.168.1.103", "192.168.1.104", "192.168.1.105",
|
||||||
|
"192.168.0.100", "192.168.0.101", "192.168.0.102"
|
||||||
|
]
|
||||||
|
|
||||||
|
found_steckdosen = []
|
||||||
|
|
||||||
|
for ip in known_ips:
|
||||||
|
if test_ping(ip):
|
||||||
|
log_message(f"🌐 {ip} ist erreichbar - teste Tapo...")
|
||||||
|
success, device_info = test_tapo_connection(ip)
|
||||||
|
if success:
|
||||||
|
found_steckdosen.append((ip, device_info))
|
||||||
|
else:
|
||||||
|
log_message(f"⚫ {ip} nicht erreichbar")
|
||||||
|
|
||||||
|
# Wenn keine gefunden, erweiterte Suche
|
||||||
|
if not found_steckdosen:
|
||||||
|
log_message("🔍 Keine Steckdosen in Standard-IPs gefunden - erweitere Suche...")
|
||||||
|
|
||||||
|
for ip_range in IP_RANGES_TO_SCAN:
|
||||||
|
log_message(f"Scanne Bereich {ip_range.format('1-20')}...")
|
||||||
|
|
||||||
|
for i in range(1, 21): # Erste 20 IPs pro Bereich
|
||||||
|
ip = ip_range.format(i)
|
||||||
|
if test_ping(ip):
|
||||||
|
log_message(f"🌐 {ip} erreichbar - teste Tapo...")
|
||||||
|
success, device_info = test_tapo_connection(ip)
|
||||||
|
if success:
|
||||||
|
found_steckdosen.append((ip, device_info))
|
||||||
|
|
||||||
|
# Ergebnisse
|
||||||
|
print()
|
||||||
|
log_message("📊 ERGEBNISSE:")
|
||||||
|
|
||||||
|
if found_steckdosen:
|
||||||
|
log_message(f"🎉 {len(found_steckdosen)} Tapo-Steckdose(n) gefunden!")
|
||||||
|
print()
|
||||||
|
|
||||||
|
for i, (ip, device_info) in enumerate(found_steckdosen, 1):
|
||||||
|
log_message(f"Steckdose #{i}:")
|
||||||
|
log_message(f" IP: {ip}")
|
||||||
|
log_message(f" Name: {device_info.get('nickname', 'Unbekannt')}")
|
||||||
|
log_message(f" Status: {'EIN' if device_info.get('device_on', False) else 'AUS'}")
|
||||||
|
log_message(f" Modell: {device_info.get('model', 'Unbekannt')}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
# Steckdosen-Test durchführen
|
||||||
|
log_message("🧪 Teste Ein/Aus-Schaltung der ersten Steckdose...")
|
||||||
|
test_ip, _ = found_steckdosen[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
from PyP100 import PyP110
|
||||||
|
p110 = PyP110.P110(test_ip, TAPO_USERNAME, TAPO_PASSWORD)
|
||||||
|
p110.handshake()
|
||||||
|
p110.login()
|
||||||
|
|
||||||
|
# Aktuelle Status abrufen
|
||||||
|
device_info = p110.getDeviceInfo()
|
||||||
|
current_state = device_info.get('device_on', False)
|
||||||
|
|
||||||
|
log_message(f"Aktueller Status: {'EIN' if current_state else 'AUS'}")
|
||||||
|
|
||||||
|
# Gegenteil schalten
|
||||||
|
if current_state:
|
||||||
|
log_message("Schalte AUS...")
|
||||||
|
p110.turnOff()
|
||||||
|
time.sleep(2)
|
||||||
|
log_message("✅ Erfolgreich ausgeschaltet!")
|
||||||
|
|
||||||
|
log_message("Schalte wieder EIN...")
|
||||||
|
p110.turnOn()
|
||||||
|
time.sleep(2)
|
||||||
|
log_message("✅ Erfolgreich eingeschaltet!")
|
||||||
|
else:
|
||||||
|
log_message("Schalte EIN...")
|
||||||
|
p110.turnOn()
|
||||||
|
time.sleep(2)
|
||||||
|
log_message("✅ Erfolgreich eingeschaltet!")
|
||||||
|
|
||||||
|
log_message("Schalte wieder AUS...")
|
||||||
|
p110.turnOff()
|
||||||
|
time.sleep(2)
|
||||||
|
log_message("✅ Erfolgreich ausgeschaltet!")
|
||||||
|
|
||||||
|
log_message("🎉 STECKDOSEN-STEUERUNG FUNKTIONIERT PERFEKT!")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
log_message(f"❌ Fehler beim Testen der Schaltung: {str(e)}", "ERROR")
|
||||||
|
|
||||||
|
else:
|
||||||
|
log_message("❌ KEINE Tapo-Steckdosen gefunden!", "ERROR")
|
||||||
|
log_message("Mögliche Ursachen:", "ERROR")
|
||||||
|
log_message("1. Steckdosen sind in einem anderen IP-Bereich", "ERROR")
|
||||||
|
log_message("2. Anmeldedaten sind falsch", "ERROR")
|
||||||
|
log_message("3. Netzwerkprobleme", "ERROR")
|
||||||
|
log_message("4. Steckdosen sind nicht im Netzwerk", "ERROR")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log_message("Test abgebrochen durch Benutzer", "INFO")
|
||||||
|
except Exception as e:
|
||||||
|
log_message(f"Unerwarteter Fehler: {str(e)}", "ERROR")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
@ -9,6 +9,7 @@ from sqlalchemy.orm import joinedload
|
|||||||
|
|
||||||
from utils.logging_config import get_logger
|
from utils.logging_config import get_logger
|
||||||
from models import Job, Printer, get_db_session
|
from models import Job, Printer, get_db_session
|
||||||
|
from config.settings import TAPO_USERNAME, TAPO_PASSWORD
|
||||||
|
|
||||||
# Lazy logger initialization
|
# Lazy logger initialization
|
||||||
_logger = None
|
_logger = None
|
||||||
@ -313,15 +314,22 @@ def toggle_plug(printer_id: int, state: bool) -> bool:
|
|||||||
db_session.close()
|
db_session.close()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Konfiguration validieren
|
# Konfiguration validieren und Fallback verwenden
|
||||||
if not printer.plug_ip or not printer.plug_username or not printer.plug_password:
|
plug_ip = printer.plug_ip
|
||||||
logger.error(f"Unvollständige Tapo-Konfiguration für Drucker {printer.name} (ID: {printer_id})")
|
plug_username = printer.plug_username or TAPO_USERNAME
|
||||||
|
plug_password = printer.plug_password or TAPO_PASSWORD
|
||||||
|
|
||||||
|
if not plug_ip:
|
||||||
|
logger.error(f"Keine Steckdosen-IP für Drucker {printer.name} (ID: {printer_id}) konfiguriert")
|
||||||
db_session.close()
|
db_session.close()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
if not plug_username or not plug_password:
|
||||||
|
logger.error(f"Unvollständige Tapo-Konfiguration für Drucker {printer.name} (ID: {printer_id}) - verwende globale Anmeldedaten")
|
||||||
|
|
||||||
# TP-Link Tapo P110 Verbindung herstellen
|
# TP-Link Tapo P110 Verbindung herstellen
|
||||||
logger.debug(f"Verbinde zu Tapo-Steckdose {printer.plug_ip} für Drucker {printer.name}")
|
logger.debug(f"Verbinde zu Tapo-Steckdose {plug_ip} für Drucker {printer.name}")
|
||||||
p110 = PyP110.P110(printer.plug_ip, printer.plug_username, printer.plug_password)
|
p110 = PyP110.P110(plug_ip, plug_username, plug_password)
|
||||||
p110.handshake() # Authentifizierung
|
p110.handshake() # Authentifizierung
|
||||||
p110.login() # Login
|
p110.login() # Login
|
||||||
|
|
||||||
@ -341,14 +349,14 @@ def toggle_plug(printer_id: int, state: bool) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def test_tapo_connection(ip_address: str, username: str, password: str) -> dict:
|
def test_tapo_connection(ip_address: str, username: str = None, password: str = None) -> dict:
|
||||||
"""
|
"""
|
||||||
Testet die Verbindung zu einer Tapo-Steckdose und gibt detaillierte Informationen zurück.
|
Testet die Verbindung zu einer Tapo-Steckdose und gibt detaillierte Informationen zurück.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
ip_address: IP-Adresse der Steckdose
|
ip_address: IP-Adresse der Steckdose
|
||||||
username: Benutzername
|
username: Benutzername (optional, verwendet globale Konfiguration als Fallback)
|
||||||
password: Passwort
|
password: Passwort (optional, verwendet globale Konfiguration als Fallback)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict: Testergebnis mit Status und Informationen
|
dict: Testergebnis mit Status und Informationen
|
||||||
@ -361,6 +369,12 @@ def test_tapo_connection(ip_address: str, username: str, password: str) -> dict:
|
|||||||
"status": "unknown"
|
"status": "unknown"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Fallback zu globalen Anmeldedaten
|
||||||
|
if not username or not password:
|
||||||
|
username = TAPO_USERNAME
|
||||||
|
password = TAPO_PASSWORD
|
||||||
|
logger.debug(f"🔧 Verwende globale Tapo-Anmeldedaten für {ip_address}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
logger.debug(f"Teste Tapo-Verbindung zu {ip_address}")
|
logger.debug(f"Teste Tapo-Verbindung zu {ip_address}")
|
||||||
p110 = PyP110.P110(ip_address, username, password)
|
p110 = PyP110.P110(ip_address, username, password)
|
||||||
|
@ -17,7 +17,7 @@ import os
|
|||||||
|
|
||||||
from models import get_db_session, Printer
|
from models import get_db_session, Printer
|
||||||
from utils.logging_config import get_logger
|
from utils.logging_config import get_logger
|
||||||
from config.settings import PRINTERS
|
from config.settings import PRINTERS, TAPO_USERNAME, TAPO_PASSWORD
|
||||||
|
|
||||||
# TP-Link Tapo P110 Unterstützung hinzufügen
|
# TP-Link Tapo P110 Unterstützung hinzufügen
|
||||||
try:
|
try:
|
||||||
@ -386,6 +386,12 @@ class PrinterMonitor:
|
|||||||
monitor_logger.debug("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdosen-Status nicht abfragen")
|
monitor_logger.debug("⚠️ PyP100-Modul nicht verfügbar - kann Tapo-Steckdosen-Status nicht abfragen")
|
||||||
return False, "unknown"
|
return False, "unknown"
|
||||||
|
|
||||||
|
# Fallback zu globalen Anmeldedaten wenn keine lokalen vorhanden
|
||||||
|
if not username or not password:
|
||||||
|
username = TAPO_USERNAME
|
||||||
|
password = TAPO_PASSWORD
|
||||||
|
monitor_logger.debug(f"🔧 Verwende globale Tapo-Anmeldedaten für {ip_address}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# TP-Link Tapo P110 Verbindung herstellen
|
# TP-Link Tapo P110 Verbindung herstellen
|
||||||
p110 = PyP110.P110(ip_address, username, password)
|
p110 = PyP110.P110(ip_address, username, password)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user