From fe3eec29b8a6c7deb95125d6e7ef227d9e0a6bc3 Mon Sep 17 00:00:00 2001 From: Eiswolf-BG <37225519+Eiswolf-BG@users.noreply.github.com> Date: Thu, 13 Aug 2026 04:13:41 +0200 Subject: [PATCH] Sun-based night dimming; separate marker for Heavy aircraft Night dimming now uses the actual sunrise/sunset at the active location (classic Almanac algorithm) instead of a fixed 22:00-06:00 window, with a fallback to that fixed window while location or time isn't known yet. Applies to both the backlight (main.cpp) and the radar's own color dimming (radar_screen.cpp). Heavy-category aircraft (ADS-B emitter category "A5") now get a distinct marker (larger circle with an outer ring, plus the usual heading line) instead of sharing the orange "notable" ring, on both the device display and the WebUI radar. Note: the orange "notable" ring itself (military/government callsign prefixes) remains unimplemented - Config::NOTABLE_CALLSIGN_PREFIXES has never been defined anywhere in this project. The WebUI radar's "notable" field is hardcoded false until that's actually specified; on the device it was never wired up in the first place. Co-Authored-By: Claude Sonnet 5 --- src/i18n_de.h | 2 +- src/i18n_en.h | 2 +- src/i18n_es.h | 2 +- src/i18n_fr.h | 2 +- src/i18n_it.h | 2 +- src/i18n_tr.h | 2 +- src/main.cpp | 35 ++++++++++--- src/radar_screen.cpp | 71 ++++++++++++++++++++++++-- src/sun_times.cpp | 102 ++++++++++++++++++++++++++++++++++++++ src/sun_times.h | 24 +++++++++ src/web_export_server.cpp | 12 ++++- 11 files changed, 237 insertions(+), 19 deletions(-) create mode 100644 src/sun_times.cpp create mode 100644 src/sun_times.h diff --git a/src/i18n_de.h b/src/i18n_de.h index 8ebae9c..e0d1253 100644 --- a/src/i18n_de.h +++ b/src/i18n_de.h @@ -56,7 +56,7 @@ static const char* const I18N_DE[] = { "WLAN-Netzwerke verwalten", "Standort-Presets", "Bildschirm-Timeout: ", - "Nachtdimmung (22-6 Uhr): ", + "Nachtdimmung (Sonnenzeit): ", "Statistik", "Verlauf", "Logbuch-Dateien", diff --git a/src/i18n_en.h b/src/i18n_en.h index 281aaeb..502c12a 100644 --- a/src/i18n_en.h +++ b/src/i18n_en.h @@ -56,7 +56,7 @@ static const char* const I18N_EN[] = { "Manage WiFi networks", "Location presets", "Screen timeout: ", - "Night dimming (10pm-6am): ", + "Night dimming (sun-based): ", "Statistics", "History chart", "Logbook files", diff --git a/src/i18n_es.h b/src/i18n_es.h index 16f5b83..315172e 100644 --- a/src/i18n_es.h +++ b/src/i18n_es.h @@ -56,7 +56,7 @@ static const char* const I18N_ES[] = { "Gestionar redes WiFi", "Ubicaciones guardadas", "Apagado de pantalla: ", - "Atenuación nocturna (22-6h): ", + "Atenuación nocturna (solar): ", "Estadísticas", "Historial", "Archivos del registro", diff --git a/src/i18n_fr.h b/src/i18n_fr.h index 75db2f5..5b14cfe 100644 --- a/src/i18n_fr.h +++ b/src/i18n_fr.h @@ -56,7 +56,7 @@ static const char* const I18N_FR[] = { "Gérer les réseaux WiFi", "Positions enregistrées", "Extinction écran : ", - "Assombrissement nuit (22h-6h) : ", + "Assombrissement nuit (soleil) : ", "Statistiques", "Historique", "Fichiers du journal", diff --git a/src/i18n_it.h b/src/i18n_it.h index 4d0f1d8..ddcf629 100644 --- a/src/i18n_it.h +++ b/src/i18n_it.h @@ -56,7 +56,7 @@ static const char* const I18N_IT[] = { "Gestisci reti WiFi", "Posizioni salvate", "Spegnimento schermo: ", - "Attenuazione notte (22-6): ", + "Attenuazione notte (solare): ", "Statistiche", "Cronologia", "File del registro", diff --git a/src/i18n_tr.h b/src/i18n_tr.h index 1eb4fde..d297c2c 100644 --- a/src/i18n_tr.h +++ b/src/i18n_tr.h @@ -56,7 +56,7 @@ static const char* const I18N_TR[] = { "WiFi ağlarını yönet", "Konum ön ayarları", "Ekran zaman aşımı: ", - "Gece kısma (22-06): ", + "Gece kısma (güneşe göre): ", "İstatistikler", "Geçmiş", "Kayıt defteri dosyaları", diff --git a/src/main.cpp b/src/main.cpp index 7103e77..40810e5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -16,6 +16,7 @@ #include "wifi_manager.h" #include "location_manager.h" #include "location_presets.h" +#include "sun_times.h" #include "adsb_client.h" #include "touch_input.h" #include "calibration_screen.h" @@ -408,23 +409,43 @@ void updateStatusLine() { } } -// Prueft, ob die aktuelle Lokalzeit im Nachtdimm-Fenster (22:00-06:00) liegt. -// Ueber Mitternacht hinweg gerechnet. Solange die Uhrzeit noch nicht per NTP -// synchronisiert ist, wird false zurueckgegeben statt zu raten (gleiche -// Pruefung wie in updateStatusLine()). +// Prueft, ob gerade Nacht ist (fuer die Nachtdimmung). Nutzt den echten +// Sonnenauf-/untergang am aktiven Standort (siehe sun_times.h), NICHT mehr +// ein festes 22:00-06:00-Fenster - im Sommer war das vorher oft noch hell +// draussen, wenn schon gedimmt wurde, und im Winter blieb es nach 6 Uhr noch +// lange dunkel, ohne dass gedimmt wurde. Solange Standort oder Uhrzeit noch +// nicht bekannt sind (z.B. kurz nach dem Start, bevor NTP/GPS/IP-Geolocation +// fertig sind), faellt die Funktion auf das alte feste Fenster zurueck, +// damit die Nachtdimmung nicht komplett ausfaellt. bool isNightDimHours() { time_t now = time(nullptr); if (now <= 8 * 3600 * 2) return false; struct tm tmNow; localtime_r(&now, &tmNow); + + double lat = 0, lon = 0; + LocationManager::getHomeLocation(lat, lon); + if (lat != 0.0 || lon != 0.0) { + SunTimes::Result sun = SunTimes::compute(lat, lon, tmNow.tm_year + 1900, tmNow.tm_mon + 1, + tmNow.tm_mday, LocationManager::utcOffsetSeconds()); + if (sun.valid) { + if (sun.alwaysDay) return false; + if (sun.alwaysNight) return true; + float hourNow = tmNow.tm_hour + tmNow.tm_min / 60.0f; + return (hourNow < sun.sunriseHour) || (hourNow >= sun.sunsetHour); + } + } + + // Fallback: Standort noch unbekannt. int hour = tmNow.tm_hour; return (hour >= 22 || hour < 6); } -// Sanfte Nachtdimmung des Backlights zwischen 22:00 und 06:00 Uhr, sofern in -// den Einstellungen aktiviert. Der Inaktivitaets-Timeout (screenDimmed) hat -// Vorrang und wird hier nicht ueberschrieben. +// Sanfte Nachtdimmung des Backlights zwischen Sonnenuntergang und +// Sonnenaufgang (siehe isNightDimHours()), sofern in den Einstellungen +// aktiviert. Der Inaktivitaets-Timeout (screenDimmed) hat Vorrang und wird +// hier nicht ueberschrieben. void updateNightDimming() { if (screenDimmed) return; diff --git a/src/radar_screen.cpp b/src/radar_screen.cpp index 8cf3bee..7813abb 100644 --- a/src/radar_screen.cpp +++ b/src/radar_screen.cpp @@ -9,6 +9,7 @@ #include "settings_store.h" #include "led_alert.h" #include "location_manager.h" +#include "sun_times.h" #include "world_map.h" #include "airline_filter.h" #include "aircraft_watchlist.h" @@ -76,6 +77,7 @@ namespace { bool isWatched; bool isGroundVehicle; bool isRotorcraft; + bool isHeavy; }; constexpr uint8_t MAX_HIT_POINTS = Config::MAX_TRACKED_AIRCRAFT; HitPoint hitPoints[MAX_HIT_POINTS]; @@ -203,15 +205,33 @@ namespace { float prevSweepAngleDeg = -1.0f; constexpr float SWEEP_DEGREES_PER_SEC = 45.0f; - // Gleiches Nachtdimm-Fenster wie main.cpp::isNightDimHours() (22:00-06:00, - // ueber Mitternacht hinweg gerechnet). Hier bewusst dupliziert statt - // geteilt, siehe CLAUDE.md-Konvention ("jeder Screen unabhaengig - // lauffaehig, kein gemeinsames Modul fuer solche Kleinigkeiten"). + // Gleiche Logik wie main.cpp::isNightDimHours() - Nacht = zwischen + // Sonnenuntergang und Sonnenaufgang am aktiven Standort (siehe + // sun_times.h), mit Rueckfall auf ein festes 22:00-06:00-Fenster, + // solange Standort/Uhrzeit noch nicht bekannt sind. Hier bewusst + // dupliziert statt geteilt, siehe CLAUDE.md-Konvention ("jeder Screen + // unabhaengig lauffaehig, kein gemeinsames Modul fuer solche + // Kleinigkeiten"). bool isNightHours() { time_t now = time(nullptr); if (now <= 8 * 3600 * 2) return false; // Uhrzeit noch nicht per NTP synchronisiert + struct tm tmNow; localtime_r(&now, &tmNow); + + double lat = 0, lon = 0; + LocationManager::getHomeLocation(lat, lon); + if (lat != 0.0 || lon != 0.0) { + SunTimes::Result sun = SunTimes::compute(lat, lon, tmNow.tm_year + 1900, tmNow.tm_mon + 1, + tmNow.tm_mday, LocationManager::utcOffsetSeconds()); + if (sun.valid) { + if (sun.alwaysDay) return false; + if (sun.alwaysNight) return true; + float hourNow = tmNow.tm_hour + tmNow.tm_min / 60.0f; + return (hourNow < sun.sunriseHour) || (hourNow >= sun.sunsetHour); + } + } + int hour = tmNow.tm_hour; return (hour >= 22 || hour < 6); } @@ -352,6 +372,37 @@ namespace { gfx.drawLine(x, (int16_t)(y - ROTOR_LEN), x, (int16_t)(y + ROTOR_LEN), color); } + // Eigener Marker fuer "Heavy"-Flugzeuge (ADS-B-Emitter-Kategorie "A5" - + // Flugzeuge ueber 136t Starthoechstgewicht, z.B. A380/B747/B777/A330). + // Gleicher Aufbau wie drawAircraftMarker() (Kreis + Kurslinie mit + // Pfeilkopf), aber mit groesserem Kreis und einem zusaetzlichen duennen + // Aussenring - auf den ersten Blick als "groesser/schwerer" erkennbar, + // ohne eine komplett neue Formsprache einzufuehren. Die Farbe bleibt wie + // gewohnt die Hoehenfarbe (colorForAltitude()) - die Form transportiert + // "Heavy", kein Alarm-/Auffaelligkeitszustand. + void drawHeavyMarker(TFT_eSPI& gfx, int16_t x, int16_t y, float headingDeg, uint16_t color) { + gfx.fillCircle(x, y, 6, color); + gfx.drawCircle(x, y, 8, color); + + double rad = headingDeg * PI / 180.0; + int16_t dx = (int16_t)(sin(rad) * 10); + int16_t dy = (int16_t)(-cos(rad) * 10); + int16_t tipX = x + dx; + int16_t tipY = y + dy; + gfx.drawLine(x, y, tipX, tipY, color); + + constexpr double WING_ANGLE_RAD = 150.0 * PI / 180.0; + constexpr int16_t WING_LEN = 4; + double wing1 = rad + WING_ANGLE_RAD; + double wing2 = rad - WING_ANGLE_RAD; + int16_t w1x = tipX + (int16_t)(sin(wing1) * WING_LEN); + int16_t w1y = tipY + (int16_t)(-cos(wing1) * WING_LEN); + int16_t w2x = tipX + (int16_t)(sin(wing2) * WING_LEN); + int16_t w2y = tipY + (int16_t)(-cos(wing2) * WING_LEN); + gfx.drawLine(tipX, tipY, w1x, w1y, color); + gfx.drawLine(tipX, tipY, w2x, w2y, color); + } + void printLineTruncated(TFT_eSPI& gfx, int16_t x, int16_t y, int16_t maxWidth, const String& text) { String s = text; if (gfx.textWidth(s) > maxWidth) { @@ -391,7 +442,7 @@ namespace { // Dieselbe colorForAltitude()-Funktion wie fuer die Flugzeug-Marker // selbst verwenden (mit einer typischen Hoehe je Band) - sonst zeigt - // die Legende bei aktiver Nachtdimmung (22-6 Uhr) die HELLEN Farben, + // die Legende bei aktiver Nachtdimmung (Sonnenunter- bis -aufgang) die HELLEN Farben, // waehrend die Marker/Beschriftungen auf dem Radar bereits gedaempft // sind. Das fuehrte dazu, dass z.B. ein rotes Flugzeug nachts eher // dunkelorange wirkte, obwohl die Legende noch reines Rot zeigte. @@ -899,6 +950,9 @@ void render(TFT_eSPI& tft, int16_t top) { // Darstellung, siehe drawGroundVehicleMarker()/colorForGroundVehicle(). bool isGroundVehicle = a.category[0] == 'C'; bool isRotorcraft = a.category[0] == 'A' && a.category[1] == '7'; + // ADS-B-Emitter-Kategorie "A5" = "Heavy" - eigene Markerform (siehe + // drawHeavyMarker()), unabhaengig von jeglicher Ring-Markierung. + bool isHeavy = a.category[0] == 'A' && a.category[1] == '5'; uint16_t color = isGroundVehicle ? colorForGroundVehicle(tft) : colorForAltitude(tft, a.altBaroFt); bool isSelected = selectedHex[0] && strcmp(a.hex, selectedHex) == 0; bool isEmergency = SettingsStore::emergencyAlertEnabled() && isEmergencySquawk(a.squawk); @@ -914,6 +968,8 @@ void render(TFT_eSPI& tft, int16_t top) { drawGroundVehicleMarker(tft, pt.x, pt.y, color); } else if (isRotorcraft) { drawHelicopterMarker(tft, pt.x, pt.y, color); + } else if (isHeavy) { + drawHeavyMarker(tft, pt.x, pt.y, a.headingDeg, color); } else { drawAircraftMarker(tft, pt.x, pt.y, a.headingDeg, color); } @@ -940,6 +996,7 @@ void render(TFT_eSPI& tft, int16_t top) { hitPoints[i].isWatched = isWatched; hitPoints[i].isGroundVehicle = isGroundVehicle; hitPoints[i].isRotorcraft = isRotorcraft; + hitPoints[i].isHeavy = isHeavy; strncpy(hitPoints[i].hex, a.hex, sizeof(hitPoints[i].hex) - 1); strncpy(hitPoints[i].callsign, a.callsign, sizeof(hitPoints[i].callsign) - 1); } @@ -1051,6 +1108,8 @@ void tick(TFT_eSPI& tft, int16_t top, uint32_t deltaMs) { drawGroundVehicleMarker(tft, hp.x, hp.y, TFT_BLACK); } else if (hp.isRotorcraft) { drawHelicopterMarker(tft, hp.x, hp.y, TFT_BLACK); + } else if (hp.isHeavy) { + drawHeavyMarker(tft, hp.x, hp.y, hp.headingDeg, TFT_BLACK); } else { drawAircraftMarker(tft, hp.x, hp.y, hp.headingDeg, TFT_BLACK); } @@ -1069,6 +1128,8 @@ void tick(TFT_eSPI& tft, int16_t top, uint32_t deltaMs) { drawGroundVehicleMarker(tft, hp.x, hp.y, hp.color); } else if (hp.isRotorcraft) { drawHelicopterMarker(tft, hp.x, hp.y, hp.color); + } else if (hp.isHeavy) { + drawHeavyMarker(tft, hp.x, hp.y, hp.headingDeg, hp.color); } else { drawAircraftMarker(tft, hp.x, hp.y, hp.headingDeg, hp.color); } diff --git a/src/sun_times.cpp b/src/sun_times.cpp new file mode 100644 index 0000000..5de549d --- /dev/null +++ b/src/sun_times.cpp @@ -0,0 +1,102 @@ +#include "sun_times.h" +#include + +namespace SunTimes { + +namespace { + constexpr double DEG2RAD = 0.017453292519943295; + constexpr double RAD2DEG = 57.29577951308232; + + int dayOfYear(int year, int month, int day) { + static const int cum[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + int n = cum[month - 1] + day; + bool leap = (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)); + if (leap && month > 2) n += 1; + return n; + } + + // Klassischer "Sunrise/Sunset Algorithm" (Almanac for Computers, 1990, + // weit verbreitete Formel). sunrise=true fuer Sonnenaufgang, false fuer + // Sonnenuntergang. Gibt false zurueck, wenn die Sonne an diesem Tag/ + // Breitengrad ueberhaupt nicht auf-/untergeht (Polartag/-nacht) - dann + // ist outHour unveraendert. + bool calc(double lat, double lon, int N, int32_t utcOffsetSeconds, bool sunrise, float& outHour) { + double lngHour = lon / 15.0; + double t = sunrise ? (N + ((6.0 - lngHour) / 24.0)) : (N + ((18.0 - lngHour) / 24.0)); + + double M = (0.9856 * t) - 3.289; + + double L = M + (1.916 * sin(M * DEG2RAD)) + (0.020 * sin(2 * M * DEG2RAD)) + 282.634; + L = fmod(L, 360.0); + if (L < 0) L += 360.0; + + double RA = RAD2DEG * atan(0.91764 * tan(L * DEG2RAD)); + RA = fmod(RA, 360.0); + if (RA < 0) RA += 360.0; + + // RA muss im selben 90-Grad-Quadranten wie L liegen (atan() liefert + // nur Werte im Bereich -90..90 Grad, muss also entsprechend + // "zurueckgeklappt" werden). + double lQuadrant = floor(L / 90.0) * 90.0; + double raQuadrant = floor(RA / 90.0) * 90.0; + RA = RA + (lQuadrant - raQuadrant); + RA = RA / 15.0; // Grad -> Stunden + + double sinDec = 0.39782 * sin(L * DEG2RAD); + double cosDec = cos(asin(sinDec)); + + constexpr double ZENITH = 90.833; // offizieller Zenit inkl. atm. Refraktion + double cosH = (cos(ZENITH * DEG2RAD) - (sinDec * sin(lat * DEG2RAD))) / (cosDec * cos(lat * DEG2RAD)); + + if (cosH > 1.0 || cosH < -1.0) return false; // Polartag/-nacht + + double H = sunrise ? (360.0 - RAD2DEG * acos(cosH)) : (RAD2DEG * acos(cosH)); + H = H / 15.0; + + double T = H + RA - (0.06571 * t) - 6.622; + + double UT = fmod(T - lngHour, 24.0); + if (UT < 0) UT += 24.0; + + double local = fmod(UT + (utcOffsetSeconds / 3600.0), 24.0); + if (local < 0) local += 24.0; + + outHour = (float)local; + return true; + } +} + +Result compute(double lat, double lon, int year, int month, int day, int32_t utcOffsetSeconds) { + Result r; + if (lat == 0.0 && lon == 0.0) { + r.valid = false; + return r; + } + + int N = dayOfYear(year, month, day); + + float sunrise = 0, sunset = 0; + bool riseOk = calc(lat, lon, N, utcOffsetSeconds, true, sunrise); + bool setOk = calc(lat, lon, N, utcOffsetSeconds, false, sunset); + + if (!riseOk || !setOk) { + // Polartag (Sonne geht nicht unter) vs. Polarnacht (Sonne geht nicht + // auf): grobe Naeherung ueber "hohe Sonne im Sommerhalbjahr der + // jeweiligen Hemisphaere = Polartag, sonst Polarnacht" - reicht fuer + // eine Nachtdimmung an den seltenen Orten/Tagen, an denen das + // ueberhaupt vorkommt, voellig aus. + bool northernSummerHalf = (N > 79 && N < 265); // grob Fruehlings-/Herbst-Tagundnachtgleiche + bool polarDay = (lat > 0) == northernSummerHalf; + r.valid = true; + r.alwaysDay = polarDay; + r.alwaysNight = !polarDay; + return r; + } + + r.valid = true; + r.sunriseHour = sunrise; + r.sunsetHour = sunset; + return r; +} + +} diff --git a/src/sun_times.h b/src/sun_times.h new file mode 100644 index 0000000..9f5d159 --- /dev/null +++ b/src/sun_times.h @@ -0,0 +1,24 @@ +#pragma once +#include + +// Berechnet Sonnenauf-/untergang (lokale Zeit) fuer einen gegebenen Ort und +// Tag - Grundlage fuer die standortbasierte Nachtdimmung (siehe main.cpp:: +// isNightDimHours()), die das vorherige feste 22:00-06:00-Fenster ersetzt. +namespace SunTimes { + + struct Result { + bool valid = false; // false = Standort noch unbekannt (lat/lon == 0,0) + bool alwaysDay = false; // Polartag: Sonne geht heute an diesem Ort nicht unter + bool alwaysNight = false; // Polarnacht: Sonne geht heute an diesem Ort nicht auf + float sunriseHour = 0; // Lokale Dezimalstunde (0-24), nur gueltig wenn weder + float sunsetHour = 0; // alwaysDay noch alwaysNight gesetzt ist. + }; + + // year/month/day sind lokale Kalenderdatumswerte (z.B. aus localtime_r()), + // utcOffsetSeconds die bekannte Zeitzonenverschiebung (siehe + // LocationManager::utcOffsetSeconds()). Nutzt den klassischen "Almanac"- + // Sonnenauf-/untergangsalgorithmus (Sonnenzenit 90.833 Grad, beruecksichtigt + // atmosphaerische Refraktion) - Genauigkeit liegt typischerweise im Bereich + // weniger Minuten, fuer eine sanfte Backlight-Dimmung mehr als ausreichend. + Result compute(double lat, double lon, int year, int month, int day, int32_t utcOffsetSeconds); +} diff --git a/src/web_export_server.cpp b/src/web_export_server.cpp index d57616a..00cc64e 100644 --- a/src/web_export_server.cpp +++ b/src/web_export_server.cpp @@ -117,6 +117,8 @@ namespace { html += "ctx.fillStyle=color;ctx.strokeStyle=color;"; html += "if(a.ground_vehicle){ctx.fillRect(x-3,y-3,6,6);}"; html += "else if(a.rotorcraft){ctx.beginPath();ctx.moveTo(x,y-5);ctx.lineTo(x+5,y);ctx.lineTo(x,y+5);ctx.lineTo(x-5,y);ctx.closePath();ctx.fill();}"; + html += "else if(a.heavy){ctx.beginPath();ctx.arc(x,y,5,0,Math.PI*2);ctx.fill();ctx.beginPath();ctx.arc(x,y,7,0,Math.PI*2);ctx.stroke();"; + html += "var hr2=a.track_deg*Math.PI/180;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x+10*Math.sin(hr2),y-10*Math.cos(hr2));ctx.stroke();}"; html += "else{ctx.beginPath();ctx.arc(x,y,4,0,Math.PI*2);ctx.fill();"; html += "var hr=a.track_deg*Math.PI/180;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x+10*Math.sin(hr),y-10*Math.cos(hr));ctx.stroke();}"; html += "if(a.emergency){ctx.strokeStyle='#ff3b3b';ctx.beginPath();ctx.arc(x,y,9,0,Math.PI*2);ctx.stroke();}"; @@ -366,9 +368,16 @@ namespace { if (AirlineFilter::isHidden(a.callsign)) continue; bool isRotorcraft = a.category[0] == 'A' && a.category[1] == '7'; + bool isHeavy = isHeavyCategoryWeb(a.category); bool isEmergency = emergencyOn && isEmergencySquawkWeb(a.squawk); bool isWatched = watchOn && AircraftWatchlist::isWatched(a.callsign); - bool isNotable = isHeavyCategoryWeb(a.category); + // "notable" (oranger Ring) ist fuer auffaellige Rufzeichen + // (Militaer/Regierung) reserviert - Heavy-Flugzeuge bekommen + // stattdessen die eigene Markerform (siehe "heavy" unten). Es + // gibt aktuell aber keine Militaer-/Regierungs-Praefixliste im + // Projekt (auch nicht am Geraete-Display, siehe radar_screen.cpp) + // - "notable" bleibt daher bis auf Weiteres immer false. + bool isNotable = false; JsonObject o = arr.add(); o["hex"] = a.hex; @@ -379,6 +388,7 @@ namespace { o["track_deg"] = a.headingDeg; o["ground_vehicle"] = isGroundVehicle; o["rotorcraft"] = isRotorcraft; + o["heavy"] = isHeavy; o["emergency"] = isEmergency; o["watched"] = isWatched; o["notable"] = isNotable;