From 7c4342e560b3335261a8a361816cf8540cb34f66 Mon Sep 17 00:00:00 2001 From: James Smith Date: Thu, 19 Mar 2026 22:21:31 +0000 Subject: [PATCH] Fix satellite tracker TLE key mismatch and empty pass caching Two root-cause bugs causing the reported issues: 1. Tracker never sent ISS positions: _start_satellite_tracker fell back to sat_name.replace(' ', '-').upper() as the TLE cache key when the DB entry had null TLE lines. For 'ISS (ZARYA)' this produced 'ISS-(ZARYA)' which has no matching entry in _tle_cache (keyed as 'ISS'). ISS was silently skipped every loop tick, so no SSE positions were ever emitted and the map marker never moved. Fix: try _BUILTIN_NORAD_TO_KEY.get(norad_int) first before the name-derived fallback so the NORAD-to-key mapping is always used. 2. Stale TLE pass prediction results were cached: if startup TLEs were too old for Skyfield to find events in the 48h window, the empty passes list was cached for 300s. A page refresh within that window re-served the empty result, showing 'NO PASSES FOUND' persistently. Fix: only cache non-empty pass results so the next request recomputes once the TLE auto-refresh has populated fresh data. Co-Authored-By: Claude Sonnet 4.6 --- routes/satellite.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/routes/satellite.py b/routes/satellite.py index 11b797e..b0e12e6 100644 --- a/routes/satellite.py +++ b/routes/satellite.py @@ -233,8 +233,14 @@ def _start_satellite_tracker(): tle1 = sat_rec.get('tle_line1') tle2 = sat_rec.get('tle_line2') if not tle1 or not tle2: - # Fall back to TLE cache - cache_key = sat_name.replace(' ', '-').upper() + # Fall back to TLE cache. Try the builtin NORAD-ID key first + # (e.g. 'ISS'), then the name-derived key as a last resort. + try: + norad_int = int(norad_id) + except (TypeError, ValueError): + norad_int = 0 + builtin_key = _BUILTIN_NORAD_TO_KEY.get(norad_int) + cache_key = builtin_key if (builtin_key and builtin_key in _tle_cache) else sat_name.replace(' ', '-').upper() if cache_key not in _tle_cache: continue tle_entry = _tle_cache[cache_key] @@ -560,7 +566,11 @@ def predict_passes(): passes.extend(sat_passes) passes.sort(key=lambda p: p['startTimeISO']) - _pass_cache[cache_key] = (passes, now_ts) + # Only cache non-empty results to avoid serving a stale empty response + # on the next request (which could happen if TLEs were too old to produce + # any events — the auto-refresh will update them shortly after startup). + if passes: + _pass_cache[cache_key] = (passes, now_ts) return jsonify({ 'status': 'success',