From 26897ccb15b1510109cd7860f3524dde8dc73a4e Mon Sep 17 00:00:00 2001 From: CaCO3 Date: Sat, 7 Jan 2023 20:21:35 +0100 Subject: [PATCH] new OTA page with progressbar (#1756) * new OTA page with progress bar * improve error message on missing demo files * . * Implemented Reboot for "firmware.bin" as well * Update feature.yaml * cache static files (#1755) Co-authored-by: CaCO3 * . * . * added filename validation * . * . * . * move * added missing dash to regex * restrict file type * . * . * . * . * cleanup no longer needed mode * only start restart counter if restart is required Co-authored-by: CaCO3 Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com> --- .../ClassControllCamera.cpp | 3 +- .../jomjol_fileserver_ota/server_ota.cpp | 29 +- .../jomjol_tfliteclass/server_tflite.cpp | 4 +- sd-card/html/index.html | 4 + sd-card/html/ota_page.html | 508 +++++++++--------- 5 files changed, 276 insertions(+), 272 deletions(-) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index fb5e071b..fc650877 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -682,7 +682,8 @@ void CCamera::useDemoMode() FILE *fd = fopen("/sdcard/demo/files.txt", "r"); if (!fd) { - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Please provide the demo files first!"); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!"); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://github.com/jomjol/AI-on-the-edge-device/wiki/Demo-Mode!"); return; } diff --git a/code/components/jomjol_fileserver_ota/server_ota.cpp b/code/components/jomjol_fileserver_ota/server_ota.cpp index 06f11366..cf2de42d 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.cpp +++ b/code/components/jomjol_fileserver_ota/server_ota.cpp @@ -645,40 +645,17 @@ esp_err_t handler_reboot(httpd_req_t *req) LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot"); ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!"); - char _query[200]; - char _valuechar[30]; - std::string _task; std::string response = "

"; - - if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) - { - ESP_LOGD(TAG, "Query: %s", _query); - - if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK) - { - ESP_LOGD(TAG, "task is found: %s", _valuechar); - _task = std::string(_valuechar); - } - } + "}

" + "" + ""; httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); - - if (_task.compare("OTA") == 0) { // Reboot after OTA upload - response.append(""); - } - else { // Normal reboot - response.append(""); - } - - response.append(""); httpd_resp_send(req, response.c_str(), strlen(response.c_str())); doReboot(); diff --git a/code/components/jomjol_tfliteclass/server_tflite.cpp b/code/components/jomjol_tfliteclass/server_tflite.cpp index ebca7b63..e97cca22 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.cpp +++ b/code/components/jomjol_tfliteclass/server_tflite.cpp @@ -839,11 +839,11 @@ void task_autodoFlow(void *pvParameter) if (!isPlannedReboot) { if (esp_reset_reason() == ESP_RST_PANIC) { - LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Restarted due to an Exception/panic! Postponing first round start by 5 minutes to allow for an OTA or to fetch the log!"); + LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Restarted due to an Exception/panic! Postponing first round start by 5 minutes to allow for an OTA Update or to fetch the log!"); LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Setting logfile level to DEBUG until the next reboot!"); LogFile.setLogLevel(ESP_LOG_DEBUG); //MQTTPublish(GetMQTTMainTopic() + "/" + "status", "Postponing first round", false); - vTaskDelay(60*5000 / portTICK_RATE_MS); // Wait 5 minutes to give time to do an OTA or fetch the log + vTaskDelay(60*5000 / portTICK_RATE_MS); // Wait 5 minutes to give time to do an OTA Update or fetch the log } } diff --git a/sd-card/html/index.html b/sd-card/html/index.html index be096379..09cbc0ce 100644 --- a/sd-card/html/index.html +++ b/sd-card/html/index.html @@ -11,6 +11,10 @@ + + + + - -input[type=number] { - width: 138px; - padding: 10px 5px; - display: inline-block; - border: 1px solid #ccc; - font-size: 16px; -} - -.button { - padding: 10px 20px; - width: 211px; - font-size: 16px; -} - - - - + + + + -

Check the Release Page to see if there is an update available.

-

Normally, the overall update package (update__*.zip) is your best choice!
-Alternatively you can use the old style firmware__*.bin and -web interface (html__*.zip). How ever it is strongly recommended to update firmware and - web interface at the same time!

