feat: poll Teams presence independently of AIDA CSV

- Teams status is now always queried, even without AIDA CSV
- Users without personal_nr are also polled (Teams-only mode)
- If AIDA is unavailable, default to 'anwesend' and use Teams color
- Dashboard will now show Teams status even without SMB mount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Christian Mueller 2026-04-23 22:14:43 +02:00
parent ce19dec8c1
commit 8d178eac6d

View File

@ -12,10 +12,9 @@ graph = None
def read_aida_csv(csv_path): def read_aida_csv(csv_path):
"""Read AIDA status CSV. Returns dict: personal_nr -> line content.""" """Read AIDA status CSV. Returns list of lines."""
if not csv_path or not os.path.exists(csv_path): if not csv_path or not os.path.exists(csv_path):
logger.warning("AIDA CSV nicht gefunden: %s", csv_path) return []
return {}
try: try:
with open(csv_path, "r", encoding="utf-8", errors="replace") as f: with open(csv_path, "r", encoding="utf-8", errors="replace") as f:
lines = f.read().splitlines() lines = f.read().splitlines()
@ -35,11 +34,11 @@ def determine_aida_status(lines, personal_nr, settings):
return None return None
line = matching[0] line = matching[0]
if line.endswith(settings["aida_status_abwesend"]): if line.endswith(settings.get("aida_status_abwesend", "~~0~~")):
return "abwesend" return "abwesend"
if line.endswith(settings["aida_status_anwesend"]): if line.endswith(settings.get("aida_status_anwesend", "~~1~~")):
return "anwesend" return "anwesend"
if line.endswith(settings["aida_status_homeoffice"]): if line.endswith(settings.get("aida_status_homeoffice", "~~2~~")):
return "homeoffice" return "homeoffice"
return None return None
@ -68,7 +67,7 @@ def poll_status():
for row in conn.execute("SELECT key, value FROM settings").fetchall(): for row in conn.execute("SELECT key, value FROM settings").fetchall():
settings[row["key"]] = row["value"] settings[row["key"]] = row["value"]
# Get all active users with assignments # Get all active users with assignments (auch ohne personal_nr)
users_with_assignments = conn.execute(""" users_with_assignments = conn.execute("""
SELECT u.azure_id, u.display_name, u.personal_nr, SELECT u.azure_id, u.display_name, u.personal_nr,
a.segment, d.hostname, a.segment, d.hostname,
@ -77,14 +76,14 @@ def poll_status():
JOIN assignments a ON a.user_azure_id = u.azure_id JOIN assignments a ON a.user_azure_id = u.azure_id
JOIN wled_devices d ON d.id = a.wled_device_id JOIN wled_devices d ON d.id = a.wled_device_id
LEFT JOIN state s ON s.user_azure_id = u.azure_id LEFT JOIN state s ON s.user_azure_id = u.azure_id
WHERE u.active = 1 AND u.personal_nr != '' WHERE u.active = 1
""").fetchall() """).fetchall()
if not users_with_assignments: if not users_with_assignments:
logger.debug("Keine aktiven User mit Zuordnungen gefunden") logger.debug("Keine aktiven User mit Zuordnungen gefunden")
return return
# Read AIDA CSV # Read AIDA CSV (kann leer sein)
aida_lines = read_aida_csv(settings.get("aida_csv_path", "")) aida_lines = read_aida_csv(settings.get("aida_csv_path", ""))
for user in users_with_assignments: for user in users_with_assignments:
@ -113,24 +112,21 @@ def _process_user(user, aida_lines, settings, conn):
last_aida = user["last_aida_status"] or "" last_aida = user["last_aida_status"] or ""
last_teams = user["last_teams_status"] or "" last_teams = user["last_teams_status"] or ""
# Determine AIDA status # Determine AIDA status (kann None sein wenn keine CSV oder keine Personalnr)
aida_status = determine_aida_status(aida_lines, personal_nr, settings) aida_status = determine_aida_status(aida_lines, personal_nr, settings)
if aida_status is None:
return
# Determine Teams status # Immer Teams-Status abfragen
teams_status = "" teams_status = ""
if aida_status == "anwesend":
presence = graph.get_presence(azure_id) presence = graph.get_presence(azure_id)
if presence and "activity" in presence: if presence and "activity" in presence:
teams_status = "teams_" + presence["activity"].lower() teams_status = "teams_" + presence["activity"].lower()
# Wenn AIDA nicht verfuegbar, nur Teams-Status nutzen
if aida_status is None:
aida_status = "anwesend" # Default: anwesend wenn AIDA nicht verfuegbar
# Check if status changed # Check if status changed
if aida_status == last_aida: if aida_status == last_aida and teams_status == last_teams:
if aida_status == "anwesend":
if teams_status == last_teams:
return # No change
else:
return # No change return # No change
# Determine color # Determine color
@ -138,10 +134,8 @@ def _process_user(user, aida_lines, settings, conn):
color = get_color_for_status("abwesend", conn) color = get_color_for_status("abwesend", conn)
elif aida_status == "homeoffice": elif aida_status == "homeoffice":
color = get_color_for_status("homeoffice", conn) color = get_color_for_status("homeoffice", conn)
elif aida_status == "anwesend" and teams_status: elif teams_status:
color = get_color_for_status(teams_status, conn) color = get_color_for_status(teams_status, conn)
if not color:
color = get_color_for_status("teams_available", conn)
else: else:
color = get_color_for_status("available", conn) color = get_color_for_status("available", conn)
@ -153,7 +147,6 @@ def _process_user(user, aida_lines, settings, conn):
success, result_text = call_wled(url) success, result_text = call_wled(url)
if success: if success:
# Update state
conn.execute(""" conn.execute("""
INSERT INTO state (user_azure_id, last_aida_status, last_teams_status, updated_at) INSERT INTO state (user_azure_id, last_aida_status, last_teams_status, updated_at)
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
@ -169,7 +162,6 @@ def _process_user(user, aida_lines, settings, conn):
display_name, aida_status, teams_status, result_text, display_name, aida_status, teams_status, result_text,
) )
else: else:
# Reset state on failure
conn.execute(""" conn.execute("""
INSERT INTO state (user_azure_id, last_aida_status, last_teams_status, updated_at) INSERT INTO state (user_azure_id, last_aida_status, last_teams_status, updated_at)
VALUES (?, '', '', ?) VALUES (?, '', '', ?)
@ -178,7 +170,6 @@ def _process_user(user, aida_lines, settings, conn):
""", (azure_id, datetime.now(), datetime.now())) """, (azure_id, datetime.now(), datetime.now()))
conn.commit() conn.commit()
# Log activity
log_activity( log_activity(
azure_id, display_name, aida_status, teams_status, url, result_text azure_id, display_name, aida_status, teams_status, url, result_text
) )