From 85b211e532103b35c9d81368dd5558597197b325 Mon Sep 17 00:00:00 2001 From: serversdwn Date: Mon, 5 Jan 2026 18:56:20 +0000 Subject: [PATCH] bugfix: unit status updating based on last heard, not just using cached status --- backend/services/snapshot.py | 41 ++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/backend/services/snapshot.py b/backend/services/snapshot.py index 7c737b7..4a6cd38 100644 --- a/backend/services/snapshot.py +++ b/backend/services/snapshot.py @@ -24,13 +24,47 @@ def format_age(last_seen): return f"{int(hours)}h {int(mins)}m" +def calculate_status(last_seen, status_ok_threshold=12, status_pending_threshold=24): + """ + Calculate status based on how long ago the unit was last seen. + + Args: + last_seen: datetime of last seen (UTC) + status_ok_threshold: hours before status becomes Pending (default 12) + status_pending_threshold: hours before status becomes Missing (default 24) + + Returns: + "OK", "Pending", or "Missing" + """ + if not last_seen: + return "Missing" + + last_seen = ensure_utc(last_seen) + now = datetime.now(timezone.utc) + hours_ago = (now - last_seen).total_seconds() / 3600 + + if hours_ago > status_pending_threshold: + return "Missing" + elif hours_ago > status_ok_threshold: + return "Pending" + else: + return "OK" + + def emit_status_snapshot(): """ Merge roster (what we *intend*) with emitter data (what is *actually happening*). + Status is recalculated based on current time to ensure accuracy. """ db = get_db_session() try: + # Get user preferences for status thresholds + from backend.models import UserPreferences + prefs = db.query(UserPreferences).filter_by(id=1).first() + status_ok_threshold = prefs.status_ok_threshold_hours if prefs else 12 + status_pending_threshold = prefs.status_pending_threshold_hours if prefs else 24 + roster = {r.id: r for r in db.query(RosterUnit).all()} emitters = {e.id: e for e in db.query(Emitter).all()} ignored = {i.id for i in db.query(IgnoredUnit).all()} @@ -48,8 +82,9 @@ def emit_status_snapshot(): fname = "" else: if e: - status = e.status last_seen = ensure_utc(e.last_seen) + # RECALCULATE status based on current time, not stored value + status = calculate_status(last_seen, status_ok_threshold, status_pending_threshold) age = format_age(last_seen) fname = e.last_file else: @@ -86,9 +121,11 @@ def emit_status_snapshot(): for unit_id, e in emitters.items(): if unit_id not in roster: last_seen = ensure_utc(e.last_seen) + # RECALCULATE status for unknown units too + status = calculate_status(last_seen, status_ok_threshold, status_pending_threshold) units[unit_id] = { "id": unit_id, - "status": e.status, + "status": status, "age": format_age(last_seen), "last": last_seen.isoformat(), "fname": e.last_file,