From 6e6edd91db43e2bfaea8d1ea63306c1fbeaf1ba2 Mon Sep 17 00:00:00 2001 From: Christian Mueller Date: Sun, 3 May 2026 11:50:55 +0200 Subject: [PATCH] docs: README komplett ueberarbeitet - AIDA entfernt, modular - Alle AIDA-Referenzen durch "Zeiterfassung" ersetzt - Modulare Zeiterfassung dokumentiert (CSV + REST API) - Azure-Einrichtung auf Webbasierte Auth aktualisiert - Verweis auf detaillierte Azure-Anleitung - Projektstruktur und Installer ergaenzt Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 321 +++++++++++++++++------------------------------------- 1 file changed, 102 insertions(+), 219 deletions(-) diff --git a/README.md b/README.md index 0421c2b..fa1aff2 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,40 @@ # Busylight WLED Controller -Web-Anwendung zur Steuerung von WLED-Busylights basierend auf Microsoft Teams Presence-Status, AIDA-Zeiterfassung und Telefonanlage (Webhook). +Web-Anwendung zur Steuerung von WLED-Busylights basierend auf Microsoft Teams Presence-Status, Zeiterfassung und Telefonanlage (Webhook). -Jedes WLED-Geraet verfuegt ueber zwei Segmente (oben/unten), die jeweils einem Benutzer zugeordnet werden. Die Farbe des Segments wird automatisch anhand des Anwesenheitsstatus (AIDA), des Teams-Status und des Telefonstatus gesetzt. +Jedes WLED-Geraet verfuegt ueber zwei Segmente (oben/unten), die jeweils einem Benutzer zugeordnet werden. Die Farbe des Segments wird automatisch anhand des Anwesenheitsstatus, des Teams-Status und des Telefonstatus gesetzt. ## Features -- **Dashboard** mit Echtzeit-Uebersicht aller Busylights (AIDA-, Teams- und Telefon-Status als Badges) -- **Benutzer-Verwaltung** mit automatischem Sync aus Azure AD +- **Dashboard** mit Echtzeit-Uebersicht aller Busylights (Zeiterfassungs-, Teams- und Telefon-Status als Badges) +- **Benutzer-Verwaltung** mit automatischem Sync aus Microsoft Entra ID (Azure AD) - **WLED-Geraete** hinzufuegen, bearbeiten, entfernen mit automatischem Status-Check (online/offline, LED-Anzahl, Firmware) - **Zuordnung** von Benutzern zu WLED-Segmenten per Dropdown - **Farb-Regeln** mit Color-Picker fuer jeden Status - **Telefon-Webhook** fuer Telefonanlage (callstart/callend auf Port 8081) -- **Einstellungen** fuer Azure AD, Polling-Intervall und AIDA-CSV-Pfad +- **Modulare Zeiterfassung** per CSV oder REST API - kompatibel mit jeder Zeiterfassung +- **Webbasierte Azure-Authentifizierung** direkt im Browser (kein Terminal noetig) +- **Einstellungen** fuer Azure, Polling-Intervall und Zeiterfassung - **Protokoll** der letzten Statusaenderungen ## Funktionsweise | Quelle | Beschreibung | Auswirkung auf WLED | |--------|-------------|---------------------| -| AIDA Zeiterfassung | Anwesend / Abwesend / Homeoffice | Grundfarbe (gruen / aus / gelb) | +| Zeiterfassung | Anwesend / Abwesend / Homeoffice | Grundfarbe (gruen / aus / gelb) | | Microsoft Teams | Verfuegbar / Beschaeftigt / Nicht stoeren / etc. | Farbe wenn anwesend | -| Telefonanlage (Webhook) | Telefoniert / Frei | Rot wenn aktiv, danach zurueck auf AIDA-Status | +| Telefonanlage (Webhook) | Telefoniert / Frei | Rot wenn aktiv, danach zurueck auf Zeiterfassungs-Status | -**Prioritaet:** Telefon > Teams > AIDA. Die WLED-Farbe wird nur gesetzt wenn der Mitarbeiter laut AIDA anwesend oder im Homeoffice ist. +**Prioritaet:** Telefon > Teams > Zeiterfassung. Die WLED-Farbe wird nur gesetzt wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist. ## Voraussetzungen -- Linux-Server (Debian 12+/Ubuntu 22.04+) +- Linux-Server (Debian 13+ empfohlen) - Python 3.10+ - Netzwerkzugriff auf die WLED-Geraete (HTTP Port 80) -- Azure AD App-Registrierung (siehe unten) -- Zugriff auf die AIDA-Zeiterfassungs-CSV (lokal oder per SMB-Mount) -- Optional: Telefonanlage mit Webhook-Unterstuetzung +- Microsoft Entra ID App-Registrierung (siehe [Azure-Einrichtung](docs/azure-einrichtung.md)) +- Optional: Zeiterfassung per CSV oder REST API +- Optional: Telefonanlage mit Webhook-Unterstuetzung (z.B. Starface) ## Installation @@ -57,156 +59,99 @@ source venv/bin/activate pip install -r requirements.txt ``` -## Azure AD einrichten +## Einrichtung -### 1. App-Registrierung erstellen +### 1. Azure verbinden -1. Azure Portal oeffnen: https://portal.azure.com -2. **Azure Active Directory** -> **App-Registrierungen** -> **Neue Registrierung** -3. Einstellungen: - - **Name**: `Busylight Web` (oder beliebig) - - **Unterstuetzte Kontotypen**: Nur Konten in diesem Organisationsverzeichnis - - **Umleitungs-URI**: leer lassen -4. **Registrieren** klicken +Detaillierte Anleitung: [docs/azure-einrichtung.md](docs/azure-einrichtung.md) -### 2. Oeffentliche Clientflows aktivieren +Kurzfassung: +1. App-Registrierung in Azure erstellen +2. Oeffentliche Clientflows aktivieren +3. API-Berechtigungen setzen (User.Read.All, Presence.Read.All) +4. Im Web-Interface unter **Einstellungen** die IDs eintragen +5. Auf **"Mit Azure verbinden"** klicken und im Browser anmelden -1. In der erstellten App-Registrierung: **Authentifizierung** (linkes Menue) -2. Ganz unten: **Erweiterte Einstellungen** -3. **Oeffentliche Clientflows zulassen** -> **Ja** -4. **Speichern** +### 2. Benutzer synchronisieren -### 3. API-Berechtigungen setzen +Unter **Benutzer** auf "Aus Azure synchronisieren" klicken. Anschliessend: +- Benutzer aktivieren/deaktivieren (nur aktive Benutzer werden abgefragt) +- Personalnummer zuordnen (fuer Zeiterfassung) +- Telefon-Durchwahl zuordnen (fuer Starface-Webhook) -1. **API-Berechtigungen** -> **Berechtigung hinzufuegen** -> **Microsoft Graph** -2. **Delegierte Berechtigungen** waehlen -3. Folgende Berechtigungen hinzufuegen: - - `User.Read` - - `User.Read.All` - - `Presence.Read` - - `Presence.Read.All` -4. **Administratorzustimmung erteilen** klicken +### 3. WLED-Geraete anlegen -### 4. IDs notieren +Unter **Tuerschilder** die Hostnamen/IP-Adressen der WLED-Busylights eintragen. +Der Status (online/offline, LEDs, Firmware) wird automatisch alle 4 Minuten geprueft. -Von der Uebersichtsseite der App-Registrierung: -- **Anwendungs-ID (Client)** -> das ist die `Client ID` -- **Verzeichnis-ID (Mandant)** -> das ist die `Tenant ID` +### 4. Zuordnungen erstellen -### 5. Credentials in Busylight eintragen +Unter **Zuordnungen** jeden aktiven Benutzer einem WLED-Geraet und Segment zuweisen: +- Segment 0 = unten +- Segment 1 = oben -Entweder ueber das Web-Interface unter **Einstellungen**, oder per CLI: +### 5. Farben anpassen -```bash -cd /opt/busylight && source venv/bin/activate -python -c " -from database import init_db, set_setting -init_db() -set_setting('azure_client_id', 'DEINE-CLIENT-ID') -set_setting('azure_tenant_id', 'DEINE-TENANT-ID') -set_setting('azure_auth_tenant', 'DEINE-TENANT-ID') -" -``` +Unter **Farb-Regeln** die Farben fuer jeden Status per Color-Picker anpassen: -### 6. Azure Authentifizierung durchfuehren +| Status | Beschreibung | +|--------|-------------| +| `abwesend` | Benutzer nicht anwesend | +| `homeoffice` | Benutzer im Homeoffice | +| `phone_active` | Benutzer telefoniert (Webhook) | +| `teams_available` | Teams: Verfuegbar | +| `teams_busy` | Teams: Beschaeftigt | +| `teams_donotdisturb` | Teams: Nicht stoeren | +| `teams_inacall` | Teams: In einem Anruf | +| `teams_inameeting` | Teams: In einer Besprechung | +| `teams_presenting` | Teams: Praesentiert | +| `teams_away` | Teams: Abwesend | +| `teams_offline` | Teams: Offline | +| `teams_outofoffice` | Teams: Abwesend (ganztaegig) | +| `teams_inactive` | Teams: Inaktiv | +| `teams_offwork` | Teams: Nicht bei der Arbeit | -Die Authentifizierung erfolgt einmalig ueber den Device-Code-Flow im Terminal. -Um den Device-Code sauber angezeigt zu bekommen (ohne Azure-Debug-Logs): +## Zeiterfassung -```bash -cd /opt/busylight && source venv/bin/activate -python -W ignore -c " -import logging -logging.getLogger('azure').setLevel(logging.WARNING) -from app import cli_auth -cli_auth() -" -``` +Die Zeiterfassung ist modular - es gibt zwei Wege den Anwesenheitsstatus zu liefern: -Es wird ein Code angezeigt, z.B.: +### Option A: CSV-Datei + +Eine CSV-Datei mit dem Anwesenheitsstatus wird periodisch gelesen. Das Format: ``` -To sign in, use a web browser to open the page https://microsoft.com/devicelogin -and enter the code LW5ZR5BFC to authenticate. +~~00100~~,~~1~~ +~~00101~~,~~0~~ +~~00102~~,~~2~~ ``` -Diesen Code im Browser eingeben und mit einem Azure-AD-Konto anmelden. -Nach erfolgreicher Anmeldung wird das Token in der Datenbank gespeichert und automatisch erneuert. - -## Migration von der alten config.cfg - -Falls das System vorher mit dem alten Python-Script und `config.cfg` betrieben wurde, -koennen alle Daten (User, Geraete, Segmente, Farben) automatisch importiert werden: - -```bash -# config.cfg ins Projektverzeichnis kopieren -cp /pfad/zur/alten/config.cfg . - -# Migration ausfuehren -python migrate.py -``` - -Die alte `config.cfg` wird danach nicht mehr benoetigt. - -## AIDA-CSV bereitstellen - -Die Zeiterfassungs-CSV liegt typischerweise auf einem Windows-Server (z.B. `\\192.168.30.224\export`). - -### Option A: Lokale Kopie - -Die CSV-Datei direkt auf den Server kopieren (z.B. per Cronjob/rsync): - -```bash -# CSV-Pfad in den Web-Einstellungen eintragen: -/opt/busylight/Status.csv -``` - -### Option B: SMB/CIFS-Mount - -```bash -# Paket installieren -sudo apt install cifs-utils - -# Mount-Punkt und Credentials erstellen -sudo mkdir -p /mnt/aida -sudo bash -c 'cat > /etc/samba/creds << EOF -username=BENUTZER -password=PASSWORT -domain=DOMAIN -EOF' -sudo chmod 600 /etc/samba/creds - -# Eintrag in /etc/fstab (eine Zeile) -# //192.168.30.224/export /mnt/aida cifs credentials=/etc/samba/creds,ro 0 0 - -# Mounten -sudo mount /mnt/aida -``` - -**Hinweis:** In LXC-Containern (Proxmox) muss CIFS-Mount erst in den Container-Features aktiviert werden. - -In den Web-Einstellungen dann als CSV-Pfad eintragen: -``` -/mnt/aida/Status.csv -``` - -### CSV-Format - -Die AIDA-CSV hat folgendes Format (eine Zeile pro Mitarbeiter): -``` -~~00341~~,~~1~~ -~~00412~~,~~0~~ -~~00433~~,~~2~~ -``` - -Dabei bedeuten die Status-Codes (konfigurierbar in den Einstellungen): +Status-Codes (konfigurierbar in den Einstellungen): - `~~0~~` = Abwesend - `~~1~~` = Anwesend - `~~2~~` = Homeoffice +Die CSV kann von jedem Zeiterfassungssystem per Script erzeugt werden. +In den **Einstellungen** den Pfad zur CSV eintragen. + +### Option B: REST API + +Externe Systeme koennen den Status direkt per API setzen (Port 8081): + +```bash +# Status setzen +curl -X POST -H "Content-Type: application/json" \ + -d '{"status":"anwesend"}' \ + http://SERVER:8081/api/attendance/00100 + +# Alle Status abfragen +curl http://SERVER:8081/api/attendance +``` + +Beide Optionen koennen parallel genutzt werden. + ## Telefonanlage (Webhook) -Die Anwendung startet automatisch einen Webhook-Server auf **Port 8081** fuer die Anbindung einer Telefonanlage. +Die Anwendung startet automatisch einen Webhook-Server auf **Port 8081** fuer die Anbindung einer Telefonanlage (z.B. Starface). ### Webhook-Endpoints @@ -215,8 +160,6 @@ GET/POST http://SERVER:8081/{durchwahl}/callstart - Anruf gestartet (WLED -> GET/POST http://SERVER:8081/{durchwahl}/callend - Anruf beendet (WLED -> zurueck auf Zeiterfassungs-Status) ``` -Die Info-Seite unter `http://SERVER:8081/` zeigt eine Uebersicht der Endpoints. - ### Einrichtung 1. Unter **Benutzer** im Web-Interface die **Durchwahl** pro User eintragen (z.B. `123`) @@ -226,8 +169,8 @@ Die Info-Seite unter `http://SERVER:8081/` zeigt eine Uebersicht der Endpoints. ### Verhalten -- `callstart`: Setzt WLED auf Telefon-Farbe (Standard: Rot), aber **nur** wenn der Mitarbeiter laut AIDA anwesend oder im Homeoffice ist -- `callend`: Setzt WLED zurueck auf den AIDA-Status (anwesend=gruen, homeoffice=gelb). Der Teams-Status wird beim naechsten Polling-Zyklus (15s) automatisch aktualisiert +- `callstart`: Setzt WLED auf Telefon-Farbe (Standard: Rot), aber **nur** wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist +- `callend`: Setzt WLED zurueck auf den Zeiterfassungs-Status. Der Teams-Status wird beim naechsten Polling-Zyklus (15s) automatisch aktualisiert - Waehrend eines aktiven Telefonats ueberschreibt das Teams-Polling die Farbe nicht - Die Telefon-Farbe (`phone_active`) ist unter **Farb-Regeln** konfigurierbar @@ -243,12 +186,12 @@ python app.py Dabei werden zwei Server gestartet: - **Port 8080**: Web-Oberflaeche -- **Port 8081**: Webhook-Server fuer Telefonanlage +- **Port 8081**: Webhook-Server (Telefonanlage + Zeiterfassungs-API) ### Als systemd-Service (Produktivbetrieb) ```bash -# Service installieren +# Service installieren (bei manueller Installation) sudo cp busylight.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now busylight @@ -259,101 +202,43 @@ sudo systemctl status busylight # Logs anzeigen sudo journalctl -u busylight -f -# Neustart nach Updates +# Update cd /opt/busylight && git pull sudo systemctl restart busylight ``` -## Benutzung - -### 1. Einstellungen konfigurieren - -Unter **Einstellungen** die Azure AD Credentials (Client ID, Tenant ID) und den AIDA-CSV-Pfad eintragen. - -### 2. Benutzer synchronisieren - -Unter **Benutzer** auf "Aus Azure synchronisieren" klicken. Alle Azure AD Benutzer werden importiert. Anschliessend: -- Benutzer aktivieren/deaktivieren (nur aktive Benutzer werden abgefragt) -- AIDA-Personalnummer zuordnen (Format: `~~00341~~`) -- Telefon-Durchwahl zuordnen (z.B. `123`) - -### 3. WLED-Geraete anlegen - -Unter **WLED-Geraete** die Hostnamen/IP-Adressen der WLED-Busylights eintragen. -Der Status (online/offline, LEDs, Firmware) wird automatisch alle 4 Minuten geprueft. - -### 4. Zuordnungen erstellen - -Unter **Zuordnungen** jeden aktiven Benutzer einem WLED-Geraet und Segment zuweisen: -- Segment 0 = unten -- Segment 1 = oben - -### 5. Farben anpassen - -Unter **Farb-Regeln** die Farben fuer jeden Status per Color-Picker anpassen: - -| Status | Beschreibung | -|--------|-------------| -| `abwesend` | Benutzer laut AIDA nicht anwesend | -| `homeoffice` | Benutzer im Homeoffice | -| `phone_active` | Benutzer telefoniert (Webhook) | -| `teams_available` | Teams: Verfuegbar | -| `teams_busy` | Teams: Beschaeftigt | -| `teams_donotdisturb` | Teams: Nicht stoeren | -| `teams_inacall` | Teams: In einem Anruf | -| `teams_inameeting` | Teams: In einer Besprechung | -| `teams_presenting` | Teams: Praesentiert | -| `teams_away` | Teams: Abwesend | -| `teams_offline` | Teams: Offline | -| `teams_outofoffice` | Teams: Abwesend (ganztaegig) | -| `teams_inactive` | Teams: Inaktiv | -| `teams_offwork` | Teams: Nicht bei der Arbeit | - -### 6. Dashboard +## Dashboard Das **Dashboard** zeigt alle Busylights mit dem aktuellen Status in Echtzeit an und aktualisiert sich automatisch alle 10 Sekunden. Pro Benutzer werden drei Status-Badges angezeigt: -- **AIDA**: Anwesend (gruen) / Abwesend (grau) / Homeoffice (gelb) +- **Zeiterfassung**: Anwesend (gruen) / Abwesend (grau) / Homeoffice (gelb) - **Teams**: Verfuegbar / Beschaeftigt / Nicht stoeren / Offline / etc. - **Telefon**: Telefoniert (rot) / Frei (grau) -### 7. Protokoll - -Unter **Protokoll** werden die letzten 200 Statusaenderungen mit Zeitstempel, WLED-URL und Ergebnis angezeigt. - ## Hintergrund-Jobs -Die Anwendung fuehrt automatisch folgende Jobs im Hintergrund aus: - | Job | Intervall | Beschreibung | |-----|-----------|-------------| -| Status-Polling | 15 Sekunden (konfigurierbar) | Teams-Presence und AIDA-Status abfragen, WLED aktualisieren | +| Status-Polling | 15 Sekunden (konfigurierbar) | Teams-Presence und Zeiterfassungs-Status abfragen, WLED aktualisieren | | Device-Check | 240 Sekunden | Alle WLED-Geraete auf Erreichbarkeit pruefen | ## Projektstruktur ``` busylight/ -├── app.py # FastAPI Web-Anwendung + CLI Auth + Startup -├── webhook.py # Webhook-Server fuer Telefonanlage (Port 8081) +├── app.py # FastAPI Web-Anwendung + Azure Auth + Startup +├── webhook.py # Webhook-Server + Zeiterfassungs-API (Port 8081) ├── database.py # SQLite Datenbank-Schema und Hilfsfunktionen ├── graph_client.py # Microsoft Graph API Client ├── wled_client.py # WLED HTTP API Client ├── scheduler.py # Hintergrund-Jobs (Polling + Device-Check) -├── migrate.py # Import aus alter config.cfg +├── install.sh # Installer fuer Debian 13 ├── requirements.txt # Python-Abhaengigkeiten ├── busylight.service # systemd Service-Datei +├── docs/ # Dokumentation ├── static/ │ └── style.css # CSS Styles -└── templates/ - ├── base.html # Basis-Layout mit Sidebar - ├── dashboard.html # Status-Uebersicht - ├── users.html # Benutzer-Verwaltung - ├── devices.html # WLED-Geraete-Verwaltung - ├── assignments.html # Zuordnungen User -> Segment - ├── colors.html # Farb-Regeln - ├── settings.html # Einstellungen - └── log.html # Aktivitaets-Protokoll +└── templates/ # Jinja2 HTML-Templates ``` ## Ports und Firewall @@ -361,35 +246,33 @@ busylight/ | Port | Richtung | Zweck | |------|----------|-------| | 8080/tcp | Eingehend | Web-Oberflaeche | -| 8081/tcp | Eingehend | Webhook-API fuer Telefonanlage | +| 8081/tcp | Eingehend | Webhook-API (Telefon + Zeiterfassung) | | 80/tcp | Ausgehend | WLED HTTP API | | 443/tcp | Ausgehend | Microsoft Graph API | ## Troubleshooting ### Dashboard zeigt nur graue Segmente -- AIDA-CSV-Pfad in den Einstellungen pruefen (muss auf dem Linux-Server erreichbar sein) +- Zeiterfassung pruefen (CSV-Pfad oder API-Status) - Benutzer muessen aktiviert sein UND eine Personalnummer haben - Zuordnung Benutzer -> WLED-Geraet + Segment muss vorhanden sein ### Teams-Status wird nicht angezeigt -- Teams-Status wird immer abgefragt, auch ohne AIDA - Azure-Authentifizierung pruefen (Sidebar zeigt "Azure verbunden") - API-Berechtigungen in Azure pruefen (Presence.Read.All) ### Telefon-Webhook reagiert nicht - Port 8081 erreichbar? `curl http://SERVER:8081/` - Durchwahl beim Benutzer eingetragen? -- Benutzer muss laut AIDA anwesend oder im Homeoffice sein +- Benutzer muss laut Zeiterfassung anwesend oder im Homeoffice sein ### Azure Auth schlaegt fehl - "Oeffentliche Clientflows zulassen" muss in der Azure App aktiviert sein -- Auth-Tenant muss die Tenant-ID sein (nicht "common"), wenn die App auf "Nur meine Organisation" steht -- Bei erneutem Auth: `python app.py --auth` loescht automatisch den alten Token +- Siehe [docs/azure-einrichtung.md](docs/azure-einrichtung.md) fuer Details ### WLED-Geraete offline -- Unter WLED-Geraete den Status pruefen (Wifi-Button oder "Alle jetzt pruefen") -- Netzwerkverbindung vom Linux-Server zu den WLED-Geraeten pruefen: `curl http://HOSTNAME/json/info` +- Unter Tuerschilder den Status pruefen ("Alle jetzt pruefen") +- Netzwerkverbindung pruefen: `curl http://HOSTNAME/json/info` -### Nach git pull aendern sich nichts +### Nach git pull aendert sich nichts - Service neustarten: `sudo systemctl restart busylight`