Compare commits

...

36 Commits

Author SHA1 Message Date
dc6dfc38ad usr/local/bin/custom/poe.sh aktualisiert 2025-10-12 19:33:11 +02:00
7561791a0b usr/local/bin/custom/poe.sh aktualisiert 2025-10-12 19:29:39 +02:00
c7266f73f3 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:21:06 +02:00
1a742c56c9 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:20:40 +02:00
9cdcc59038 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:20:11 +02:00
6523fdf675 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:19:42 +02:00
d846856cb4 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:19:02 +02:00
94142f9ead srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:17:25 +02:00
8c93eab3a5 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:17:09 +02:00
ab6ecd773d srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:16:51 +02:00
970f7dbeb5 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:16:34 +02:00
19f6390e22 srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:16:08 +02:00
268800d31a srv/poe_manager/static/css/style.css aktualisiert 2025-10-12 19:14:41 +02:00
7b0c847e67 srv/poe_manager/app.py aktualisiert 2025-10-12 18:25:08 +02:00
007d9f919f revert 7c045a65b2
revert srv/poe_manager/templates/index.html aktualisiert
2025-10-12 18:24:13 +02:00
7c045a65b2 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:23:57 +02:00
98023092a2 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:23:16 +02:00
28fa9087a4 srv/poe_manager/app.py aktualisiert 2025-10-12 18:22:37 +02:00
804753dde8 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:20:53 +02:00
eaf2e2f78e srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:18:45 +02:00
50d5f58af4 srv/poe_manager/app.py aktualisiert 2025-10-12 18:18:08 +02:00
12d2511695 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:13:29 +02:00
3bd2aca4f5 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:11:26 +02:00
b6e9ff3f98 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:09:58 +02:00
398629eaaa srv/poe_manager/templates/index.html aktualisiert 2025-10-12 18:09:04 +02:00
3eb78b46a7 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 17:51:21 +02:00
681888a36a DB 2025-10-12 17:45:24 +02:00
e8df4f937b srv/poe_manager/templates/users.html aktualisiert 2025-10-12 17:43:58 +02:00
29823bb4ef srv/poe_manager/templates/switche.html aktualisiert 2025-10-12 17:43:46 +02:00
a2920a98bd srv/poe_manager/templates/devices.html aktualisiert 2025-10-12 17:43:12 +02:00
7f0871fa64 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 17:33:30 +02:00
5ae38a9e20 srv/poe_manager/app.py aktualisiert 2025-10-12 17:33:05 +02:00
de23b132ed srv/poe_manager/templates/index.html aktualisiert 2025-10-12 17:31:41 +02:00
746972e321 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 17:31:08 +02:00
dfba8789a7 srv/poe_manager/app.py aktualisiert 2025-10-12 17:28:05 +02:00
194e3cfbf9 srv/poe_manager/templates/index.html aktualisiert 2025-10-12 17:22:31 +02:00
8 changed files with 88 additions and 43 deletions

View File

@@ -4,6 +4,7 @@ from flask_login import LoginManager, login_user, login_required, logout_user, U
from flask_bcrypt import Bcrypt from flask_bcrypt import Bcrypt
from cryptography.fernet import Fernet from cryptography.fernet import Fernet
from datetime import datetime from datetime import datetime
from collections import defaultdict
import sqlite3, glob, os, re import sqlite3, glob, os, re
app = Flask(__name__) app = Flask(__name__)
@@ -104,9 +105,8 @@ def get_last_seen(dev_name: str):
continue continue
if latest_time: if latest_time:
date_str = latest_time.strftime("Zuletzt Online am %d.%m.%Y") datetime_str = latest_time.strftime("Zuletzt Online am %d.%m.%Y um %H:%M Uhr")
time_str = latest_time.strftime("um %H:%M Uhr") return f"{datetime_str}"
return f"{date_str}\n{time_str}"
return None return None
@@ -119,6 +119,13 @@ def index():
c.execute("SELECT mac, name, is_active FROM devices ORDER BY name ASC") c.execute("SELECT mac, name, is_active FROM devices ORDER BY name ASC")
devices = c.fetchall() devices = c.fetchall()
devices = sorted(devices, key=lambda d: d[1][0].upper())
grouped_devices = defaultdict(list)
for d in devices:
first_letter = d[1][:2].upper()
grouped_devices[first_letter].append(d)
# Intervall aus DB laden # Intervall aus DB laden
c.execute("SELECT value FROM settings WHERE key='interval'") c.execute("SELECT value FROM settings WHERE key='interval'")
row = c.fetchone() row = c.fetchone()
@@ -152,7 +159,7 @@ def index():
else: else:
status_dict[dev[0]] = "unbekannt" status_dict[dev[0]] = "unbekannt"
return render_template("index.html", devices=devices, status=status_dict, last_seen=last_seen_dict, interval=interval) return render_template("index.html", grouped_devices=grouped_devices, devices=devices, status=status_dict, last_seen=last_seen_dict, interval=interval)
@app.route("/settings", methods=["GET", "POST"]) @app.route("/settings", methods=["GET", "POST"])
@login_required @login_required

