diff --git a/src/adsb_client.cpp b/src/adsb_client.cpp index f189741..b0645d2 100644 --- a/src/adsb_client.cpp +++ b/src/adsb_client.cpp @@ -106,10 +106,12 @@ FetchResult fetch(double homeLat, double homeLon, float radiusKm, a.lat = ac["lat"] | 0.0f; a.lon = ac["lon"] | 0.0f; - if (ac["alt_baro"].is()) { +if (ac["alt_baro"].is()) { a.altBaroFt = 0; + a.onGround = (strcmp(ac["alt_baro"], "ground") == 0); } else { a.altBaroFt = ac["alt_baro"] | 0; + a.onGround = false; } a.vertRateFtMin = ac["baro_rate"] | 0; diff --git a/src/aircraft.h b/src/aircraft.h index 45241d2..7c12a94 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -23,6 +23,7 @@ struct Aircraft { uint32_t alertedAtMs = 0; bool valid = false; + bool onGround = false; char airlineName[24] = {0}; uint16_t estSeats = 0; diff --git a/src/aircraft_list_screen.cpp b/src/aircraft_list_screen.cpp index 6dd0969..dadd637 100644 --- a/src/aircraft_list_screen.cpp +++ b/src/aircraft_list_screen.cpp @@ -90,7 +90,7 @@ bool run(TFT_eSPI& tft) { for (uint8_t i = 0; i < AircraftTable::capacity(); i++) { if (!table[i].valid) continue; if (table[i].distanceKm > rangeKm * 1.05f) continue; - if (SettingsStore::hideGroundVehicles() && table[i].category[0] == 'C') continue; + if (SettingsStore::hideGroundVehicles() && (table[i].category[0] == 'C' || table[i].onGround)) continue; if (AirlineFilter::isHidden(table[i].callsign)) continue; snapshot[count++] = table[i]; } diff --git a/src/main.cpp b/src/main.cpp index 4e8592c..9272f59 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -34,6 +34,7 @@ #include "first_run_language_screen.h" #include "first_run_location_screen.h" #include "first_run_complete_screen.h" +#include "ota_update.h" #include "menu_stars.h" #include "ui_font.h" #include @@ -48,6 +49,8 @@ constexpr uint32_t SWEEP_TICK_MS = 80; constexpr uint32_t STATUS_LINE_UPDATE_MS = 1000; uint32_t lastPollMs = 0; uint32_t lastSweepMs = 0; +bool gOtaUpdateAvailable = false; +char gOtaLatestVersion[16] = {0}; uint32_t lastStatusLineMs = 0; uint32_t lastRenderedVersion = 0xFFFFFFFF; Weather::Condition lastRenderedWeather = Weather::Condition::Unknown; @@ -632,7 +635,24 @@ void setup() { // regardless of when the device was booted. configTime(0, 0, "pool.ntp.org", "time.nist.gov"); setenv("TZ", "CET-1CEST-2,M3.5.0/2,M10.5.0/3", 1); - tzset(); +tzset(); + + // Quick OTA version check during splash screen + SplashScreen::setStatusLine(tft, 1, I18n::t(StringId::OTA_CHECKING)); + uint32_t otaStart = millis(); + while (WifiMgr::getState() != WifiMgr::State::Connected && + millis() - otaStart < 4000) { + MenuStars::update(tft); + delay(100); + } + if (WifiMgr::getState() == WifiMgr::State::Connected) { + auto otaInfo = OtaUpdate::checkForUpdate(); + if (otaInfo.result == OtaUpdate::CheckResult::UpdateAvailable) { + gOtaUpdateAvailable = true; + strncpy(gOtaLatestVersion, otaInfo.latestVersion, sizeof(gOtaLatestVersion) - 1); + } + } + SplashScreen::setStatusLine(tft, 1, ""); AircraftTable::init(); AirlineLookup::init(); @@ -640,7 +660,28 @@ void setup() { NetTask::begin(); - SplashScreen::waitRemaining(tft); +SplashScreen::waitRemaining(tft); + + if (gOtaUpdateAvailable) { + tft.fillScreen(TFT_BLACK); + tft.setTextDatum(MC_DATUM); + tft.setTextColor(TFT_YELLOW, TFT_BLACK); + tft.setTextSize(1); + tft.drawString(String(I18n::t(StringId::OTA_UPDATE_AVAILABLE_PREFIX)) + gOtaLatestVersion, + Config::SCREEN_WIDTH / 2, Config::SCREEN_HEIGHT / 2 - 20); + tft.setTextSize(1); + tft.setTextColor(TFT_DARKGREY, TFT_BLACK); + tft.drawString(String(I18n::t(StringId::MENU_CATEGORY_SYSTEM)) + " > " + String(I18n::t(StringId::MENU_CHECK_UPDATE)), + Config::SCREEN_WIDTH / 2, Config::SCREEN_HEIGHT / 2 + 10); + tft.setTextDatum(TL_DATUM); + MenuStars::reset(); + TouchInput::Point tap; + while (true) { + if (TouchInput::wasTapped(tap)) break; + MenuStars::update(tft); + delay(20); + } + } drawHeader(); updateStatusLine(); diff --git a/src/ota_update.cpp b/src/ota_update.cpp index 98e7743..9e75cfc 100644 --- a/src/ota_update.cpp +++ b/src/ota_update.cpp @@ -27,7 +27,11 @@ namespace { // Numeric version comparison (not string-based, so e.g. "3.10.0" > "3.9.0"). int compareVersions(const char* a, const char* b) { int aMaj, aMin, aPat, bMaj, bMin, bPat; - if (!parseVersion(a, aMaj, aMin, aPat) || !parseVersion(b, bMaj, bMin, bPat)) return 0; + bool aOk = parseVersion(a, aMaj, aMin, aPat); + bool bOk = parseVersion(b, bMaj, bMin, bPat); + if (!aOk && !bOk) return 0; + if (!aOk) return -1; // non-numeric version (e.g. "custom") = older than any real version + if (!bOk) return 1; if (aMaj != bMaj) return aMaj - bMaj; if (aMin != bMin) return aMin - bMin; return aPat - bPat; @@ -104,7 +108,7 @@ CheckInfo checkForUpdate() { int cmp = compareVersions(info.latestVersion, Config::APP_VERSION); info.result = (cmp > 0) ? CheckResult::UpdateAvailable : CheckResult::UpToDate; - Serial.printf("[OTA] Check successful: installed=v%s latest=v%s -> %s\n", Config::APP_VERSION, + Serial.printf("[OTA] Check successful: installed=%s latest=%s -> %s\n", Config::APP_VERSION, info.latestVersion, info.result == CheckResult::UpdateAvailable ? "Update available" : "already up-to-date"); return info; diff --git a/src/radar_screen.cpp b/src/radar_screen.cpp index 351a3e6..0c82297 100644 --- a/src/radar_screen.cpp +++ b/src/radar_screen.cpp @@ -864,7 +864,7 @@ void render(TFT_eSPI& tft, int16_t top) { Aircraft& a = snapshot[i]; if (a.distanceKm > rangeKm * 1.05f) continue; - if (SettingsStore::hideGroundVehicles() && a.category[0] == 'C') continue; + if (SettingsStore::hideGroundVehicles() && (a.category[0] == 'C' || a.onGround)) continue; if (AirlineFilter::isHidden(a.callsign)) continue; @@ -1188,7 +1188,7 @@ bool runTable(TFT_eSPI& tft, int16_t top) { for (uint8_t i = 0; i < AircraftTable::capacity(); i++) { if (!table[i].valid) continue; if (table[i].distanceKm > rangeKm * 1.05f) continue; - if (SettingsStore::hideGroundVehicles() && table[i].category[0] == 'C') continue; + if (SettingsStore::hideGroundVehicles() && (table[i].category[0] == 'C' || table[i].onGround)) continue; if (AirlineFilter::isHidden(table[i].callsign)) continue; uint8_t altMode = SettingsStore::altFilterIndex(); diff --git a/src/route_filter_screen.cpp b/src/route_filter_screen.cpp index 76cfdf2..6926155 100644 --- a/src/route_filter_screen.cpp +++ b/src/route_filter_screen.cpp @@ -185,7 +185,7 @@ bool run(TFT_eSPI& tft) { for (uint8_t i = 0; i < AircraftTable::capacity(); i++) { if (!table[i].valid) continue; if (table[i].distanceKm > rangeKm * 1.05f) continue; - if (SettingsStore::hideGroundVehicles() && table[i].category[0] == 'C') continue; + if (SettingsStore::hideGroundVehicles() && (table[i].category[0] == 'C' || table[i].onGround)) continue; if (AirlineFilter::isHidden(table[i].callsign)) continue; total++; } @@ -199,7 +199,7 @@ bool run(TFT_eSPI& tft) { for (uint8_t i = 0; i < AircraftTable::capacity() && doneCount < total; i++) { if (!table2[i].valid) continue; if (table2[i].distanceKm > rangeKm * 1.05f) continue; - if (SettingsStore::hideGroundVehicles() && table2[i].category[0] == 'C') continue; + if (SettingsStore::hideGroundVehicles() && (table2[i].category[0] == 'C' || table2[i].onGround)) continue; if (AirlineFilter::isHidden(table2[i].callsign)) continue; doneCount++; diff --git a/src/web_export_server.cpp b/src/web_export_server.cpp index 887bd9b..36f78d0 100644 --- a/src/web_export_server.cpp +++ b/src/web_export_server.cpp @@ -484,7 +484,7 @@ namespace { if (!a.valid) continue; if (a.distanceKm > rangeKm * 1.05f) continue; - bool isGroundVehicle = a.category[0] == 'C'; + bool isGroundVehicle = a.category[0] == 'C' || a.onGround; if (hideGround && isGroundVehicle) continue; if (AirlineFilter::isHidden(a.callsign)) continue;