feat: phone webhook integration (callstart/callend on port 8081)

- New webhook server on port 8081 for phone system (PBX)
- Endpoints: GET/POST /{extension}/callstart and /{extension}/callend
- New 'phone_extension' field on users (Durchwahl)
- Only activates when user is anwesend or homeoffice (AIDA)
- Sets WLED to phone_active color (red) on callstart
- Restores previous Teams/AIDA color on callend
- Polling skips WLED update while phone is active
- Dashboard shows phone badge when user is in a call
- New color rule 'phone_active' (configurable via web UI)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 23:15:51 +02:00
co-authored by Claude Opus 4.6
parent 47210cb068
commit 7f2858aab6
6 changed files with 183 additions and 7 deletions
+23 -4
View File
@@ -78,6 +78,7 @@ async def dashboard(request: Request):
row = conn.execute("""
SELECT u.display_name, u.azure_id,
s.last_aida_status, s.last_teams_status,
COALESCE(s.phone_active, 0) as phone_active,
cr_aida.r as ar, cr_aida.g as ag, cr_aida.b as ab,
cr_teams.r as tr, cr_teams.g as tg, cr_teams.b as tb
FROM assignments a
@@ -89,8 +90,12 @@ async def dashboard(request: Request):
""", (dev["id"], seg_idx)).fetchone()
if row:
# Use teams color if anwesend, otherwise aida color
if row["last_aida_status"] == "anwesend" and row["tr"] is not None:
phone = row["phone_active"]
if phone:
# Phone active: show phone color
pc = conn.execute("SELECT r,g,b FROM color_rules WHERE status='phone_active'").fetchone()
r, g, b = (pc["r"], pc["g"], pc["b"]) if pc else (255, 0, 0)
elif row["last_aida_status"] == "anwesend" and row["tr"] is not None:
r, g, b = row["tr"], row["tg"], row["tb"]
elif row["ar"] is not None:
r, g, b = row["ar"], row["ag"], row["ab"]
@@ -101,6 +106,7 @@ async def dashboard(request: Request):
"user": row["display_name"],
"aida": row["last_aida_status"] or "-",
"teams": row["last_teams_status"] or "-",
"phone": phone,
"r": r, "g": g, "b": b,
})
else:
@@ -167,12 +173,13 @@ async def sync_users():
async def update_user(
azure_id: str,
personal_nr: str = Form(""),
phone_extension: str = Form(""),
active: str = Form("0"),
):
conn = database.get_db()
conn.execute(
"UPDATE users SET personal_nr=?, active=? WHERE azure_id=?",
(personal_nr, 1 if active == "1" else 0, azure_id),
"UPDATE users SET personal_nr=?, phone_extension=?, active=? WHERE azure_id=?",
(personal_nr, phone_extension, 1 if active == "1" else 0, azure_id),
)
conn.commit()
conn.close()
@@ -471,8 +478,20 @@ def cli_auth():
if __name__ == "__main__":
import uvicorn
import threading
if len(sys.argv) > 1 and sys.argv[1] == "--auth":
cli_auth()
else:
# Start webhook server on port 8081 in background thread
from webhook import webhook_app
def run_webhook():
uvicorn.run(webhook_app, host="0.0.0.0", port=8081, log_level="info")
webhook_thread = threading.Thread(target=run_webhook, daemon=True)
webhook_thread.start()
logger.info("Webhook-Server gestartet auf Port 8081")
# Main web UI on port 8080
uvicorn.run(app, host="0.0.0.0", port=8080)