skyview/internal/parser/sbs1.go
Ole-Morten Duesund 55710614da Add historical flight track functionality
- Store track history with position, altitude, speed, and timestamp
- Automatic track point collection every 30 seconds when position changes
- API endpoint /api/aircraft/{hex}/history for individual aircraft tracks
- Frontend "Show History" button to display historical flight paths
- Click aircraft markers to show their historical track (dashed red line)
- Track cleanup: keep last 200 points per aircraft, 24-hour retention
- Add aircraft type badges in table view with color coding
- Start/end markers for historical tracks with timestamps

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-23 22:52:16 +02:00

105 lines
2.5 KiB
Go

package parser
import (
"strconv"
"strings"
"time"
)
type TrackPoint struct {
Timestamp time.Time `json:"timestamp"`
Latitude float64 `json:"lat"`
Longitude float64 `json:"lon"`
Altitude int `json:"altitude"`
Speed int `json:"speed"`
Track int `json:"track"`
}
type Aircraft struct {
Hex string `json:"hex"`
Flight string `json:"flight,omitempty"`
Altitude int `json:"alt_baro,omitempty"`
GroundSpeed int `json:"gs,omitempty"`
Track int `json:"track,omitempty"`
Latitude float64 `json:"lat,omitempty"`
Longitude float64 `json:"lon,omitempty"`
VertRate int `json:"vert_rate,omitempty"`
Squawk string `json:"squawk,omitempty"`
Emergency bool `json:"emergency,omitempty"`
OnGround bool `json:"on_ground,omitempty"`
LastSeen time.Time `json:"last_seen"`
Messages int `json:"messages"`
TrackHistory []TrackPoint `json:"track_history,omitempty"`
}
type AircraftData struct {
Now int64 `json:"now"`
Messages int `json:"messages"`
Aircraft map[string]Aircraft `json:"aircraft"`
}
func ParseSBS1Line(line string) (*Aircraft, error) {
parts := strings.Split(strings.TrimSpace(line), ",")
if len(parts) < 22 {
return nil, nil
}
messageType := parts[1]
if messageType != "1" && messageType != "3" && messageType != "4" {
return nil, nil
}
aircraft := &Aircraft{
Hex: strings.TrimSpace(parts[4]),
LastSeen: time.Now(),
Messages: 1,
}
if parts[10] != "" {
aircraft.Flight = strings.TrimSpace(parts[10])
}
if parts[11] != "" {
if alt, err := strconv.Atoi(parts[11]); err == nil {
aircraft.Altitude = alt
}
}
if parts[12] != "" {
if gs, err := strconv.Atoi(parts[12]); err == nil {
aircraft.GroundSpeed = gs
}
}
if parts[13] != "" {
if track, err := strconv.Atoi(parts[13]); err == nil {
aircraft.Track = track
}
}
if parts[14] != "" && parts[15] != "" {
if lat, err := strconv.ParseFloat(parts[14], 64); err == nil {
aircraft.Latitude = lat
}
if lon, err := strconv.ParseFloat(parts[15], 64); err == nil {
aircraft.Longitude = lon
}
}
if parts[16] != "" {
if vr, err := strconv.Atoi(parts[16]); err == nil {
aircraft.VertRate = vr
}
}
if parts[17] != "" {
aircraft.Squawk = strings.TrimSpace(parts[17])
}
if parts[21] != "" {
aircraft.OnGround = parts[21] == "1"
}
return aircraft, nil
}