- Add online, leds, version, last_check columns to wled_devices table - Background job checks all WLED devices every 4 minutes - Initial check on startup - Devices page reads status from DB (instant page load) - 'Alle jetzt pruefen' button triggers manual check Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Busylight WLED Controller
Web-Anwendung zur Steuerung von WLED-Busylights basierend auf Microsoft Teams Presence-Status und AIDA-Zeiterfassung.
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) und des Teams-Status gesetzt.
Features
- Dashboard mit Echtzeit-Uebersicht aller Busylights und deren aktuellem Status
- Benutzer-Verwaltung mit automatischem Sync aus Azure AD
- WLED-Geraete hinzufuegen, bearbeiten, entfernen und Live-Status pruefen (online/offline, LED-Anzahl, Firmware-Version)
- Zuordnung von Benutzern zu WLED-Segmenten per Dropdown (statt UUID-Mapping in einer Config-Datei)
- Farb-Regeln mit Color-Picker fuer jeden Teams-/Anwesenheitsstatus
- Einstellungen fuer Azure AD, Polling-Intervall und AIDA-CSV-Pfad
- Protokoll der letzten Statusaenderungen
Voraussetzungen
- Linux-Server (Debian 12+/Ubuntu 22.04+)
- 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)
Installation
# Repository klonen
git clone https://git.cynfo.net/christian/busylight.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
Azure AD einrichten
1. App-Registrierung erstellen
- Azure Portal oeffnen: https://portal.azure.com
- Azure Active Directory -> App-Registrierungen -> Neue Registrierung
- Einstellungen:
- Name:
Busylight Web(oder beliebig) - Unterstuetzte Kontotypen: Nur Konten in diesem Organisationsverzeichnis
- Umleitungs-URI: leer lassen
- Name:
- Registrieren klicken
2. Oeffentliche Clientflows aktivieren
- In der erstellten App-Registrierung: Authentifizierung (linkes Menue)
- Ganz unten: Erweiterte Einstellungen
- Oeffentliche Clientflows zulassen -> Ja
- Speichern
3. API-Berechtigungen setzen
- API-Berechtigungen -> Berechtigung hinzufuegen -> Microsoft Graph
- Delegierte Berechtigungen waehlen
- Folgende Berechtigungen hinzufuegen:
User.ReadUser.Read.AllPresence.ReadPresence.Read.All
- Administratorzustimmung erteilen klicken
4. IDs notieren
Von der Uebersichtsseite der App-Registrierung:
- Anwendungs-ID (Client) -> das ist die
Client ID - Verzeichnis-ID (Mandant) -> das ist die
Tenant ID
5. Credentials in Busylight eintragen
Entweder ueber das Web-Interface unter Einstellungen, oder per CLI:
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')
"
6. Azure Authentifizierung durchfuehren
Die Authentifizierung erfolgt einmalig ueber den Device-Code-Flow im Terminal. Um den Device-Code sauber angezeigt zu bekommen (ohne Azure-Debug-Logs):
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()
"
Es wird ein Code angezeigt, z.B.:
To sign in, use a web browser to open the page https://microsoft.com/devicelogin
and enter the code LW5ZR5BFC to authenticate.
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:
# 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 auf Linux bereitstellen
Die Zeiterfassungs-CSV liegt typischerweise auf einem Windows-Server. Fuer den Zugriff von Linux empfiehlt sich ein SMB/CIFS-Mount:
# Paket installieren
sudo apt install cifs-utils
# Mount-Punkt erstellen
sudo mkdir -p /mnt/zeiterfassung
# Credentials-Datei erstellen
sudo bash -c 'cat > /etc/samba/creds << EOF
username=DOMAIN\user
password=geheim
EOF'
sudo chmod 600 /etc/samba/creds
# Eintrag in /etc/fstab (eine Zeile)
# //SERVERNAME/Zeiterfassung /mnt/zeiterfassung cifs credentials=/etc/samba/creds,uid=busylight,gid=busylight,ro 0 0
# Mounten
sudo mount /mnt/zeiterfassung
In den Web-Einstellungen dann als CSV-Pfad eintragen:
/mnt/zeiterfassung/Aida/profiles/aida/Transfer/Export/Status.csv
Alternativ: Per Cronjob die CSV regelmaessig per scp oder rsync kopieren.
Starten
Manuell (zum Testen)
cd /opt/busylight
source venv/bin/activate
python app.py
Die Web-Oberflaeche ist dann erreichbar unter: http://SERVER-IP:8080
Als systemd-Service (Produktivbetrieb)
# Service-User anlegen
sudo useradd -r -s /usr/sbin/nologin busylight
sudo chown -R busylight:busylight /opt/busylight
# Service installieren
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
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~~)
3. WLED-Geraete anlegen
Unter WLED-Geraete die Hostnamen/IP-Adressen der WLED-Busylights eintragen. Die Seite zeigt automatisch den Online-Status, LED-Anzahl und Firmware-Version jedes Geraets an.
4. Zuordnungen erstellen
Unter Zuordnungen jeden aktiven Benutzer einem WLED-Geraet und Segment zuweisen:
- Segment 0 = oben
- Segment 1 = unten
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 |
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
Das Dashboard zeigt alle Busylights mit dem aktuellen Status in Echtzeit an und aktualisiert sich automatisch alle 10 Sekunden.
- Farbige Segmente = Status wurde erfolgreich abgefragt
- Graue Segmente mit "Warte auf Status..." = Zuordnung vorhanden, aber noch kein Polling-Ergebnis (z.B. AIDA-CSV nicht erreichbar)
- "Nicht zugeordnet" = kein Benutzer diesem Segment zugewiesen
7. Protokoll
Unter Protokoll werden die letzten 200 Statusaenderungen mit Zeitstempel, WLED-URL und Ergebnis angezeigt.
Projektstruktur
busylight/
├── app.py # FastAPI Web-Anwendung + CLI Auth
├── database.py # SQLite Datenbank-Schema und Hilfsfunktionen
├── graph_client.py # Microsoft Graph API Client
├── wled_client.py # WLED HTTP API Client
├── scheduler.py # Hintergrund-Polling (AIDA + Teams -> WLED)
├── migrate.py # Import aus alter config.cfg
├── requirements.txt # Python-Abhaengigkeiten
├── busylight.service # systemd Service-Datei
├── 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
Ports und Firewall
| Port | Richtung | Zweck |
|---|---|---|
| 8080/tcp | Eingehend | Web-Oberflaeche |
| 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)
- Benutzer muessen aktiviert sein UND eine Personalnummer haben
- Zuordnung Benutzer -> WLED-Geraet + Segment muss vorhanden 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 --authloescht automatisch den alten Token
WLED-Geraete offline
- Unter WLED-Geraete den Status pruefen (Wifi-Button)
- Netzwerkverbindung vom Linux-Server zu den WLED-Geraeten pruefen:
curl http://HOSTNAME/json/info