Binary file not shown.

View File

@@ -87,25 +87,33 @@ pre {
#log-container { #log-container {
position: relative; position: relative;
height: calc(100vh - 150px); /* Füllt die Seite minus Header */ height: calc(100vh - 252px); /* Füllt die Seite minus Header */
padding: 1rem; /* optional, Abstand innen */
box-sizing: border-box; /* damit Padding nicht die Höhe sprengt */
display: flex;
flex-direction: column;
} }
#log-box { #log-box {
height: 97%; flex: 1 1 auto; /* füllt den Container, berücksichtigt Header/Padding */
overflow: auto; overflow: auto;
white-space: pre-wrap; white-space: pre-wrap;
font-family: monospace; font-family: monospace;
border: 1px solid #dee2e6; /* Bootstrap-like border */ border: 1px solid #dee2e6;
padding: 1rem;
background-color: #f8f9fa; background-color: #f8f9fa;
padding: 0.5rem;
} }
#refresh-timer { #refresh-timer {
position: absolute; position: absolute;
bottom: 10px; bottom: 18px;
right: 10px; right: 30px;
font-size: 0.9em; font-size: 0.9em;
color: gray; color: gray;
background-color: rgba(255,255,255,0.7); /* optional, besser lesbar */
padding: 2px 4px;
border-radius: 3px;
pointer-events: none; /* damit Scrollbar nicht blockiert wird */
} }
/* Tabelle anpassen */ /* Tabelle anpassen */

View File

@@ -8,7 +8,7 @@
<button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#deviceModal" onclick="openDeviceModal()">Neues Gerät hinzufügen</button> <button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#deviceModal" onclick="openDeviceModal()">Neues Gerät hinzufügen</button>
{% endif %} {% endif %}
<table class="table table-bordered"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>Hostname</th> <th>Hostname</th>

View File

@@ -7,26 +7,34 @@
Nächste Prüfung in -- Sekunden Nächste Prüfung in -- Sekunden
</span> </span>
</h2> </h2>
<div class="row row-cols-1 row-cols-md-6 g-3"> <div class="row g-3">
{% for d in devices %} {% for letter, group in grouped_devices.items() %}
<div class="col"> <div class="row g-3">
<div class="card text-center p-2" {% for d in group %}
{% if last_seen[d[0]] %} title="{{ last_seen[d[0]][0] }}&#10;{{ last_seen[d[0]][1] }}" {% elif status[d[0]] == 'offline' %} title="Noch nie online" {% endif %}> <div class="col-6 col-md-4 col-lg-3 col-xl-2">
<div class="card-header">{{ d[1] }}</div> <div class="card text-center p-2"
<div class="card-body"> {% if last_seen.get(d[0]) %}
<span class="fw-bold" style="color: title="{{ last_seen[d[0]] }}"
{% if d[2] == 0 %}gray {% elif status[d[0]] == 'offline' %}
{% elif status[d[0]] == 'online' %}green title="Noch nie online"
{% else %}red {% endif %}>
{% endif %};"> <div class="card-header">{{ d[1] }}</div>
{% if d[2] == 0 %} <div class="card-body">
Deaktiviert <span class="fw-bold" style="color:
{% else %} {% if d[2] == 0 %}gray
{% if status[d[0]] %}{{ status[d[0]]|capitalize }}{% else %}Unbekannt{% endif %} {% elif status[d[0]] == 'online' %}green
{% endif %} {% else %}red
</span> {% endif %};">
{% if d[2] == 0 %}
Deaktiviert
{% else %}
{% if status[d[0]] %}{{ status[d[0]]|capitalize }}{% else %}Unbekannt{% endif %}
{% endif %}
</span>
</div>
</div> </div>
</div> </div>
{% endfor %}
</div> </div>
{% endfor %} {% endfor %}
</div> </div>

