diff --git a/src/i18n_de.h b/src/i18n_de.h index e0d1253..916d436 100644 --- a/src/i18n_de.h +++ b/src/i18n_de.h @@ -246,7 +246,7 @@ static const char* const I18N_DE[] = { "Prüfung fehlgeschlagen. WLAN prüfen.", "Bereits aktuell: v", "Update verfügbar: v", - "Ein neues Firmware-Update wird heruntergeladen und installiert. Bitte WLAN-Verbindung und Stromversorgung während des Vorgangs nicht unterbrechen. Nach der Installation wirst du zum Neustart aufgefordert.", + "Ein neues Firmware-Update wird heruntergeladen und installiert. Bitte WLAN-Verbindung und Stromversorgung während des Vorgangs nicht unterbrechen. Nach der Installation wirst du zum Neustart aufgefordert. Falls die WebUI-Seite (Logbuch/Radar) in einem Browser geöffnet ist, bitte vorher schließen - sie fragt regelmäßig Daten vom Gerät ab und kann den Download sonst stören.", "Installiere Update ", "Update fehlgeschlagen", "Update installiert", diff --git a/src/i18n_en.h b/src/i18n_en.h index 502c12a..7af1774 100644 --- a/src/i18n_en.h +++ b/src/i18n_en.h @@ -247,7 +247,7 @@ static const char* const I18N_EN[] = { "Check failed. Check your WiFi connection.", "Already up to date: v", "Update available: v", - "A new firmware update will be downloaded and installed. Please don't interrupt the WiFi connection or power supply during this process. You'll be asked to restart once installation is complete.", + "A new firmware update will be downloaded and installed. Please don't interrupt the WiFi connection or power supply during this process. You'll be asked to restart once installation is complete. If the WebUI page (logbook/radar) is open in a browser, please close it first - it regularly polls the device for data and can interfere with the download otherwise.", "Installing update ", "Update failed", "Update installed", diff --git a/src/i18n_es.h b/src/i18n_es.h index 315172e..9e086b2 100644 --- a/src/i18n_es.h +++ b/src/i18n_es.h @@ -246,7 +246,7 @@ static const char* const I18N_ES[] = { "Error al comprobar. Revisa tu conexión WiFi.", "Ya actualizado: v", "Actualización disponible: v", - "Se descargará e instalará una nueva actualización de firmware. No interrumpas la conexión WiFi ni la alimentación durante este proceso. Se te pedirá reiniciar una vez completada la instalación.", + "Se descargará e instalará una nueva actualización de firmware. No interrumpas la conexión WiFi ni la alimentación durante este proceso. Se te pedirá reiniciar una vez completada la instalación. Si la página WebUI (registro/radar) está abierta en un navegador, ciérrala primero - consulta datos del dispositivo regularmente y podría interferir con la descarga.", "Instalando actualización ", "Error al actualizar", "Actualización instalada", diff --git a/src/i18n_fr.h b/src/i18n_fr.h index 5b14cfe..024b116 100644 --- a/src/i18n_fr.h +++ b/src/i18n_fr.h @@ -246,7 +246,7 @@ static const char* const I18N_FR[] = { "Échec de la vérification. Vérifiez votre connexion WiFi.", "Déjà à jour : v", "Mise à jour disponible : v", - "Une nouvelle mise à jour du micrologiciel va être téléchargée et installée. Merci de ne pas interrompre la connexion WiFi ni l'alimentation pendant ce processus. Un redémarrage vous sera demandé une fois l'installation terminée.", + "Une nouvelle mise à jour du micrologiciel va être téléchargée et installée. Merci de ne pas interrompre la connexion WiFi ni l'alimentation pendant ce processus. Un redémarrage vous sera demandé une fois l'installation terminée. Si la page WebUI (journal/radar) est ouverte dans un navigateur, merci de la fermer au préalable - elle interroge régulièrement l'appareil et pourrait sinon perturber le téléchargement.", "Installation de la mise à jour ", "Échec de la mise à jour", "Mise à jour installée", diff --git a/src/i18n_it.h b/src/i18n_it.h index ddcf629..91b1ce0 100644 --- a/src/i18n_it.h +++ b/src/i18n_it.h @@ -246,7 +246,7 @@ static const char* const I18N_IT[] = { "Verifica fallita. Controlla la connessione WiFi.", "Già aggiornato: v", "Aggiornamento disponibile: v", - "Un nuovo aggiornamento del firmware verrà scaricato e installato. Non interrompere la connessione WiFi o l'alimentazione durante questo processo. Al termine dell'installazione ti verrà chiesto di riavviare.", + "Un nuovo aggiornamento del firmware verrà scaricato e installato. Non interrompere la connessione WiFi o l'alimentazione durante questo processo. Al termine dell'installazione ti verrà chiesto di riavviare. Se la pagina WebUI (registro/radar) è aperta in un browser, chiudila prima - interroga regolarmente il dispositivo e potrebbe interferire con il download.", "Installazione aggiornamento ", "Aggiornamento fallito", "Aggiornamento installato", diff --git a/src/i18n_tr.h b/src/i18n_tr.h index d297c2c..0e36c3b 100644 --- a/src/i18n_tr.h +++ b/src/i18n_tr.h @@ -246,7 +246,7 @@ static const char* const I18N_TR[] = { "Kontrol başarısız. WiFi bağlantınızı kontrol edin.", "Zaten güncel: v", "Güncelleme mevcut: v", - "Yeni bir donanım yazılımı güncellemesi indirilip yüklenecek. Lütfen bu işlem sırasında WiFi bağlantısını veya güç kaynağını kesmeyin. Kurulum tamamlandığında yeniden başlatmanız istenecek.", + "Yeni bir donanım yazılımı güncellemesi indirilip yüklenecek. Lütfen bu işlem sırasında WiFi bağlantısını veya güç kaynağını kesmeyin. Kurulum tamamlandığında yeniden başlatmanız istenecek. WebUI sayfası (kayıt defteri/radar) bir tarayıcıda açıksa, lütfen önce kapatın - cihazdan düzenli olarak veri istediği için indirmeyi aksatabilir.", "Güncelleme yükleniyor ", "Güncelleme başarısız", "Güncelleme yüklendi", diff --git a/src/ota_update.cpp b/src/ota_update.cpp index fd69e7d..1c6af1d 100644 --- a/src/ota_update.cpp +++ b/src/ota_update.cpp @@ -1,5 +1,6 @@ #include "ota_update.h" #include "config.h" +#include #include #include #include @@ -68,6 +69,9 @@ CheckInfo checkForUpdate() { strncpy(info.latestVersion, (tag[0] == 'v' || tag[0] == 'V') ? tag + 1 : tag, sizeof(info.latestVersion) - 1); + // Der Release-Workflow (siehe CLAUDE.md im Repo) laedt das rohe + // Build-Artefakt unveraendert als "firmware.bin" ins Release hoch - + // keine Umbenennung mehr noetig. JsonArray assets = doc["assets"]; for (JsonObject asset : assets) { const char* name = asset["name"] | ""; @@ -86,6 +90,15 @@ CheckInfo checkForUpdate() { } bool performUpdate(const char* url, void (*onProgress)(uint8_t percent)) { + // Diagnose-Logging (nur ueber USB-Seriell sichtbar, kein Einfluss auf + // die UI) - vorher wurde bei einem Fehlschlag nur ein simples "true/ + // false" nach aussen gegeben, ohne den eigentlichen Grund (Timeout, + // TLS-Fehler, HTTP-Statuscode...) festzuhalten. Damit laesst sich ein + // fehlgeschlagener OTA-Versuch am Seriell-Monitor nachvollziehen, statt + // erneut raten zu muessen. + Serial.printf("[OTA] Start: url=%s freeHeap=%u RSSI=%ddBm\n", url, + (unsigned)ESP.getFreeHeap(), WiFi.RSSI()); + WiFiClientSecure client; client.setInsecure(); client.setTimeout(15000); @@ -108,9 +121,29 @@ bool performUpdate(const char* url, void (*onProgress)(uint8_t percent)) { if (onProgress && total > 0) { onProgress((uint8_t)((cur * 100) / total)); } + // Nur gelegentlich loggen (alle ~10%), sonst quillt der Seriell- + // Monitor bei grossen Dateien mit hunderten Zeilen ueber. + static int8_t lastLoggedPercent = -1; + if (total > 0) { + int8_t pct = (int8_t)((cur * 100) / total); + if (pct != lastLoggedPercent && pct % 10 == 0) { + lastLoggedPercent = pct; + Serial.printf("[OTA] Fortschritt: %d%% (%d/%d Bytes) freeHeap=%u\n", pct, cur, total, + (unsigned)ESP.getFreeHeap()); + } + } }); t_httpUpdate_return result = httpUpdate.update(client, url); + + if (result != HTTP_UPDATE_OK) { + Serial.printf("[OTA] Fehlgeschlagen: result=%d error=%d (%s) freeHeap=%u\n", (int)result, + httpUpdate.getLastError(), httpUpdate.getLastErrorString().c_str(), + (unsigned)ESP.getFreeHeap()); + } else { + Serial.println("[OTA] Erfolgreich heruntergeladen und geflasht."); + } + return result == HTTP_UPDATE_OK; } diff --git a/src/web_export_server.cpp b/src/web_export_server.cpp index 00cc64e..a4c6790 100644 --- a/src/web_export_server.cpp +++ b/src/web_export_server.cpp @@ -10,6 +10,7 @@ #include #include #include +#include namespace WebExportServer { @@ -44,13 +45,15 @@ namespace { return false; } - // "Auffaellig" beschraenkt sich aktuell auf die Heavy-Kategorie (ADS-B - // Emitter-Kategorie "A5") - der Teil ueber Militaer-/Regierungs- - // Rufzeichen-Praefixe (Config::NOTABLE_CALLSIGN_PREFIXES) ist NICHT - // umgesetzt, weil diese Konstante nirgends im Projekt existiert (auch - // nicht in radar_screen.cpp) - das zugehoerige Feature wurde bisher nie - // tatsaechlich spezifiziert/implementiert. Sobald es das gibt, hier den - // Praefix-Abgleich ergaenzen, analog zu isEmergencySquawkWeb() oben. + // "Auffaellig" (oranger Ring) beschraenkt sich aktuell auf gar nichts - + // der Teil ueber Militaer-/Regierungs-Rufzeichen-Praefixe + // (Config::NOTABLE_CALLSIGN_PREFIXES) ist NICHT umgesetzt, weil diese + // Konstante nirgends im Projekt existiert (auch nicht in + // radar_screen.cpp) - das zugehoerige Feature wurde bisher nie + // tatsaechlich spezifiziert/implementiert. "notable" wird deshalb unten + // in handleRadarJson() fest auf false gesetzt. Sobald es eine echte + // Praefixliste gibt, hier eine isNotableCallsignWeb()-Funktion analog zu + // isEmergencySquawkWeb() ergaenzen. bool isHeavyCategoryWeb(const char* category) { return category[0] == 'A' && category[1] == '5'; } @@ -78,8 +81,12 @@ namespace { html += ".addbtn:hover{background:#39ff14;color:#0a0f0d;}"; html += "input[type=text]{background:#0a0f0d;color:#39ff14;border:1px solid #39ff14;border-radius:4px;padding:5px 8px;font-family:inherit;}"; html += "nav{margin-bottom:10px;}nav a{color:#39ff14;margin-right:16px;}"; - html += "#radarCanvas{width:100%;max-width:400px;height:auto;background:#05100a;border:1px solid #1f3a2b;border-radius:8px;display:block;}"; + html += "#radarCanvas{width:100%;max-width:400px;height:auto;background:#05100a;border:1px solid #1f3a2b;border-radius:8px;display:block;cursor:pointer;}"; html += "#radarStatus{font-size:12px;color:#7a9a86;margin-top:4px;}"; + html += "#radarControls{font-size:12px;margin-bottom:8px;}"; + html += "#radarControls select{background:#0a0f0d;color:#39ff14;border:1px solid #39ff14;border-radius:4px;padding:2px 6px;font-family:inherit;}"; + html += "#acInfo{display:none;max-width:400px;margin-top:8px;padding:8px 10px;border:1px solid #39ff14;border-radius:6px;font-size:13px;line-height:1.7;}"; + html += "#acInfo a{color:#ff3b3b;text-decoration:none;border:1px solid #ff3b3b;border-radius:4px;padding:2px 8px;display:inline-block;margin-top:4px;}"; html += ""; html += "

" + title + "

"; return html; @@ -91,24 +98,73 @@ namespace { // fetch()-Polling statt WebSocket/SSE gehalten - deutlich weniger Code // und Speicherbedarf auf dem ESP32, und fuer eine gelegentlich vom Handy // aus aufgerufene Seite voellig ausreichend. + // + // Der Reichweiten-Waehler ("; + for (uint8_t i = 0; i < Config::RANGE_STEP_COUNT; i++) { + bool isDefault = fabsf(Config::RANGE_STEPS_KM[i] - deviceRangeKm) < 0.5f; + html += "