diff --git a/assets/static/css/style.css b/assets/static/css/style.css index b34a241..9a3400d 100644 --- a/assets/static/css/style.css +++ b/assets/static/css/style.css @@ -268,12 +268,14 @@ body { border: 1px solid #ffffff; } -.legend-icon.commercial { background: #00ff88; } -.legend-icon.cargo { background: #ff8c00; } -.legend-icon.helicopter { background: #00d4ff; } -.legend-icon.military { background: #ff4444; } -.legend-icon.ga { background: #ffff00; } -.legend-icon.ground { background: #888888; } +.legend-icon.light { background: #00bfff; } /* Sky blue for light aircraft */ +.legend-icon.medium { background: #00ff88; } /* Green for medium aircraft */ +.legend-icon.large { background: #ff8c00; } /* Orange for large aircraft */ +.legend-icon.heavy { background: #ff0000; } /* Red for heavy aircraft */ +.legend-icon.helicopter { background: #ff00ff; } /* Magenta for helicopters */ +.legend-icon.military { background: #ff4444; } /* Red-orange for military */ +.legend-icon.ga { background: #ffff00; } /* Yellow for general aviation */ +.legend-icon.ground { background: #888888; } /* Gray for ground vehicles */ .table-controls { display: flex; diff --git a/assets/static/icons/cargo.svg b/assets/static/icons/cargo.svg index b3605b1..6d30370 100644 --- a/assets/static/icons/cargo.svg +++ b/assets/static/icons/cargo.svg @@ -1,9 +1,28 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/commercial.svg b/assets/static/icons/commercial.svg index f1f1b28..f193d6a 100644 --- a/assets/static/icons/commercial.svg +++ b/assets/static/icons/commercial.svg @@ -1,7 +1,21 @@ - - + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/ga.svg b/assets/static/icons/ga.svg index cfba161..2be9e7a 100644 --- a/assets/static/icons/ga.svg +++ b/assets/static/icons/ga.svg @@ -1,7 +1,27 @@ - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/ground.svg b/assets/static/icons/ground.svg index ee5af8e..96c03a3 100644 --- a/assets/static/icons/ground.svg +++ b/assets/static/icons/ground.svg @@ -1,10 +1,24 @@ - - + + + + + + + + + - - + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/helicopter.svg b/assets/static/icons/helicopter.svg index 5197bea..b1c90bc 100644 --- a/assets/static/icons/helicopter.svg +++ b/assets/static/icons/helicopter.svg @@ -1,12 +1,29 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/icons/military.svg b/assets/static/icons/military.svg index c4e58a7..931c9c8 100644 --- a/assets/static/icons/military.svg +++ b/assets/static/icons/military.svg @@ -1,7 +1,27 @@ - - + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/static/index.html b/assets/static/index.html index 0a00509..b9f43b0 100644 --- a/assets/static/index.html +++ b/assets/static/index.html @@ -107,19 +107,19 @@

ADS-B Categories

- + Light < 7000kg
- + Medium 7000-34000kg
- + Large 34000-136000kg
- + Heavy > 136000kg
diff --git a/assets/static/js/modules/aircraft-manager.js b/assets/static/js/modules/aircraft-manager.js index 1485d38..347399b 100644 --- a/assets/static/js/modules/aircraft-manager.js +++ b/assets/static/js/modules/aircraft-manager.js @@ -215,7 +215,7 @@ export class AircraftManager { createAircraftIcon(aircraft) { const iconType = this.getAircraftIconType(aircraft); - const color = this.getAircraftColor(iconType); + const color = this.getAircraftColor(iconType, aircraft); const size = aircraft.OnGround ? 12 : 16; const rotation = aircraft.Track || 0; @@ -277,16 +277,38 @@ export class AircraftManager { return 'commercial'; } - getAircraftColor(type) { - const colors = { - commercial: '#00ff88', - cargo: '#ff8c00', - military: '#ff4444', - ga: '#ffff00', - ground: '#888888', - helicopter: '#ff00ff' // Magenta for helicopters - }; - return colors[type] || colors.commercial; + getAircraftColor(type, aircraft) { + // Special colors for specific types + if (type === 'military') return '#ff4444'; + if (type === 'helicopter') return '#ff00ff'; + if (type === 'ground') return '#888888'; + if (type === 'ga') return '#ffff00'; + + // For commercial and cargo types, use weight-based colors + if (aircraft && aircraft.Category) { + const cat = aircraft.Category.toLowerCase(); + + // Check for specific weight ranges in the category string + // Light aircraft (< 7000kg) - Sky blue + if (cat.includes('light') || cat.includes('7000kg')) { + return '#00bfff'; + } + // Medium aircraft (7000-34000kg) - Green + if (cat.includes('medium 7000')) { + return '#00ff88'; + } + // Large aircraft (34000-136000kg) - Orange + if (cat.includes('medium 34000') || cat.includes('large')) { + return '#ff8c00'; + } + // Heavy aircraft (> 136000kg) - Red + if (cat.includes('heavy') || cat.includes('136000kg') || cat.includes('super')) { + return '#ff0000'; + } + } + + // Default to green for unknown commercial aircraft + return '#00ff88'; } diff --git a/internal/modes/decoder.go b/internal/modes/decoder.go index 397a1f9..f4a1ed7 100644 --- a/internal/modes/decoder.go +++ b/internal/modes/decoder.go @@ -232,6 +232,11 @@ func (d *Decoder) Decode(data []byte) (*Aircraft, error) { df := (data[0] >> 3) & 0x1F icao := d.extractICAO(data, df) + + // Debug: Log DF types to verify we're processing new formats + if df == 0 || df == 11 || df == 16 || df == 19 || df == 24 { + fmt.Printf("DEBUG: Processing new DF%d message for ICAO %06X\n", df, icao) + } aircraft := &Aircraft{ ICAO24: icao, diff --git a/internal/server/server.go b/internal/server/server.go index 76e89a8..2197f85 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -190,6 +190,9 @@ func (s *Server) Stop() { func (s *Server) setupRoutes() http.Handler { router := mux.NewRouter() + // Health check endpoint for load balancers/monitoring + router.HandleFunc("/health", s.handleHealthCheck).Methods("GET") + // API routes api := router.PathPrefix("/api").Subrouter() api.HandleFunc("/aircraft", s.handleGetAircraft).Methods("GET") @@ -240,6 +243,63 @@ func (s *Server) isAircraftUseful(aircraft *merger.AircraftState) bool { return hasValidPosition || hasCallsign || hasAltitude || hasSquawk } +// handleHealthCheck serves the /health endpoint for monitoring and load balancers. +// Returns a simple health status with basic service information. +// +// Response includes: +// - status: "healthy" or "degraded" +// - uptime: server uptime in seconds +// - sources: number of active sources and their connection status +// - aircraft: current aircraft count +// +// The endpoint returns: +// - 200 OK when the service is healthy +// - 503 Service Unavailable when the service is degraded (no active sources) +func (s *Server) handleHealthCheck(w http.ResponseWriter, r *http.Request) { + sources := s.merger.GetSources() + stats := s.merger.GetStatistics() + aircraft := s.merger.GetAircraft() + + // Check if we have any active sources + activeSources := 0 + for _, source := range sources { + if source.Active { + activeSources++ + } + } + + // Determine health status + status := "healthy" + statusCode := http.StatusOK + if activeSources == 0 && len(sources) > 0 { + status = "degraded" + statusCode = http.StatusServiceUnavailable + } + + response := map[string]interface{}{ + "status": status, + "timestamp": time.Now().Unix(), + "sources": map[string]interface{}{ + "total": len(sources), + "active": activeSources, + }, + "aircraft": map[string]interface{}{ + "count": len(aircraft), + }, + } + + // Add statistics if available + if stats != nil { + if totalMessages, ok := stats["total_messages"]; ok { + response["messages"] = totalMessages + } + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(statusCode) + json.NewEncoder(w).Encode(response) +} + // handleGetAircraft serves the /api/aircraft endpoint. // Returns all currently tracked aircraft with their latest state information. //