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 <noreply@anthropic.com>
This commit is contained in:
James Smith
2026-03-19 22:21:31 +00:00
parent 33959403f4
commit 7c4342e560

View File

@@ -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',