View File

@@ -5,7 +5,7 @@
<!-- Button zum Hinzufügen --> <!-- Button zum Hinzufügen -->
<button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#addSwitchModal">Neuen Switch hinzufügen</button> <button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#addSwitchModal">Neuen Switch hinzufügen</button>
<table class="table table-bordered"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>Hostname</th> <th>Hostname</th>

View File

@@ -8,7 +8,7 @@
<button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#userModal" onclick="openUserModal()">Neuen Benutzer</button> <button class="btn btn-success mb-3" data-bs-toggle="modal" data-bs-target="#userModal" onclick="openUserModal()">Neuen Benutzer</button>
{% endif %} {% endif %}
<table class="table table-bordered"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th class="col-ip">Username</th> <th class="col-ip">Username</th>

View File

@@ -87,23 +87,45 @@ EOF
echo "" > "$LOGFILE" echo "" > "$LOGFILE"
MAX_PARALLEL=10 # maximal gleichzeitig laufende Geräte
while true; do while true; do
echo "--------------------------------------------------------------------" >> "$LOGFILE" echo "--------------------------------------------------------------------" >> "$LOGFILE"
python3 /srv/poe_manager/generate_ips.py | while IFS=: read -r rpi_ip dev_name switch_ip switch_hostname switch_port switch_user switch_pass; do python3 /srv/poe_manager/generate_ips.py | while IFS=: read -r rpi_ip dev_name switch_ip switch_hostname switch_port switch_user switch_pass; do
if ping -c 1 -W 2 "$rpi_ip" &> /dev/null; then # Funktion für ein Gerät
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name ist erreichbar!" >> "$LOGFILE" check_device() {
else local rpi_ip="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name ist nicht erreichbar!" >> "$LOGFILE" local dev_name="$2"
local switch_ip="$3"
local switch_hostname="$4"
local switch_port="$5"
local switch_user="$6"
local switch_pass="$7"
# Nur PoE neu starten, wenn Port vorhanden ist if ping -c 4 -W 1 "$rpi_ip" &> /dev/null; then
if [ -n "$switch_port" ] && [ "$switch_port" != "None" ]; then echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name ist erreichbar!" >> "$LOGFILE"
disable_poe "$switch_ip" "$switch_port" "$switch_user" "$switch_pass" else
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name PoE auf Port $switch_port am Switch $switch_hostname deaktiviert." >> "$LOGFILE" echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name ist nicht erreichbar!" >> "$LOGFILE"
sleep 2
enable_poe "$switch_ip" "$switch_port" "$switch_user" "$switch_pass" if [ -n "$switch_port" ] && [ "$switch_port" != "None" ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name PoE auf Port $switch_port am Switch $switch_hostname aktiviert." >> "$LOGFILE" disable_poe "$switch_ip" "$switch_port" "$switch_user" "$switch_pass"
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name PoE auf Port $switch_port am Switch $switch_hostname deaktiviert." >> "$LOGFILE"
sleep 2
enable_poe "$switch_ip" "$switch_port" "$switch_user" "$switch_pass"
echo "$(date '+%Y-%m-%d %H:%M:%S') $dev_name PoE auf Port $switch_port am Switch $switch_hostname aktiviert." >> "$LOGFILE"
fi
fi fi
fi }
# Job in Hintergrund starten
check_device "$rpi_ip" "$dev_name" "$switch_ip" "$switch_hostname" "$switch_port" "$switch_user" "$switch_pass" &
# Limit auf MAX_PARALLEL Jobs
while [ "$(jobs -rp | wc -l)" -ge "$MAX_PARALLEL" ]; do
sleep 0.2
done
done done
wait # alle Hintergrundjobs beenden, bevor sleep
sleep "$SLEEP" sleep "$SLEEP"
done done