mirror of
https://github.com/OpenSquawk/OpenSquawk
synced 2026-08-02 06:46:18 +08:00
- NormalizedTelemetry carries lat/lon (0/0 no-GPS guard, position in the change-detection signature) so the backend can derive distance triggers - bridge polling moves from setInterval to a Worker tick: with the sim in the foreground the /live-atc tab is backgrounded and Chrome throttles plain intervals to ~1/min — telemetry-driven ATC lagged behind the silence fallback Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
49 lines
2.3 KiB
TypeScript
49 lines
2.3 KiB
TypeScript
import type { NormalizedTelemetry } from '../../app/composables/useRadioBackend'
|
|
|
|
export function normalizeSimFreq(value: unknown): string | null {
|
|
const num = typeof value === 'number' ? value : Number(value)
|
|
if (!Number.isFinite(num) || num < 118 || num >= 137) return null
|
|
return num.toFixed(3)
|
|
}
|
|
|
|
// Map the raw bridge telemetry (SimConnect-style field names) to the
|
|
// sim-agnostic contract the backend understands. The raw lat/lon position is
|
|
// forwarded so the backend can derive distance_to_dep_nm / distance_to_dest_nm
|
|
// (it has the airport coordinates via the session's ICAO codes); heading is
|
|
// currently true (bridge only reports true) — magnetic correction is needed
|
|
// before any localizer/heading trigger can rely on it.
|
|
export function normalizeBridgeTelemetry(raw: any): NormalizedTelemetry | null {
|
|
if (!raw || typeof raw !== 'object') return null
|
|
const num = (v: unknown): number | undefined => {
|
|
const n = typeof v === 'number' ? v : Number(v)
|
|
return Number.isFinite(n) ? n : undefined
|
|
}
|
|
const lat = num(raw.PLANE_LATITUDE)
|
|
const lon = num(raw.PLANE_LONGITUDE)
|
|
// 0/0 is the bridge's "no GPS data" default — don't forward it as a position.
|
|
const hasPosition =
|
|
lat !== undefined && lon !== undefined && (Math.abs(lat) > 0.1 || Math.abs(lon) > 0.1)
|
|
return {
|
|
altitude_ft: num(raw.PLANE_ALTITUDE),
|
|
ias_kts: num(raw.AIRSPEED_INDICATED),
|
|
gs_kts: num(raw.GROUND_VELOCITY),
|
|
vs_fpm: num(raw.VERTICAL_SPEED),
|
|
heading_deg: num(raw.PLANE_HEADING_DEGREES_TRUE),
|
|
on_ground: typeof raw.SIM_ON_GROUND === 'boolean' ? raw.SIM_ON_GROUND : undefined,
|
|
...(hasPosition ? { lat, lon } : {}),
|
|
}
|
|
}
|
|
|
|
// Only forward telemetry that meaningfully changed, so idle cruise doesn't POST
|
|
// an identical tick every poll. Rounded so tiny jitter doesn't count as change.
|
|
// Position rounds at ~0.01° (≈0.6 nm) so a moving aircraft keeps ticking the
|
|
// backend's distance triggers without spamming while parked.
|
|
export function telemetrySignature(t: NormalizedTelemetry): string {
|
|
const r = (v: number | undefined, step: number) => (v === undefined ? '_' : Math.round(v / step))
|
|
return [
|
|
r(t.altitude_ft, 100), r(t.ias_kts, 5), r(t.gs_kts, 5),
|
|
r(t.vs_fpm, 100), r(t.heading_deg, 5), t.on_ground ? 'G' : 'A',
|
|
r(t.lat, 0.01), r(t.lon, 0.01),
|
|
].join('|')
|
|
}
|