Fix aircraft track propagation issues in web frontend

This commit addresses issue #23 where aircraft track changes were not
propagating properly to the web frontend. The fixes include:

**Server-side improvements:**
- Enhanced WebSocket broadcast reliability with timeout-based queueing
- Increased broadcast channel buffer size (1000 -> 2000)
- Improved error handling and connection management
- Added write timeouts to prevent slow clients from blocking updates
- Enhanced connection cleanup and ping/pong handling
- Added debug endpoint /api/debug/websocket for troubleshooting
- Relaxed position validation thresholds for better track acceptance

**Frontend improvements:**
- Enhanced WebSocket manager with exponential backoff reconnection
- Improved aircraft position update detection and logging
- Fixed position update logic to always propagate changes to map
- Better coordinate validation and error reporting
- Enhanced debugging with detailed console logging
- Fixed track rotation update thresholds and logic
- Improved marker lifecycle management and cleanup
- Better handling of edge cases in aircraft state transitions

**Key bug fixes:**
- Removed overly aggressive position change detection that blocked updates
- Fixed track rotation sensitivity (5° -> 10° threshold)
- Enhanced coordinate validation to handle null/undefined values
- Improved WebSocket message ordering and processing
- Fixed marker position updates to always propagate to Leaflet

These changes ensure reliable real-time aircraft tracking with proper
position, heading, and altitude updates across multiple data sources.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ole-Morten Duesund 2025-08-25 10:14:03 +02:00
commit 1fe15c06a3
6 changed files with 216 additions and 49 deletions

View file

@ -238,7 +238,6 @@ func (d *Decoder) Decode(data []byte) (*Aircraft, error) {
df := (data[0] >> 3) & 0x1F
icao := d.extractICAO(data, df)
aircraft := &Aircraft{
ICAO24: icao,
@ -345,7 +344,7 @@ func (d *Decoder) decodeExtendedSquitter(data []byte, aircraft *Aircraft) (*Airc
// Set baseline signal quality for ADS-B extended squitter
aircraft.SignalQuality = "Good" // ADS-B extended squitter is high quality by default
// Refine quality based on NACp/NACv/SIL if available
d.calculateSignalQuality(aircraft)
@ -452,7 +451,7 @@ func (d *Decoder) decodeAirbornePosition(data []byte, aircraft *Aircraft) {
// Try to decode position if we have both even and odd messages
d.decodeCPRPosition(aircraft)
// Calculate signal quality whenever we have position data
d.calculateSignalQuality(aircraft)
}
@ -551,28 +550,28 @@ func (d *Decoder) decodeCPRPosition(aircraft *Aircraft) {
// Longitude calculation using correct CPR global decoding algorithm
// Reference: http://www.lll.lu/~edward/edward/adsb/DecodingADSBposition.html
nl := d.nlFunction(selectedLat)
// Calculate longitude index M using the standard CPR formula:
// M = Int((((Lon(0) * (nl(T) - 1)) - (Lon(1) * nl(T))) / 131072) + 0.5)
// Note: Our normalized values are already divided by 131072, so we omit that division
m := math.Floor(evenLon*(nl-1) - oddLon*nl + 0.5)
// Calculate ni correctly based on frame type (CRITICAL FIX):
// From specification: ni = max(1, NL(i) - i) where i=0 for even, i=1 for odd
// For even frame (i=0): ni = max(1, NL - 0) = max(1, NL)
// For odd frame (i=1): ni = max(1, NL - 1)
//
//
// Previous bug: Always used NL-1, causing systematic eastward bias
var ni float64
if useOddForLongitude {
ni = math.Max(1, nl-1) // Odd frame: NL - 1
} else {
ni = math.Max(1, nl) // Even frame: NL - 0 (full NL zones)
ni = math.Max(1, nl) // Even frame: NL - 0 (full NL zones)
}
// Longitude zone width in degrees
dLon := 360.0 / ni
// Calculate global longitude using frame-consistent encoding:
// Lon = dlon(T) * (modulo(M, ni) + Lon(T) / 131072)
var lon float64