feat: improve update progress reporting and enhance WebSocket notifications
This commit is contained in:
		| @@ -157,25 +157,70 @@ | |||||||
|  |  | ||||||
|         // WebSocket für Update-Progress |         // WebSocket für Update-Progress | ||||||
|         const ws = new WebSocket('ws://' + window.location.host + '/ws'); |         const ws = new WebSocket('ws://' + window.location.host + '/ws'); | ||||||
|  |         let updateInProgress = false; | ||||||
|  |  | ||||||
|         ws.onmessage = function(event) { |         ws.onmessage = function(event) { | ||||||
|             try { |             try { | ||||||
|                 const data = JSON.parse(event.data); |                 const data = JSON.parse(event.data); | ||||||
|                 if (data.type === "updateProgress") { |                 if (data.type === "updateProgress" && updateInProgress) { | ||||||
|                     progressContainer.style.display = 'block'; |                     progressContainer.style.display = 'block'; | ||||||
|  |                      | ||||||
|  |                     // Setze den Fortschritt nur wenn er größer ist als der aktuelle | ||||||
|  |                     const currentProgress = parseInt(progress.textContent); | ||||||
|  |                     const newProgress = parseInt(data.progress); | ||||||
|  |                     if (isNaN(currentProgress) || newProgress > currentProgress) { | ||||||
|                         progress.style.width = data.progress + '%'; |                         progress.style.width = data.progress + '%'; | ||||||
|                         progress.textContent = data.progress + '%'; |                         progress.textContent = data.progress + '%'; | ||||||
|                     } |                     } | ||||||
|  |                      | ||||||
|  |                     // Zeige verschiedene Status-Nachrichten | ||||||
|  |                     if (data.status === "finalizing") { | ||||||
|  |                         status.textContent = "Finalizing update..."; | ||||||
|  |                         status.classList.add('success'); | ||||||
|  |                         status.style.display = 'block'; | ||||||
|  |                     } else if (data.status === "complete" || data.status === "success") { | ||||||
|  |                         status.textContent = "Update successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                         status.classList.add('success'); | ||||||
|  |                         status.style.display = 'block'; | ||||||
|  |                          | ||||||
|  |                         // Versuche die WebSocket-Verbindung sauber zu schließen | ||||||
|  |                         try { | ||||||
|  |                             ws.close(); | ||||||
|  |                         } catch (e) { | ||||||
|  |                             console.log('WebSocket already closed'); | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         setTimeout(() => { | ||||||
|  |                             window.location.href = '/'; | ||||||
|  |                         }, 30000); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|             } catch (e) { |             } catch (e) { | ||||||
|                 console.error('WebSocket message error:', e); |                 console.error('WebSocket message error:', e); | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
|         ws.onclose = function() { |         ws.onclose = function() { | ||||||
|             // Wenn der WebSocket geschlossen wird während eines Updates, zeige eine Nachricht |             // Wenn das Update läuft und der Fortschritt hoch ist, zeige Success | ||||||
|             if (progressContainer.style.display !== 'none' && progress.style.width !== '100%') { |             if (updateInProgress) { | ||||||
|                 status.textContent = "Connection lost. Update may still be in progress..."; |                 const currentProgress = parseInt(progress.textContent); | ||||||
|  |                 if (!isNaN(currentProgress) && currentProgress >= 90) { | ||||||
|  |                     status.textContent = "Update appears successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                     status.classList.add('success'); | ||||||
|  |                     status.style.display = 'block'; | ||||||
|  |                      | ||||||
|  |                     setTimeout(() => { | ||||||
|  |                         window.location.href = '/'; | ||||||
|  |                     }, 30000); | ||||||
|  |                 } else { | ||||||
|  |                     status.textContent = "Connection lost. Please wait 30 seconds and check if the update was successful..."; | ||||||
|                     status.classList.add('warning'); |                     status.classList.add('warning'); | ||||||
|                     status.style.display = 'block'; |                     status.style.display = 'block'; | ||||||
|  |                      | ||||||
|  |                     setTimeout(() => { | ||||||
|  |                         window.location.href = '/'; | ||||||
|  |                     }, 30000); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|  |  | ||||||
| @@ -188,6 +233,7 @@ | |||||||
|                 alert('Please select a file.'); |                 alert('Please select a file.'); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|  |              | ||||||
|             // Validate file name pattern |             // Validate file name pattern | ||||||
|             if (updateType === 'firmware' && !file.name.startsWith('upgrade_filaman_firmware_')) { |             if (updateType === 'firmware' && !file.name.startsWith('upgrade_filaman_firmware_')) { | ||||||
|                 alert('Please select a valid firmware file (upgrade_filaman_firmware_*.bin)'); |                 alert('Please select a valid firmware file (upgrade_filaman_firmware_*.bin)'); | ||||||
| @@ -198,13 +244,13 @@ | |||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|              |              | ||||||
|  |             updateInProgress = true; | ||||||
|             progressContainer.style.display = 'block'; |             progressContainer.style.display = 'block'; | ||||||
|             status.style.display = 'none'; |             status.style.display = 'none'; | ||||||
|             status.className = 'status'; |             status.className = 'status'; | ||||||
|             // Reset progress bar |  | ||||||
|             progress.style.width = '0%'; |             progress.style.width = '0%'; | ||||||
|             progress.textContent = '0%'; |             progress.textContent = '0%'; | ||||||
|             // Disable both forms during update |              | ||||||
|             document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = true); |             document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = true); | ||||||
|  |  | ||||||
|             const xhr = new XMLHttpRequest(); |             const xhr = new XMLHttpRequest(); | ||||||
| @@ -215,44 +261,72 @@ | |||||||
|                     try { |                     try { | ||||||
|                         const response = JSON.parse(xhr.responseText); |                         const response = JSON.parse(xhr.responseText); | ||||||
|                         if (response.success) { |                         if (response.success) { | ||||||
|                             status.textContent = "Update successful! Restarting device... The page will reload in 30 seconds."; |                             if (progress.textContent !== '100%') { | ||||||
|                             status.classList.add('success'); |  | ||||||
|                             status.style.display = 'block'; |  | ||||||
|                              |  | ||||||
|                             // Setze Progress auf 100% |  | ||||||
|                                 progress.style.width = '100%'; |                                 progress.style.width = '100%'; | ||||||
|                                 progress.textContent = '100%'; |                                 progress.textContent = '100%'; | ||||||
|                              |                             } | ||||||
|                             // Automatischer Redirect nach 30 Sekunden |                             status.textContent = "Update successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                             status.classList.add('success'); | ||||||
|  |                             status.style.display = 'block'; | ||||||
|                             setTimeout(() => { |                             setTimeout(() => { | ||||||
|                                 window.location.href = '/'; |                                 window.location.href = '/'; | ||||||
|                             }, 30000); |                             }, 30000); | ||||||
|                         } else { |                         } else { | ||||||
|  |                             updateInProgress = false; | ||||||
|                             status.textContent = response.message || "Update failed"; |                             status.textContent = response.message || "Update failed"; | ||||||
|                             status.classList.add('error'); |                             status.classList.add('error'); | ||||||
|                             status.style.display = 'block'; |                             status.style.display = 'block'; | ||||||
|                             document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); |                             document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); | ||||||
|                         } |                         } | ||||||
|                     } catch (e) { |                     } catch (e) { | ||||||
|                         status.textContent = "Error: Invalid server response"; |                         if (progress.textContent === '100%') { | ||||||
|                         status.classList.add('error'); |                             // Wenn 100% erreicht wurden, nehmen wir an, dass das Update erfolgreich war | ||||||
|  |                             status.textContent = "Update appears successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                             status.classList.add('success'); | ||||||
|                             status.style.display = 'block'; |                             status.style.display = 'block'; | ||||||
|                         document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); |                             setTimeout(() => { | ||||||
|  |                                 window.location.href = '/'; | ||||||
|  |                             }, 30000); | ||||||
|  |                         } else { | ||||||
|  |                             handleUpdateError("Invalid server response"); | ||||||
|  |                         } | ||||||
|                     } |                     } | ||||||
|                 } else { |                 } else { | ||||||
|                     status.textContent = "Update failed with status: " + xhr.status; |                     if (progress.textContent === '100%') { | ||||||
|                     status.classList.add('error'); |                         // Bei 100% Fortschritt gehen wir von einem erfolgreichen Update aus | ||||||
|  |                         status.textContent = "Update appears successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                         status.classList.add('success'); | ||||||
|                         status.style.display = 'block'; |                         status.style.display = 'block'; | ||||||
|                     document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); |                         setTimeout(() => { | ||||||
|  |                             window.location.href = '/'; | ||||||
|  |                         }, 30000); | ||||||
|  |                     } else { | ||||||
|  |                         handleUpdateError("Server error: " + xhr.status); | ||||||
|  |                     } | ||||||
|                 } |                 } | ||||||
|             }; |             }; | ||||||
|              |              | ||||||
|             xhr.onerror = function() { |             xhr.onerror = function() { | ||||||
|                 status.textContent = "Network error during update"; |                 if (progress.textContent === '100%') { | ||||||
|  |                     // Bei 100% Fortschritt gehen wir von einem erfolgreichen Update aus | ||||||
|  |                     status.textContent = "Update appears successful! Device is restarting... Page will reload in 30 seconds."; | ||||||
|  |                     status.classList.add('success'); | ||||||
|  |                     status.style.display = 'block'; | ||||||
|  |                     setTimeout(() => { | ||||||
|  |                         window.location.href = '/'; | ||||||
|  |                     }, 30000); | ||||||
|  |                 } else { | ||||||
|  |                     handleUpdateError("Network error during update"); | ||||||
|  |                 } | ||||||
|  |             }; | ||||||
|  |  | ||||||
|  |             function handleUpdateError(message) { | ||||||
|  |                 updateInProgress = false; | ||||||
|  |                 status.textContent = message; | ||||||
|                 status.classList.add('error'); |                 status.classList.add('error'); | ||||||
|                 status.style.display = 'block'; |                 status.style.display = 'block'; | ||||||
|                 document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); |                 document.querySelectorAll('form input[type=submit]').forEach(btn => btn.disabled = false); | ||||||
|             }; |             } | ||||||
|  |  | ||||||
|             const formData = new FormData(); |             const formData = new FormData(); | ||||||
|             formData.append('update', file); |             formData.append('update', file); | ||||||
|   | |||||||
| @@ -376,15 +376,19 @@ void setupWebserver(AsyncWebServer &server) { | |||||||
|     // Update-Handler mit verbesserter Fehlerbehandlung |     // Update-Handler mit verbesserter Fehlerbehandlung | ||||||
|     server.on("/update", HTTP_POST,  |     server.on("/update", HTTP_POST,  | ||||||
|         [](AsyncWebServerRequest *request) { |         [](AsyncWebServerRequest *request) { | ||||||
|             // Nach Update-Abschluss |  | ||||||
|             bool success = !Update.hasError(); |             bool success = !Update.hasError(); | ||||||
|              |              | ||||||
|             // Bei SPIFFS Update und Erfolg: Restore Configs vor dem Neustart |  | ||||||
|             if (success && currentUpdateCommand == U_SPIFFS) { |             if (success && currentUpdateCommand == U_SPIFFS) { | ||||||
|                 restoreJsonConfigs(); |                 restoreJsonConfigs(); | ||||||
|  |                 delay(200);  // Warte auf Restore-Abschluss | ||||||
|             } |             } | ||||||
|              |              | ||||||
|             String message = success ? "Update successful" : String("Update failed: ") + Update.errorString(); |             String message = success ? "Update successful" : String("Update failed: ") + Update.errorString(); | ||||||
|  |              | ||||||
|  |             // Sende finale Bestätigung über WebSocket mit eindeutigem Status | ||||||
|  |             ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"complete\",\"success\":true}"); | ||||||
|  |             delay(1000);  // Längerer Delay für WebSocket | ||||||
|  |              | ||||||
|             AsyncWebServerResponse *response = request->beginResponse( |             AsyncWebServerResponse *response = request->beginResponse( | ||||||
|                 success ? 200 : 400, |                 success ? 200 : 400, | ||||||
|                 "application/json", |                 "application/json", | ||||||
| @@ -394,26 +398,26 @@ void setupWebserver(AsyncWebServer &server) { | |||||||
|             request->send(response); |             request->send(response); | ||||||
|              |              | ||||||
|             if (success) { |             if (success) { | ||||||
|                 oledShowMessage("Upgrade successful Rebooting"); |                 oledShowMessage("Update successful"); | ||||||
|                 delay(500); |                 delay(2000);  // Noch längerer Delay vor Neustart | ||||||
|                 ESP.restart(); |                 ESP.restart(); | ||||||
|             } |             } else { | ||||||
|             else { |                 oledShowMessage("Update failed"); | ||||||
|                 oledShowMessage("Upgrade failed"); |  | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { |         [](AsyncWebServerRequest *request, const String& filename, size_t index, uint8_t *data, size_t len, bool final) { | ||||||
|             static size_t updateSize = 0; |             static size_t updateSize = 0; | ||||||
|  |             static size_t totalWritten = 0; | ||||||
|  |  | ||||||
|             if (!index) { |             if (!index) { | ||||||
|                 updateSize = request->contentLength(); |                 updateSize = request->contentLength(); | ||||||
|  |                 totalWritten = 0; | ||||||
|                 currentUpdateCommand = (filename.indexOf("website") > -1) ? U_SPIFFS : U_FLASH; |                 currentUpdateCommand = (filename.indexOf("website") > -1) ? U_SPIFFS : U_FLASH; | ||||||
|                  |                  | ||||||
|                 if (currentUpdateCommand == U_SPIFFS) { |                 if (currentUpdateCommand == U_SPIFFS) { | ||||||
|                     oledShowMessage("SPIFFS Update..."); |                     oledShowMessage("SPIFFS Update..."); | ||||||
|                     backupJsonConfigs(); |                     backupJsonConfigs(); | ||||||
|                      |                      | ||||||
|                     // Get the actual SPIFFS partition size from ESP32 |  | ||||||
|                     const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); |                     const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_SPIFFS, NULL); | ||||||
|                     if (!partition) { |                     if (!partition) { | ||||||
|                         String errorMsg = "SPIFFS partition not found"; |                         String errorMsg = "SPIFFS partition not found"; | ||||||
| @@ -443,15 +447,25 @@ void setupWebserver(AsyncWebServer &server) { | |||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                  |                  | ||||||
|                 // Update OLED Display alle 5% und Webseite bei jeder Änderung |                 totalWritten += len; | ||||||
|  |                 int currentProgress; | ||||||
|  |                  | ||||||
|  |                 // Unterschiedliche Fortschrittsberechnung für SPIFFS und Firmware | ||||||
|  |                 if (currentUpdateCommand == U_SPIFFS) { | ||||||
|  |                     // SPIFFS Update: Fortschritt basierend auf Upload-Größe | ||||||
|  |                     currentProgress = (totalWritten * 100) / updateSize; | ||||||
|  |                     // Skaliere den Fortschritt auf 0-90%, da das Schreiben ins SPIFFS länger dauert | ||||||
|  |                     currentProgress = (currentProgress * 90) / 100; | ||||||
|  |                 } else { | ||||||
|  |                     // Firmware Update: Normaler Fortschritt | ||||||
|  |                     currentProgress = (totalWritten * 100) / updateSize; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|                 static int lastProgress = -1; |                 static int lastProgress = -1; | ||||||
|                 int currentProgress = (index + len) * 100 / updateSize; |  | ||||||
|                 if (currentProgress != lastProgress) { |                 if (currentProgress != lastProgress) { | ||||||
|                     // OLED nur alle 5% aktualisieren |  | ||||||
|                     if (currentProgress % 5 == 0) { |                     if (currentProgress % 5 == 0) { | ||||||
|                         oledShowMessage(String(currentProgress) + "% complete"); |                         oledShowMessage(String(currentProgress) + "% complete"); | ||||||
|                     } |                     } | ||||||
|                     // Webseite bei jeder Änderung aktualisieren |  | ||||||
|                     lastProgress = currentProgress; |                     lastProgress = currentProgress; | ||||||
|                     ws.textAll("{\"type\":\"updateProgress\",\"progress\":" + String(currentProgress) + "}"); |                     ws.textAll("{\"type\":\"updateProgress\",\"progress\":" + String(currentProgress) + "}"); | ||||||
|                 } |                 } | ||||||
| @@ -463,8 +477,14 @@ void setupWebserver(AsyncWebServer &server) { | |||||||
|                     request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); |                     request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); | ||||||
|                     return; |                     return; | ||||||
|                 } |                 } | ||||||
|                 // Sende finale Progress-Nachricht |                  | ||||||
|                 ws.textAll("{\"type\":\"updateProgress\",\"progress\":100}"); |                 // Bei SPIFFS Update zeige 95% an, da noch das Restore kommt | ||||||
|  |                 if (currentUpdateCommand == U_SPIFFS) { | ||||||
|  |                     ws.textAll("{\"type\":\"updateProgress\",\"progress\":95,\"status\":\"finalizing\"}"); | ||||||
|  |                 } else { | ||||||
|  |                     ws.textAll("{\"type\":\"updateProgress\",\"progress\":100,\"status\":\"finalizing\"}"); | ||||||
|  |                 } | ||||||
|  |                 delay(200); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     ); |     ); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user