Christian Mueller ce19dec8c1 docs: rewrite README with Azure setup guide and troubleshooting
Also improve dashboard to show 'Warte auf Status...' instead of
gray bars when user is assigned but no polling result exists yet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 22:11:57 +02:00

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

  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

2. Oeffentliche Clientflows aktivieren

  1. In der erstellten App-Registrierung: Authentifizierung (linkes Menue)
  2. Ganz unten: Erweiterte Einstellungen
  3. Oeffentliche Clientflows zulassen -> Ja
  4. Speichern

3. API-Berechtigungen setzen

  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

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 --auth loescht 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
Description
Modulares Busylight WLED Controller System mit Plugin-System fuer Zeiterfassung
Readme 222 KiB
Languages
Python 48.9%
HTML 47.2%
Shell 2%
CSS 1.9%