-
-

Update

-Do not reload the page or switch to another page while the update is in progress! - - -

-

+

OTA Update

+

Check the Release Page to see if there is an update available.
+ Then pick the AI-on-the-edge-device__update__*.zip file!

+

Alternatively you can use a file in the following format:

+
    +
  • AI-on-the-edge-device__update__*.zip
  • +
  • AI-on-the-edge-device__firmware__*.bin
  • +
  • *.tfl/tflite
  • +
+

Make sure the file extention is lower case.

+ +


Do not reload the page or switch to another page while the update is in progress!

+ + +

+ + +

+ +

+

Status: idle

+ + + + + + var xhttp = new XMLHttpRequest(); + /* first delete the old firmware */ + xhttp.onreadystatechange = function() { + if (xhttp.readyState == 4) { + if (xhttp.status == 200) { + document.cookie = "page=overview.html"; // Make sure after the reboot we go to the overview page + + if (xhttp.responseText.startsWith("reboot")) { // Reboot required + console.log("Upload completed, the device will now restart and install the update!"); + document.getElementById("status").innerText = "Status: Installing..."; + firework.launch('Upload completed, the device will now restart and install the update', 'success', 5000); + + /* Tell it to reboot */ + doRebootAfterUpdate(); + + action_runtime = 0; + updateTimer = setInterval(function() { + action_runtime += 1; + console.log("Waiting: " + action_runtime + "s"); + _("progressBar").value = Math.round(action_runtime); + + if (action_runtime > 10) { // After 10 seconds, start to check if we are up again + /* Check if the device is up again and forward to index page if so */ + fetch('reboot_page.html?' + Math.random(), {mode: 'no-cors'}).then( + r=>{parent.location.href=('index.html');} + ) + } + + if (action_runtime > 100) { // We reached 300 seconds but device is not ready yet + firework.launch("The device seems not do be up again, or maybe we missed it. Try to reload this page or reset the device!", 'danger', 30000); + clearInterval(updateTimer); + } + }, 3000); + } + else // No reboot required + { + document.getElementById("status").innerText = "Status: Update completed"; + firework.launch('Update completed!', 'success', 5000); + document.getElementById("file_selector").disabled = false; + } + } else if (xhttp.status == 0) { + firework.launch('Server closed the connection abruptly!', 'danger', 30000); + } else { + firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000); + } + } + }; + + var file_name = document.getElementById("file_selector").value; + filePath = file_name.split(/[\\\/]/).pop(); + var _toDo = domainname + "/ota?task=update&file=" + filePath; + xhttp.open("GET", _toDo, true); + xhttp.send(); + } + + + function _(el) { + return document.getElementById(el); + } + + + function upload() { + document.getElementById("status").innerText = "Status: Uploading..."; + + var upload_path = "/upload/firmware/" + filePath; + + var file = _("file_selector").files[0]; + var formdata = new FormData(); + formdata.append("file_selector", file); + var ajax = new XMLHttpRequest(); + ajax.upload.addEventListener("progress", progressHandler, false); + ajax.addEventListener("load", completeHandler, false); + ajax.addEventListener("error", errorHandler, false); + ajax.addEventListener("abort", abortHandler, false); + + ajax.open("POST", upload_path); + ajax.send(file); + } + + + function progressHandler(event) { + _("loaded_n_total").innerHTML = "Uploaded " + (event.loaded / 1024 / 1024).toFixed(2) + + " MBytes of " + (event.total / 1024/ 1024).toFixed(2) + " MBytes."; + var percent = (event.loaded / event.total) * 100; + _("progressBar").value = Math.round(percent); + _("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded... please wait"; + } + + + function completeHandler(event) { + _("status").innerHTML = "Status: " + event.target.responseText; + _("progressBar").value = 0; //will clear progress bar after successful upload + _("loaded_n_total").innerHTML = ""; + + extract(); + } + + + function errorHandler(event) { + _("status").innerHTML = "Status: Upload Failed"; + firework.launch('Upload failed!', 'danger', 30000); + document.getElementById("file_selector").disabled = false; + } + + + function abortHandler(event) { + _("status").innerHTML = "Status: Upload Aborted"; + firework.launch('Upload aborted!', 'danger', 30000); + document.getElementById("file_selector").disabled = false; + } + - +