Neue Features: Satelliten-Orbits, Naturkatastrophen, Visual Modes
SATELLITEN (CelesTrak TLE): - Raumstationen (ISS), GPS, Galileo, Wetter, Erdbeobachtung, Starlink - Echtzeit-Positionsberechnung aus Kepler-Elementen (2s Update) - Orbitbahnen als leuchtende Linien (Stationen, GPS, Galileo) - Farbkodiert nach Gruppe (rot=Station, orange=GPS, blau=Galileo) NATURKATASTROPHEN (NASA EONET): - Waldbraende, Vulkane, Stuerme, Fluten, Erdrutsche, Eis - Farbige Punkte mit Emoji-Labels - Klick zeigt Details und Quellen VISUAL MODES: - STD: Standard-Ansicht - NVG: Nachtsicht (gruener Monochrom-Filter) - FLIR: Thermal-Ansicht (invertiert, Infrarot-Look) - CRT: Retro-Monitor (Scanlines, Vignette) 4 neue Dateien: satellites.js, disasters.js, visualmodes.js, data_satellites.py, data_disasters.py
Dieser Commit ist enthalten in:
30
src/data_disasters.py
Normale Datei
30
src/data_disasters.py
Normale Datei
@@ -0,0 +1,30 @@
|
||||
"""Naturkatastrophen: NASA EONET (Earth Observatory Natural Event Tracker)."""
|
||||
import logging
|
||||
import time
|
||||
|
||||
import httpx
|
||||
from fastapi import APIRouter
|
||||
|
||||
logger = logging.getLogger("globe.disasters")
|
||||
router = APIRouter()
|
||||
|
||||
_cache: dict = {"data": None, "ts": 0}
|
||||
|
||||
|
||||
@router.get("/disasters")
|
||||
async def get_disasters():
|
||||
now = time.time()
|
||||
if _cache["data"] and now - _cache["ts"] < 600: # 10min Cache
|
||||
return _cache["data"]
|
||||
try:
|
||||
async with httpx.AsyncClient(timeout=12) as client:
|
||||
r = await client.get("https://eonet.gsfc.nasa.gov/api/v3/events?status=open&limit=100")
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
_cache["data"] = data
|
||||
_cache["ts"] = time.time()
|
||||
logger.info(f"Disasters: {len(data.get('events', []))} aktive Ereignisse")
|
||||
return data
|
||||
except Exception as e:
|
||||
logger.warning(f"NASA EONET Fehler: {e}")
|
||||
return _cache["data"] or {"events": []}
|
||||
69
src/data_satellites.py
Normale Datei
69
src/data_satellites.py
Normale Datei
@@ -0,0 +1,69 @@
|
||||
"""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"]
|
||||
@@ -31,12 +31,16 @@ from data_flights import router as flights_router, start_flight_collector
|
||||
from data_ships import router as ships_router, start_ais_collector
|
||||
from data_quakes import router as quakes_router
|
||||
from data_gdelt import router as gdelt_router
|
||||
from data_satellites import router as satellites_router
|
||||
from data_disasters import router as disasters_router
|
||||
|
||||
# Alle Daten-APIs hinter Auth
|
||||
app.include_router(flights_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
app.include_router(ships_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
app.include_router(quakes_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
app.include_router(gdelt_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
app.include_router(satellites_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
app.include_router(disasters_router, prefix="/api", dependencies=[Depends(get_current_user)])
|
||||
|
||||
# --- Static files ---
|
||||
static_dir = Path(__file__).parent.parent / "static"
|
||||
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren