diff --git a/README.md b/README.md index f0b3260..7b5c06c 100644 --- a/README.md +++ b/README.md @@ -2,24 +2,24 @@ Web-Anwendung zur Steuerung von WLED-Busylights basierend auf Microsoft Teams Presence-Status und AIDA-Zeiterfassung. -Jedes WLED-Gerät verfügt über 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. +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-Übersicht aller Busylights und deren aktuellem Status +- **Dashboard** mit Echtzeit-Uebersicht aller Busylights und deren aktuellem Status - **Benutzer-Verwaltung** mit automatischem Sync aus Azure AD -- **WLED-Geräte** hinzufügen, bearbeiten und entfernen +- **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 für jeden Teams-/Anwesenheitsstatus -- **Einstellungen** für Azure AD, Polling-Intervall und AIDA-CSV-Pfad -- **Protokoll** der letzten Statusänderungen +- **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-Geräte (HTTP) -- Azure AD App-Registrierung mit folgenden Berechtigungen: - - `User.Read`, `User.Read.All`, `Presence.Read`, `Presence.Read.All` +- 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 @@ -33,40 +33,105 @@ cd /opt/busylight python3 -m venv venv source venv/bin/activate -# Abhängigkeiten installieren +# 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, können alle Daten (User, Geräte, Segmente, Farben, Azure-Credentials) automatisch importiert werden: +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 ausführen +# Migration ausfuehren python migrate.py ``` -Die alte `config.cfg` wird danach nicht mehr benötigt. - -## Azure Authentifizierung - -Die Authentifizierung gegen Microsoft Graph erfolgt einmalig über den Device-Code-Flow im Terminal: - -```bash -source venv/bin/activate -python app.py --auth -``` - -Es wird ein Code angezeigt, der unter https://microsoft.com/devicelogin eingegeben werden muss. Nach erfolgreicher Anmeldung wird das Token in der Datenbank gespeichert und automatisch erneuert. +Die alte `config.cfg` wird danach nicht mehr benoetigt. ## AIDA-CSV auf Linux bereitstellen -Die Zeiterfassungs-CSV liegt typischerweise auf einem Windows-Server. Für den Zugriff von Linux gibt es mehrere Möglichkeiten: - -### Option A: SMB/CIFS-Mount (empfohlen) +Die Zeiterfassungs-CSV liegt typischerweise auf einem Windows-Server. +Fuer den Zugriff von Linux empfiehlt sich ein SMB/CIFS-Mount: ```bash # Paket installieren @@ -75,9 +140,6 @@ sudo apt install cifs-utils # Mount-Punkt erstellen sudo mkdir -p /mnt/zeiterfassung -# Eintrag in /etc/fstab -# //SERVERNAME/Zeiterfassung /mnt/zeiterfassung cifs credentials=/etc/samba/creds,uid=busylight,gid=busylight,ro 0 0 - # Credentials-Datei erstellen sudo bash -c 'cat > /etc/samba/creds << EOF username=DOMAIN\user @@ -85,6 +147,9 @@ 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 ``` @@ -94,20 +159,19 @@ In den Web-Einstellungen dann als CSV-Pfad eintragen: /mnt/zeiterfassung/Aida/profiles/aida/Transfer/Export/Status.csv ``` -### Option B: Regelmäßiger Kopiervorgang - -Per Cronjob die CSV regelmäßig auf den Linux-Server kopieren (z.B. via `scp` oder `rsync`). +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-Oberfläche ist dann erreichbar unter: **http://localhost:8080** +Die Web-Oberflaeche ist dann erreichbar unter: **http://SERVER-IP:8080** ### Als systemd-Service (Produktivbetrieb) @@ -121,7 +185,7 @@ sudo cp busylight.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now busylight -# Status prüfen +# Status pruefen sudo systemctl status busylight # Logs anzeigen @@ -132,48 +196,56 @@ sudo journalctl -u busylight -f ### 1. Einstellungen konfigurieren -Unter **Einstellungen** die Azure AD Credentials (Client ID, Client Secret, Tenant ID) und den CSV-Pfad eintragen. +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. Anschließend: +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-Geräte anlegen +### 3. WLED-Geraete anlegen -Unter **WLED-Geräte** die Hostnamen/IP-Adressen der WLED-Busylights eintragen und die Anzahl der Segmente festlegen (Standard: 2). +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-Gerät und Segment zuweisen: +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 für jeden Status per Color-Picker 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: Verfügbar | -| `teams_busy` | Teams: Beschäftigt | -| `teams_donotdisturb` | Teams: Nicht stören | +| `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: Präsentiert | +| `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 Statusänderungen mit Zeitstempel, WLED-URL und Ergebnis angezeigt. +Unter **Protokoll** werden die letzten 200 Statusaenderungen mit Zeitstempel, WLED-URL und Ergebnis angezeigt. ## Projektstruktur @@ -183,27 +255,43 @@ busylight/ ├── 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) +├── scheduler.py # Hintergrund-Polling (AIDA + Teams -> WLED) ├── migrate.py # Import aus alter config.cfg -├── requirements.txt # Python-Abhängigkeiten +├── requirements.txt # Python-Abhaengigkeiten ├── busylight.service # systemd Service-Datei ├── static/ │ └── style.css # CSS Styles └── templates/ ├── base.html # Basis-Layout mit Sidebar - ├── dashboard.html # Status-Übersicht + ├── dashboard.html # Status-Uebersicht ├── users.html # Benutzer-Verwaltung - ├── devices.html # WLED-Geräte-Verwaltung - ├── assignments.html # Zuordnungen User → Segment + ├── devices.html # WLED-Geraete-Verwaltung + ├── assignments.html # Zuordnungen User -> Segment ├── colors.html # Farb-Regeln ├── settings.html # Einstellungen - └── log.html # Aktivitäts-Protokoll + └── log.html # Aktivitaets-Protokoll ``` ## Ports und Firewall | Port | Richtung | Zweck | |------|----------|-------| -| 8080/tcp | Eingehend | Web-Oberfläche | +| 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` diff --git a/templates/dashboard.html b/templates/dashboard.html index 99287d5..c8db05e 100644 --- a/templates/dashboard.html +++ b/templates/dashboard.html @@ -38,11 +38,19 @@
Segment {{ seg.index }} {% if seg.user %} + {% if seg.aida == '-' %} +
+ + {{ seg.user }} +
+ Warte auf Status... + {% else %}
{{ seg.user }}
{{ seg.aida }} / {{ seg.teams }} + {% endif %} {% else %}
Nicht zugeordnet