Hi all — first post here. I’ve built a small open-data satellite control room on top of SatNOGS, and wanted to show it here first, since it’s your data and your decoders doing the heavy lifting.
A MapLibre globe with 23 satellites (the ones I found currently decodable with satnogs-decoders), each clickable into Grafana dashboards of battery and temperature values decoded locally from the raw frames. My favorite part: selecting a satellite draws lines to the ground stations that heard it in the last 7 days — the volunteer network made visible.
Everything is cached in Postgres on my side — visitors never hit SatNOGS; my ingest polls /api/telemetry/ gently (~23 requests per 30 min). If that cadence bothers anyone, or there’s a better route for frame history, tell me and I’ll adapt.
Feedback very welcome. And thanks for all of this — none of it exists without Libre Space and the station operators.
Thanks Lars! If you operate one of the SatNOGS stations, some of the orange reception lines on the globe may literally be yours — clicking one shows which frame the station decoded and where the satellite was at that moment. The whole feature exists to make the volunteer network visible.
This is very cool. This thread might be of interest to you, since your dealing with demote data as well.
Since your using MapLibre, I am wandering how hard it is to deal with interval based data with it. (Having it track the satellite) are you precomputing positions or computing them each update. (Asking since I am looking into porting my Network activity map from CesiumJS (I build CZML json files every 15min) to using MapLibre, and I am using Cesium’s interpolared intervals which MapLibre has no equivalance of)
Precomputed, server-side. An ingest service runs SGP4 (python-sgp4) over cached CelesTrak elements and writes one position row per satellite every 15 s into Postgres (7-day rolling window). The globe polls a small /api/satellites endpoint every 15 s and just setData()s the GeoJSON source — no client-side propagation, no interpolation. At globe zoom the 15 s hops aren’t visible; the ground track is the same table replayed (/api/track/{norad}).
So the honest answer to “interval data in MapLibre”: I side-stepped it. MapLibre has nothing like Cesium’s time-dynamic CZML/interpolated properties — the database is my interpolation buffer. For your port, two options I’d consider:
keep the CZML pipeline but sample it into plain GeoJSON snapshots and swap them with setData() on your playback clock — fine up to thousands of points;
or go client-side: satellite.js gives you SGP4 in the browser, so for tens of satellites you can compute exact positions per animation frame straight from TLEs — smoother than any interpolation, no intervals needed. For non-orbital interval data (reception activity), a property filter on a time field steps a slider fast enough.
The JOVH analysis you linked is close to something that shipped today, prompted by this thread: station search. Type a callsign on https://overwatch.confinia.io and you get that station’s receptions across the tracked fleet drawn on the globe — shareable, e.g. https://overwatch.confinia.io/#station:UX5UL-KO50ei (1,236 frames, 16 satellites this week). And the new /api/v1/stations endpoints expose per-station reception aggregates directly, which might save some log crunching.