feat: Zentrale per Durchwahl selbst besetzen
Das Busylight im Empfangsbereich wird wechselnd besetzt. Mitarbeiter
koennen sich jetzt selbst darauf setzen, ohne Admin-Passwort.
- Neue Seite /zentrale (Durchwahl eingeben) und /zentrale/{durchwahl}
als Direktlink fuer QR-Codes. Der Direktlink zeigt nur an und aendert
nichts, damit Link-Vorschau und Prefetch niemanden versetzen.
- Neue Tabelle home_assignments merkt das eigene Tuerschild, solange der
Mitarbeiter in der Zentrale sitzt. Beim Verlassen wird es
wiederhergestellt, das Zentral-Segment wird freigegeben.
- Der Vorgaenger bleibt ohne Zuordnung - er ist nicht da. Sein gemerkter
Heimatplatz bleibt erhalten, er kann jederzeit zurueckkehren.
- Ist der Heimatplatz inzwischen belegt, wird die Rueckkehr abgelehnt
und nichts geaendert.
- Eine ausdrueckliche Admin-Zuordnung verwirft den gemerkten Heimatplatz.
Ein reines Loeschen der Zuordnung nicht, sonst kaeme niemand mehr von
der Zentrale zurueck.
- Farbe wird sofort ans Geraet geschickt (scheduler.push_user_light).
Das Polling allein reicht nicht: _process_user sendet nur bei einer
Statusaenderung, und beim Platzwechsel bleibt der Status gleich.
- Neue Settings selfservice_device_id und selfservice_segment,
einstellbar unter Einstellungen.
- Jeder Wechsel landet im Protokoll (zentrale / zentrale_frei).
Die Durchwahl ist eine Kennung, kein Geheimnis - im README dokumentiert.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -72,6 +72,67 @@ def get_color_for_status(status, conn):
|
||||
return {"r": 200, "g": 200, "b": 200, "effect": ""}
|
||||
|
||||
|
||||
def current_color_for_user(azure_id, conn):
|
||||
"""Farbe fuer den zuletzt gespeicherten Status eines Users.
|
||||
|
||||
Prioritaet wie im Polling und im Telefon-Webhook: Telefon > Teams > Zeiterfassung.
|
||||
Wer laut Zeiterfassung nicht anwesend/homeoffice ist, bekommt die abwesend-Farbe.
|
||||
"""
|
||||
row = conn.execute("""
|
||||
SELECT last_attendance_status, last_teams_status,
|
||||
COALESCE(phone_active, 0) as phone_active
|
||||
FROM state WHERE user_azure_id = ?
|
||||
""", (azure_id,)).fetchone()
|
||||
|
||||
attendance = (row["last_attendance_status"] or "") if row else ""
|
||||
teams = (row["last_teams_status"] or "") if row else ""
|
||||
phone_active = row["phone_active"] if row else 0
|
||||
|
||||
if attendance not in ("anwesend", "homeoffice"):
|
||||
return get_color_for_status("abwesend", conn)
|
||||
if phone_active:
|
||||
return get_color_for_status("phone_active", conn)
|
||||
if attendance == "homeoffice":
|
||||
return get_color_for_status("homeoffice", conn)
|
||||
if teams:
|
||||
return get_color_for_status(teams, conn)
|
||||
return get_color_for_status("available", conn)
|
||||
|
||||
|
||||
def push_user_light(azure_id, display_name, hostname, segment, conn, reason="zentrale"):
|
||||
"""Aktuelle Farbe eines Users sofort an WLED senden.
|
||||
|
||||
Wird beim Platzwechsel gebraucht: _process_user schickt nur bei einer
|
||||
Statusaenderung etwas ans Geraet, nach einem Wechsel ist der Status aber
|
||||
unveraendert. Ohne diesen Push wuerde das Segment die Farbe des Vorgaengers
|
||||
behalten, bis sich zufaellig etwas aendert.
|
||||
"""
|
||||
color = current_color_for_user(azure_id, conn)
|
||||
url = build_wled_url(
|
||||
hostname, color["r"], color["g"], color["b"],
|
||||
segment=segment, effect=color.get("effect", ""),
|
||||
)
|
||||
success, result_text = call_wled(url)
|
||||
log_activity(azure_id, display_name, reason, "-", url, result_text)
|
||||
if not success:
|
||||
logger.warning("WLED Fehler beim Platzwechsel fuer %s: %s", display_name, result_text)
|
||||
return success, result_text
|
||||
|
||||
|
||||
def clear_segment(hostname, segment, conn, reason="zentrale_frei"):
|
||||
"""Segment auf die abwesend-Farbe setzen (Standard ist 0,0,0 = aus)."""
|
||||
color = get_color_for_status("abwesend", conn)
|
||||
url = build_wled_url(
|
||||
hostname, color["r"], color["g"], color["b"],
|
||||
segment=segment, effect=color.get("effect", ""),
|
||||
)
|
||||
success, result_text = call_wled(url)
|
||||
log_activity(None, "-", reason, "-", url, result_text)
|
||||
if not success:
|
||||
logger.warning("WLED Fehler beim Freigeben von %s Segment %s: %s", hostname, segment, result_text)
|
||||
return success, result_text
|
||||
|
||||
|
||||
def poll_status():
|
||||
"""Main polling function - called periodically by APScheduler."""
|
||||
global graph
|
||||
|
||||
Reference in New Issue
Block a user