"""Satelliten-Daten: CelesTrak TLE Orbital Elements.""" import logging import time import httpx from fastapi import APIRouter logger = logging.getLogger("globe.satellites") router = APIRouter() _cache: dict = {"data": None, "ts": 0} # Wichtigste Satellitengruppen (nicht alle 14.000) _GROUPS = [ ("stations", "Raumstationen (ISS etc.)"), ("gps-ops", "GPS Navigationssatelliten"), ("galileo", "Galileo Navigation"), ("weather", "Wettersatelliten"), ("resource", "Erdbeobachtung"), ("starlink", "Starlink (Auswahl)"), ("active", None), # Fallback: alle aktiven, wird gefiltert ] @router.get("/satellites") async def get_satellites(): now = time.time() if _cache["data"] and now - _cache["ts"] < 3600: # 1h Cache return _cache["data"] all_sats = [] try: async with httpx.AsyncClient(timeout=15) as client: for group, label in _GROUPS: if group == "active": continue # Zu gross, skip url = f"https://celestrak.org/NORAD/elements/gp.php?GROUP={group}&FORMAT=json" try: r = await client.get(url) if r.status_code == 200: sats = r.json() # Starlink: nur 200 nehmen (sind tausende) if group == "starlink": sats = sats[:200] for s in sats: all_sats.append({ "name": s.get("OBJECT_NAME", "?"), "id": s.get("NORAD_CAT_ID"), "group": group, "epoch": s.get("EPOCH"), "meanMotion": s.get("MEAN_MOTION"), "eccentricity": s.get("ECCENTRICITY"), "inclination": s.get("INCLINATION"), "raOfAscNode": s.get("RA_OF_ASC_NODE"), "argOfPericenter": s.get("ARG_OF_PERICENTER"), "meanAnomaly": s.get("MEAN_ANOMALY"), "bstar": s.get("BSTAR"), "meanMotionDot": s.get("MEAN_MOTION_DOT"), }) except Exception as e: logger.warning(f"CelesTrak {group}: {e}") except Exception as e: logger.warning(f"CelesTrak Fehler: {e}") return _cache["data"] or {"satellites": [], "total": 0} _cache["data"] = {"satellites": all_sats, "total": len(all_sats)} _cache["ts"] = time.time() logger.info(f"Satellites: {len(all_sats)} geladen") return _cache["data"]