[fix](trx-rs): don't use fabricated TLEs for satellite pass predictions
Hardcoded fallback TLEs had approximate orbital elements (round numbers for RAAN, arg of perigee, mean anomaly) producing pass times hours off. Return empty predictions with a clear error when CelesTrak data is not yet available. Add TLE source and satellite count to the API response. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Stan Grams <sjg@haxx.space>
This commit is contained in:
@@ -292,6 +292,7 @@ document
|
||||
let satPredData = [];
|
||||
let satPredFilterText = "";
|
||||
let satPredMinEl = 0;
|
||||
let satPredSatCount = 0;
|
||||
const satPredFilterInput = document.getElementById("sat-pred-filter");
|
||||
const satPredMinElSelect = document.getElementById("sat-pred-min-el");
|
||||
|
||||
@@ -375,7 +376,11 @@ function renderSatPredictions(passes, error) {
|
||||
fragment.appendChild(row);
|
||||
}
|
||||
list.replaceChildren(fragment);
|
||||
if (status) status.textContent = `${passes.length} pass${passes.length === 1 ? "" : "es"} in the next 24 h · times in UTC`;
|
||||
if (status) {
|
||||
let text = `${passes.length} pass${passes.length === 1 ? "" : "es"} in the next 24 h · times in UTC`;
|
||||
if (satPredSatCount > 0) text += ` · ${satPredSatCount} satellites tracked`;
|
||||
status.textContent = text;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSatPredictions() {
|
||||
@@ -387,6 +392,7 @@ async function loadSatPredictions() {
|
||||
const resp = await fetch("/sat_passes");
|
||||
if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
|
||||
const data = await resp.json();
|
||||
satPredSatCount = data.satellite_count || 0;
|
||||
if (data.error) {
|
||||
satPredData = [];
|
||||
renderSatPredictions([], data.error);
|
||||
|
||||
@@ -1376,12 +1376,17 @@ struct SatPassesResponse {
|
||||
passes: Vec<trx_core::geo::PassPrediction>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
error: Option<String>,
|
||||
/// Number of satellites evaluated for predictions.
|
||||
satellite_count: usize,
|
||||
/// Source of the TLE data used: "celestrak" or "unavailable".
|
||||
tle_source: trx_core::geo::TleSource,
|
||||
}
|
||||
|
||||
/// Return predicted passes for all known amateur satellites over the next 24 h.
|
||||
/// Return predicted passes for all known satellites over the next 24 h.
|
||||
///
|
||||
/// Requires the server station location to be configured. Returns an empty
|
||||
/// `passes` array with an `error` field if the location is missing.
|
||||
/// `passes` array with an `error` field if the location is missing or TLE
|
||||
/// data has not been fetched yet.
|
||||
#[get("/sat_passes")]
|
||||
pub async fn sat_passes(state: web::Data<watch::Receiver<RigState>>) -> impl Responder {
|
||||
let rig_state = state.get_ref().borrow().clone();
|
||||
@@ -1392,6 +1397,8 @@ pub async fn sat_passes(state: web::Data<watch::Receiver<RigState>>) -> impl Res
|
||||
return web::Json(SatPassesResponse {
|
||||
passes: vec![],
|
||||
error: Some("No station location configured".to_string()),
|
||||
satellite_count: 0,
|
||||
tle_source: trx_core::geo::TleSource::Unavailable,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1401,10 +1408,18 @@ pub async fn sat_passes(state: web::Data<watch::Receiver<RigState>>) -> impl Res
|
||||
.as_millis() as i64;
|
||||
let window_ms = 24 * 60 * 60 * 1000_i64;
|
||||
|
||||
let passes = trx_core::geo::compute_upcoming_passes(lat, lon, now_ms, window_ms);
|
||||
let result = trx_core::geo::compute_upcoming_passes(lat, lon, now_ms, window_ms);
|
||||
let error = match result.tle_source {
|
||||
trx_core::geo::TleSource::Unavailable => {
|
||||
Some("TLE data not yet available — waiting for CelesTrak fetch".to_string())
|
||||
}
|
||||
trx_core::geo::TleSource::Celestrak => None,
|
||||
};
|
||||
web::Json(SatPassesResponse {
|
||||
passes,
|
||||
error: None,
|
||||
passes: result.passes,
|
||||
error,
|
||||
satellite_count: result.satellite_count,
|
||||
tle_source: result.tle_source,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user