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>
298 lines
9.4 KiB
Markdown
298 lines
9.4 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```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')
|
|
"
|
|
```
|
|
|
|
### 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):
|
|
|
|
```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()
|
|
"
|
|
```
|
|
|
|
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:
|
|
|
|
```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 auf Linux bereitstellen
|
|
|
|
Die Zeiterfassungs-CSV liegt typischerweise auf einem Windows-Server.
|
|
Fuer den Zugriff von Linux empfiehlt sich ein SMB/CIFS-Mount:
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
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)
|
|
|
|
```bash
|
|
# 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`
|