feat: implement WebSocket for update progress and enhance update response handling

This commit is contained in:
Manuel Weiser 2025-02-22 18:12:27 +01:00
parent fe7b57fe0e
commit 4135073623
2 changed files with 39 additions and 33 deletions

View File

@ -155,17 +155,29 @@
const progressContainer = document.querySelector('.progress-container'); const progressContainer = document.querySelector('.progress-container');
const status = document.querySelector('.status'); const status = document.querySelector('.status');
// WebSocket für Update-Progress
const ws = new WebSocket('ws://' + window.location.host + '/ws');
ws.onmessage = function(event) {
try {
const data = JSON.parse(event.data);
if (data.type === "updateProgress") {
progress.style.width = data.progress + '%';
progress.textContent = data.progress + '%';
}
} catch (e) {
console.error('WebSocket message error:', e);
}
};
function handleUpdate(e) { function handleUpdate(e) {
e.preventDefault(); e.preventDefault();
const form = e.target; const form = e.target;
const file = form.update.files[0]; const file = form.update.files[0];
const updateType = form.dataset.type; const updateType = form.dataset.type;
if (!file) { if (!file) {
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)');
@ -179,11 +191,9 @@
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 // Reset progress bar
progress.style.width = '0%'; progress.style.width = '0%';
progress.textContent = '0%'; progress.textContent = '0%';
// Disable both forms during update // 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);
@ -191,36 +201,36 @@
xhr.open('POST', '/update', true); xhr.open('POST', '/update', true);
xhr.onload = function() { xhr.onload = function() {
if (xhr.status === 200) {
try { try {
let response = this.responseText; const response = JSON.parse(xhr.responseText);
try { if (response.success) {
const jsonResponse = JSON.parse(response); status.textContent = "Update successful! Restarting device... The page will reload in 30 seconds.";
status.classList.add('success');
// Zeige finale Nachricht
status.textContent = jsonResponse.message || "Update complete";
status.classList.add(jsonResponse.success ? 'success' : 'error');
status.style.display = 'block'; status.style.display = 'block';
if (jsonResponse.success) { // Setze Progress auf 100%
progress.style.width = '100%'; progress.style.width = '100%';
progress.textContent = '100%'; progress.textContent = '100%';
// Automatischer Neustart nach erfolgreicher Aktualisierung // Automatischer Redirect nach 30 Sekunden
status.textContent = "Update successful! Restarting device... The page will reload in 30 seconds.";
setTimeout(() => { setTimeout(() => {
window.location.href = '/'; window.location.href = '/';
}, 30000); }, 30000);
} else { } else {
status.textContent = response.message || "Update failed";
status.classList.add('error');
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) {
console.error('JSON parse error:', e); status.textContent = "Error: Invalid server response";
status.textContent = 'Update failed: Invalid response from server';
status.classList.add('error'); status.classList.add('error');
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 (error) { } else {
status.textContent = 'Error: ' + error.message; status.textContent = "Update failed with status: " + xhr.status;
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);
@ -228,7 +238,7 @@
}; };
xhr.onerror = function() { xhr.onerror = function() {
status.textContent = 'Update failed: Network error'; status.textContent = "Network error during update";
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);

View File

@ -375,6 +375,12 @@ void setupWebserver(AsyncWebServer &server) {
[](AsyncWebServerRequest *request) { [](AsyncWebServerRequest *request) {
// Nach Update-Abschluss // Nach Update-Abschluss
bool success = !Update.hasError(); bool success = !Update.hasError();
// Bei SPIFFS Update und Erfolg: Restore Configs vor dem Neustart
if (success && Update.command() == U_SPIFFS) {
restoreJsonConfigs();
}
String message = success ? "Update successful" : String("Update failed: ") + Update.errorString(); String message = success ? "Update successful" : String("Update failed: ") + Update.errorString();
AsyncWebServerResponse *response = request->beginResponse( AsyncWebServerResponse *response = request->beginResponse(
success ? 200 : 400, success ? 200 : 400,
@ -397,8 +403,6 @@ void setupWebserver(AsyncWebServer &server) {
static size_t updateSize = 0; static size_t updateSize = 0;
static int command = 0; static int command = 0;
//oledShowMessage("Upgrade please wait");
if (!index) { if (!index) {
updateSize = request->contentLength(); updateSize = request->contentLength();
command = (filename.indexOf("website") > -1) ? U_SPIFFS : U_FLASH; command = (filename.indexOf("website") > -1) ? U_SPIFFS : U_FLASH;
@ -410,14 +414,12 @@ void setupWebserver(AsyncWebServer &server) {
// Get the actual SPIFFS partition size from ESP32 // 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) {
restoreJsonConfigs();
String errorMsg = "SPIFFS partition not found"; String errorMsg = "SPIFFS partition not found";
request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}");
return; return;
} }
if (!Update.begin(partition->size, command)) { if (!Update.begin(partition->size, command)) {
restoreJsonConfigs();
String errorMsg = String("Update begin failed: ") + Update.errorString(); String errorMsg = String("Update begin failed: ") + Update.errorString();
request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}");
return; return;
@ -434,9 +436,6 @@ void setupWebserver(AsyncWebServer &server) {
if (len) { if (len) {
if (Update.write(data, len) != len) { if (Update.write(data, len) != len) {
if (command == U_SPIFFS) {
restoreJsonConfigs();
}
String errorMsg = String("Write failed: ") + Update.errorString(); String errorMsg = String("Write failed: ") + Update.errorString();
request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}");
return; return;
@ -458,9 +457,6 @@ void setupWebserver(AsyncWebServer &server) {
if (final) { if (final) {
if (!Update.end(true)) { if (!Update.end(true)) {
if (command == U_SPIFFS) {
restoreJsonConfigs();
}
String errorMsg = String("Update end failed: ") + Update.errorString(); String errorMsg = String("Update end failed: ") + Update.errorString();
request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}"); request->send(400, "application/json", "{\"success\":false,\"message\":\"" + errorMsg + "\"}");
return; return;