Merge pull request 'Fix issue #21 and add aircraft position tracking indicators' (#29) from feature/position-tracking-fixes into main

Reviewed-on: #29
This commit is contained in:
Ole-Morten Duesund 2025-08-31 11:41:48 +02:00
commit ec676f678a
8 changed files with 125 additions and 74 deletions

View file

@ -53,6 +53,7 @@
<!-- Summary stats -->
<div class="stats-summary">
<span id="aircraft-count">0 aircraft</span>
<span id="position-summary">0 positioned</span>
<span id="sources-count">0 sources</span>
<span id="active-clients">1 viewer</span>
<span id="connection-status" class="connection-status disconnected">Connecting...</span>
@ -208,6 +209,14 @@
<h3>Max Range</h3>
<div class="stat-value" id="max-range">0 km</div>
</div>
<div class="stat-card">
<h3>Aircraft with Position</h3>
<div class="stat-value" id="aircraft-with-position">0</div>
</div>
<div class="stat-card">
<h3>Aircraft without Position</h3>
<div class="stat-value" id="aircraft-without-position">0</div>
</div>
</div>
<!-- Charts -->

View file

@ -244,6 +244,8 @@ export class UIManager {
const activeViewersEl = document.getElementById('active-viewers');
const maxRangeEl = document.getElementById('max-range');
const messagesSecEl = document.getElementById('messages-sec');
const aircraftWithPositionEl = document.getElementById('aircraft-with-position');
const aircraftWithoutPositionEl = document.getElementById('aircraft-without-position');
if (totalAircraftEl) totalAircraftEl.textContent = this.aircraftData.size;
if (activeSourcesEl) {
@ -253,6 +255,14 @@ export class UIManager {
activeViewersEl.textContent = this.stats.active_clients || 1;
}
// Update position tracking statistics from backend
if (aircraftWithPositionEl) {
aircraftWithPositionEl.textContent = this.stats.aircraft_with_position || 0;
}
if (aircraftWithoutPositionEl) {
aircraftWithoutPositionEl.textContent = this.stats.aircraft_without_position || 0;
}
// Calculate max range
let maxDistance = 0;
for (const aircraft of this.aircraftData.values()) {
@ -270,10 +280,18 @@ export class UIManager {
updateHeaderInfo() {
const aircraftCountEl = document.getElementById('aircraft-count');
const positionSummaryEl = document.getElementById('position-summary');
const sourcesCountEl = document.getElementById('sources-count');
const activeClientsEl = document.getElementById('active-clients');
if (aircraftCountEl) aircraftCountEl.textContent = `${this.aircraftData.size} aircraft`;
// Update position summary in header
if (positionSummaryEl) {
const positioned = this.stats.aircraft_with_position || 0;
positionSummaryEl.textContent = `${positioned} positioned`;
}
if (sourcesCountEl) sourcesCountEl.textContent = `${this.sourcesData.size} sources`;
// Update active clients count

11
debian/DEBIAN/prerm vendored
View file

@ -2,8 +2,8 @@
set -e
case "$1" in
remove|upgrade|deconfigure)
# Stop and disable the service
remove|deconfigure)
# Stop and disable the service on removal
if systemctl is-active --quiet skyview-adsb.service; then
systemctl stop skyview-adsb.service
fi
@ -12,6 +12,13 @@ case "$1" in
systemctl disable skyview-adsb.service
fi
;;
upgrade)
# Only stop service during upgrade, preserve enabled state
if systemctl is-active --quiet skyview-adsb.service; then
systemctl stop skyview-adsb.service
fi
# Don't disable - postinst will restart if service was enabled
;;
esac
exit 0

View file

@ -795,10 +795,13 @@ func (m *Merger) GetSources() []*Source {
//
// The statistics include:
// - total_aircraft: Current number of tracked aircraft
// - aircraft_with_position: Number of aircraft with valid position data
// - aircraft_without_position: Number of aircraft without position data
// - total_messages: Sum of all messages processed
// - active_sources: Number of currently connected sources
// - aircraft_by_sources: Distribution of aircraft by number of tracking sources
//
// The position statistics help assess data quality and tracking effectiveness.
// The aircraft_by_sources map shows data quality - aircraft tracked by
// multiple sources generally have better position accuracy and reliability.
//
@ -810,11 +813,22 @@ func (m *Merger) GetStatistics() map[string]interface{} {
totalMessages := int64(0)
activeSources := 0
aircraftBySources := make(map[int]int) // Count by number of sources
aircraftWithPosition := 0
aircraftWithoutPosition := 0
for _, state := range m.aircraft {
totalMessages += state.TotalMessages
numSources := len(state.Sources)
aircraftBySources[numSources]++
// Check if aircraft has valid position data
if state.Aircraft.PositionValid &&
state.Aircraft.Latitude != 0.0 &&
state.Aircraft.Longitude != 0.0 {
aircraftWithPosition++
} else {
aircraftWithoutPosition++
}
}
for _, src := range m.sources {
@ -825,6 +839,8 @@ func (m *Merger) GetStatistics() map[string]interface{} {
return map[string]interface{}{
"total_aircraft": len(m.aircraft),
"aircraft_with_position": aircraftWithPosition,
"aircraft_without_position": aircraftWithoutPosition,
"total_messages": totalMessages,
"active_sources": activeSources,
"aircraft_by_sources": aircraftBySources,

View file

@ -614,6 +614,7 @@ func (d *Decoder) decodeCPRPosition(aircraft *Aircraft) {
}
aircraft.Longitude = lon
aircraft.PositionValid = true
// CPR decoding completed successfully
}