# Busylight WLED Controller 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, des Teams-Status und des Telefonstatus gesetzt. ## Features - **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) - **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 | |--------|-------------|---------------------| | 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 Zeiterfassungs-Status | **Prioritaet:** Telefon > Teams > Zeiterfassung. Die WLED-Farbe wird nur gesetzt wenn der Mitarbeiter laut Zeiterfassung anwesend oder im Homeoffice ist. ## Voraussetzungen - Linux-Server (Debian 13+ empfohlen) - Python 3.10+ - Netzwerkzugriff auf die WLED-Geraete (HTTP Port 80) - 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 ### Schnellinstallation (Debian 13) ```bash curl -s https://git.cynfo.net/christian/busylight_modular/raw/branch/master/install.sh | bash ``` ### Manuelle Installation ```bash # Repository klonen git clone https://git.cynfo.net/christian/busylight_modular.git /opt/busylight cd /opt/busylight # Python Virtual Environment erstellen python3 -m venv venv source venv/bin/activate # Abhaengigkeiten installieren pip install -r requirements.txt ``` ## Einrichtung ### 1. Azure verbinden Detaillierte Anleitung: [docs/azure-einrichtung.md](docs/azure-einrichtung.md) 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 ### 2. Benutzer synchronisieren 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) ### 3. WLED-Geraete anlegen Unter **Tuerschilder** 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 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 | ## Zeiterfassung Die Zeiterfassung ist modular - es gibt zwei Wege den Anwesenheitsstatus zu liefern: ### Option A: CSV-Datei Eine CSV-Datei mit dem Anwesenheitsstatus wird periodisch gelesen. Das Format: ``` ~~00100~~,~~1~~ ~~00101~~,~~0~~ ~~00102~~,~~2~~ ``` 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 (z.B. Starface). ### Webhook-Endpoints ``` GET/POST http://SERVER:8081/{durchwahl}/callstart - Anruf gestartet (WLED -> Rot) GET/POST http://SERVER:8081/{durchwahl}/callend - Anruf beendet (WLED -> zurueck auf Zeiterfassungs-Status) ``` ### Einrichtung 1. Unter **Benutzer** im Web-Interface die **Durchwahl** pro User eintragen (z.B. `123`) 2. In der Telefonanlage den Webhook konfigurieren: - Anrufbeginn: `http://SERVER-IP:8081/123/callstart` - Anrufende: `http://SERVER-IP:8081/123/callend` ### Verhalten - `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 ## Starten ### Manuell (zum Testen) ```bash cd /opt/busylight source venv/bin/activate python app.py ``` Dabei werden zwei Server gestartet: - **Port 8080**: Web-Oberflaeche - **Port 8081**: Webhook-Server (Telefonanlage + Zeiterfassungs-API) ### Als systemd-Service (Produktivbetrieb) ```bash # Service installieren (bei manueller Installation) sudo cp busylight.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now busylight # Status pruefen sudo systemctl status busylight # Logs anzeigen sudo journalctl -u busylight -f # Update cd /opt/busylight && git pull sudo systemctl restart busylight ``` ## 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: - **Zeiterfassung**: Anwesend (gruen) / Abwesend (grau) / Homeoffice (gelb) - **Teams**: Verfuegbar / Beschaeftigt / Nicht stoeren / Offline / etc. - **Telefon**: Telefoniert (rot) / Frei (grau) ## Hintergrund-Jobs | Job | Intervall | Beschreibung | |-----|-----------|-------------| | 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 + 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) ├── install.sh # Installer fuer Debian 13 ├── requirements.txt # Python-Abhaengigkeiten ├── busylight.service # systemd Service-Datei ├── docs/ # Dokumentation ├── static/ │ └── style.css # CSS Styles └── templates/ # Jinja2 HTML-Templates ``` ## Ports und Firewall | Port | Richtung | Zweck | |------|----------|-------| | 8080/tcp | Eingehend | Web-Oberflaeche | | 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 - 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 - 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 Zeiterfassung anwesend oder im Homeoffice sein ### Azure Auth schlaegt fehl - "Oeffentliche Clientflows zulassen" muss in der Azure App aktiviert sein - Siehe [docs/azure-einrichtung.md](docs/azure-einrichtung.md) fuer Details ### WLED-Geraete offline - Unter Tuerschilder den Status pruefen ("Alle jetzt pruefen") - Netzwerkverbindung pruefen: `curl http://HOSTNAME/json/info` ### Nach git pull aendert sich nichts - Service neustarten: `sudo systemctl restart busylight`