mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-07 12:06:58 +03:00
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 <caco@ruinelli.ch> * . * . * 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 <caco@ruinelli.ch> Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
This commit is contained in:
@@ -682,7 +682,8 @@ void CCamera::useDemoMode()
|
|||||||
|
|
||||||
FILE *fd = fopen("/sdcard/demo/files.txt", "r");
|
FILE *fd = fopen("/sdcard/demo/files.txt", "r");
|
||||||
if (!fd) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -645,40 +645,17 @@ esp_err_t handler_reboot(httpd_req_t *req)
|
|||||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
|
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
|
||||||
ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!");
|
ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!");
|
||||||
|
|
||||||
char _query[200];
|
|
||||||
char _valuechar[30];
|
|
||||||
std::string _task;
|
|
||||||
std::string response =
|
std::string response =
|
||||||
"<html><head><script>"
|
"<html><head><script>"
|
||||||
"function m(h) {"
|
"function m(h) {"
|
||||||
"document.getElementById('t').innerHTML=h;"
|
"document.getElementById('t').innerHTML=h;"
|
||||||
"setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h;"
|
"setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h;"
|
||||||
"fetch('reboot_page.html',{mode: 'no-cors'}).then(r=>{parent.location.href=('index.html');})}, 1000);"
|
"fetch('reboot_page.html',{mode: 'no-cors'}).then(r=>{parent.location.href=('index.html');})}, 1000);"
|
||||||
"}</script></head></html><body style='font-family: arial'><h3 id=t></h3>";
|
"}</script></head></html><body style='font-family: arial'><h3 id=t></h3>"
|
||||||
|
"<script>m('Rebooting!<br>The page will automatically reload in around 25..60s.<br><br>');</script>"
|
||||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
"</body></html>";
|
||||||
{
|
|
||||||
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", "*");
|
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
if (_task.compare("OTA") == 0) { // Reboot after OTA upload
|
|
||||||
response.append("<script>m('The upload completed successfully.<br>Rebooting and installing it now...<br><br>"
|
|
||||||
"The page will automatically reload after the update completed.<br>"
|
|
||||||
"This can take several minutes!<br><br>');</script>");
|
|
||||||
}
|
|
||||||
else { // Normal reboot
|
|
||||||
response.append("<script>m('Rebooting!<br>The page will automatically reload in around 25..60s.<br><br>');</script>");
|
|
||||||
}
|
|
||||||
|
|
||||||
response.append("</body></html>");
|
|
||||||
httpd_resp_send(req, response.c_str(), strlen(response.c_str()));
|
httpd_resp_send(req, response.c_str(), strlen(response.c_str()));
|
||||||
|
|
||||||
doReboot();
|
doReboot();
|
||||||
|
|||||||
@@ -839,11 +839,11 @@ void task_autodoFlow(void *pvParameter)
|
|||||||
if (!isPlannedReboot)
|
if (!isPlannedReboot)
|
||||||
{
|
{
|
||||||
if (esp_reset_reason() == ESP_RST_PANIC) {
|
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.WriteToFile(ESP_LOG_WARN, TAG, "Setting logfile level to DEBUG until the next reboot!");
|
||||||
LogFile.setLogLevel(ESP_LOG_DEBUG);
|
LogFile.setLogLevel(ESP_LOG_DEBUG);
|
||||||
//MQTTPublish(GetMQTTMainTopic() + "/" + "status", "Postponing first round", false);
|
//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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,10 @@
|
|||||||
<script type="text/javascript" src="readconfigcommon.js"></script>
|
<script type="text/javascript" src="readconfigcommon.js"></script>
|
||||||
<script type="text/javascript" src="readconfigparam.js"></script>
|
<script type="text/javascript" src="readconfigparam.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
|
||||||
|
<script type="text/javascript" src="common.js"></script>
|
||||||
|
<script type="text/javascript" src="firework.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
async function loadPage(page) {
|
async function loadPage(page) {
|
||||||
console.log("loadPage(" + page + ")");
|
console.log("loadPage(" + page + ")");
|
||||||
|
|||||||
@@ -1,271 +1,293 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
<link rel="icon" href="favicon.ico" type="image/x-icon">
|
||||||
<title>OTA Update</title>
|
<title>OTA Update</title>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|
||||||
<script type="text/javascript" src="common.js"></script>
|
<style>
|
||||||
<style>
|
h1 {font-size: 2em;}
|
||||||
h1 {font-size: 2em;}
|
h2 {font-size: 1.5em;}
|
||||||
h2 {font-size: 1.5em;}
|
h3 {font-size: 1.2em;}
|
||||||
h3 {font-size: 1.2em;}
|
p {font-size: 1em;}
|
||||||
p {font-size: 1em;}
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
input[type=number] {
|
<link href="firework.css" rel="stylesheet">
|
||||||
width: 138px;
|
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
|
||||||
padding: 10px 5px;
|
<script type="text/javascript" src="common.js"></script>
|
||||||
display: inline-block;
|
<script type="text/javascript" src="firework.js"></script>
|
||||||
border: 1px solid #ccc;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
padding: 10px 20px;
|
|
||||||
width: 211px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<link href="firework.css" rel="stylesheet">
|
|
||||||
<script type="text/javascript" src="jquery-3.6.0.min.js"></script>
|
|
||||||
<script type="text/javascript" src="firework.js"></script>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body style="font-family: arial; padding: 0px 10px;">
|
<body style="font-family: arial; padding: 0px 10px;">
|
||||||
<p>Check the <a href="https://github.com/jomjol/AI-on-the-edge-device/releases" target=_blank>Release Page</a> to see if there is an update available.</p>
|
<h2>OTA Update</h2>
|
||||||
<p>Normally, the overall update package (<i><span style="font-family:monospace">update__*.zip</span></i>) is your best choice!<br>
|
<p>Check the <a href="https://github.com/jomjol/AI-on-the-edge-device/releases" target=_blank>Release Page</a> to see if there is an update available. <br>
|
||||||
Alternatively you can use the old style <i><span style="font-family:monospace">firmware__*.bin</span></i> and
|
Then pick the <i><span style="font-family:monospace">AI-on-the-edge-device__update__*.zip</span></i> file!</p>
|
||||||
web interface (<i><span style="font-family:monospace">html__*.zip</span></i>). How ever it is strongly recommended to update firmware and
|
<p>Alternatively you can use a file in the following format:</p>
|
||||||
web interface at the same time!</p>
|
<ul>
|
||||||
<hr>
|
<li><span style="font-family:monospace">AI-on-the-edge-device__update__*.zip</span></li>
|
||||||
<h2>Update</h2>
|
<li><span style="font-family:monospace">AI-on-the-edge-device__firmware__*.bin</span></li>
|
||||||
<b>Do not reload the page or switch to another page while the update is in progress!</b>
|
<li><span style="font-family:monospace">*.tfl/tflite</span></li>
|
||||||
<table class="fixed" border="0">
|
</ul>
|
||||||
<tr>
|
<p>Make sure the file extention is lower case.</p>
|
||||||
<p>
|
|
||||||
<label for="newfile">Select the file containig the update (
|
<p><br><b>Do not reload the page or switch to another page while the update is in progress!</b><br></p>
|
||||||
<i><span style="font-family:monospace">update__*.zip</span></i>,
|
|
||||||
<i><span style="font-family:monospace">firmware__*.bin</span></i>,
|
<form id="upload_form" enctype="multipart/form-data" method="post">
|
||||||
<i><span style="font-family:monospace">html__*.zip</span></i>,
|
<input type="file" accept=".bin,.zip,.tfl,.tflite" name="file_selector" id="file_selector" onchange="validate_file()"><br><br>
|
||||||
<i><span style="font-family:monospace">*.tfl/tflite</span></i>)
|
|
||||||
</p>
|
<button class="button" style="width:300px" id="start_OTA_button" type="button" onclick="start_OTA()" disabled>Upload and install</button>
|
||||||
|
<br><br>
|
||||||
|
<progress id="progressBar" value="0" max="100" style="width:600px;"></progress>
|
||||||
|
<p id="loaded_n_total"></p>
|
||||||
|
<h3><span id="status">Status: idle</span></h3>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script language="JavaScript">
|
||||||
|
var domainname = getDomainname();
|
||||||
|
|
||||||
</tr>
|
var action_runtime = 0;
|
||||||
<tr>
|
|
||||||
<p>
|
/* Max size of an individual file. Make sure this
|
||||||
<input id="newfile" type="file" onchange="setpath()" style="width:100%;">
|
* value is same as that set in server_file.c */
|
||||||
</p>
|
var MAX_FILE_SIZE = 8000*1024;
|
||||||
</tr>
|
var MAX_FILE_SIZE_STR = "8MB";
|
||||||
<tr>
|
|
||||||
<p>
|
function validate_file() {
|
||||||
<button class="button" style="width:300px" id="doUpdate" type="button" onclick="prepareOnServer()">Upload and update<br>(incl. reboot - if needed)</button>
|
document.getElementById("start_OTA_button").disabled = true;
|
||||||
</p>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<p>
|
|
||||||
<h3><span id="status">Status: idle</span> <span id="progress"></span></h3>
|
|
||||||
</p>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
var fileInput = document.getElementById("file_selector").files;
|
||||||
|
var filepath = document.getElementById("file_selector").value;
|
||||||
|
|
||||||
<script language="JavaScript">
|
console.log("filepath: " + filepath);
|
||||||
|
|
||||||
var domainname = getDomainname();
|
filename = filepath.split(/[\\\/]/).pop();
|
||||||
|
|
||||||
|
console.log("filename: " + filename);
|
||||||
|
|
||||||
/* Max size of an individual file. Make sure this
|
/* Various checks on filename length and file size */
|
||||||
* value is same as that set in server_file.c */
|
if (fileInput.length == 0) {
|
||||||
var MAX_FILE_SIZE = 8000*1024;
|
firework.launch('No file selected!', 'danger', 30000);
|
||||||
var MAX_FILE_SIZE_STR = "8MB";
|
return;
|
||||||
|
} else if (filename.length == 0) {
|
||||||
var action_runtime = 0;
|
firework.launch('File path on server is not set!', 'danger', 30000);
|
||||||
var progressTimerHandle = null;
|
return;
|
||||||
|
} else if (filename.length > 100) {
|
||||||
|
firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
|
||||||
function init(){
|
return;
|
||||||
domainname = getDomainname();
|
} else if (filename.indexOf(' ') >= 0) {
|
||||||
|
firework.launch('Filename can not have spaces!', 'danger', 30000);
|
||||||
document.getElementById("doUpdate").disabled = true;
|
return;
|
||||||
}
|
} else if (filename[filename.length-1] == '/') {
|
||||||
|
firework.launch('File name not specified after path!', 'danger', 30000);
|
||||||
|
return;
|
||||||
function doRebootAfterUpdate() {
|
} else if (fileInput[0].size > MAX_FILE_SIZE) {
|
||||||
/* if (confirm("Upload completed!\nThe device will reboot now and complete the update.\nThis will take up to 180s!")) {*/
|
firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
|
||||||
var stringota = "/reboot?task=OTA";
|
return;
|
||||||
window.location = stringota;
|
|
||||||
window.location.href = stringota;
|
|
||||||
window.location.assign(stringota);
|
|
||||||
window.location.replace(stringota);
|
|
||||||
/* }*/
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function setpath() {
|
|
||||||
var nameneu = document.getElementById("newfile").value;
|
|
||||||
nameneu = nameneu.split(/[\\\/]/).pop();
|
|
||||||
document.getElementById("doUpdate").disabled = false;
|
|
||||||
document.getElementById("status").innerText = "Status: File selected";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function prepareOnServer() {
|
|
||||||
var fileInput = document.getElementById("newfile").files;
|
|
||||||
var nameneu = document.getElementById("newfile").value;
|
|
||||||
filePath = nameneu.split(/[\\\/]/).pop();
|
|
||||||
|
|
||||||
/* Max size of an individual file. Make sure this
|
|
||||||
* value is same as that set in file_server.c */
|
|
||||||
var MAX_FILE_SIZE = 8000*1024;
|
|
||||||
var MAX_FILE_SIZE_STR = "8000KB";
|
|
||||||
|
|
||||||
if (fileInput.length == 0) {
|
|
||||||
firework.launch('No file selected!', 'danger', 30000);
|
|
||||||
return;
|
|
||||||
} else if (filePath.length == 0) {
|
|
||||||
firework.launch('File path on server is not set!', 'danger', 30000);
|
|
||||||
return;
|
|
||||||
} else if (filePath.length > 100) {
|
|
||||||
firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
|
|
||||||
return;
|
|
||||||
} else if (filePath.indexOf(' ') >= 0) {
|
|
||||||
firework.launch('File path on server cannot have spaces!', 'danger', 30000);
|
|
||||||
return;
|
|
||||||
} else if (filePath[filePath.length-1] == '/') {
|
|
||||||
firework.launch('File name not specified after path!', 'danger', 30000);
|
|
||||||
return;
|
|
||||||
} else if (fileInput[0].size > MAX_FILE_SIZE) {
|
|
||||||
firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById("status").innerText = "Status: Preparations on device";
|
|
||||||
document.getElementById("doUpdate").disabled = true;
|
|
||||||
|
|
||||||
var xhttp = new XMLHttpRequest();
|
|
||||||
|
|
||||||
var nameneu = document.getElementById("newfile").value;
|
|
||||||
filePath = nameneu.split(/[\\\/]/).pop();
|
|
||||||
|
|
||||||
/* first delete the old firmware AND empty the /firmware directory*/
|
|
||||||
xhttp.onreadystatechange = function() {
|
|
||||||
if (xhttp.readyState == 4) {
|
|
||||||
stopProgressTimer();
|
|
||||||
if (xhttp.status == 200) {
|
|
||||||
/* keine Reaktion, damit sich das Dokument nicht ändert */
|
|
||||||
upload();
|
|
||||||
} else if (xhttp.status == 0) {
|
|
||||||
firework.launch('Server closed the connection abruptly!', 'danger', 30000);
|
|
||||||
document.getElementById("doUpdate").disabled = false;
|
|
||||||
} else {
|
|
||||||
firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
|
|
||||||
document.getElementById("doUpdate").disabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
startProgressTimer("Server preparations...");
|
|
||||||
|
|
||||||
var _toDo = domainname + "/ota?task=emptyfirmwaredir";
|
|
||||||
xhttp.open("GET", _toDo, true);
|
|
||||||
xhttp.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function upload() {
|
|
||||||
document.getElementById("newfile").disabled = true;
|
|
||||||
|
|
||||||
var xhttp = new XMLHttpRequest();
|
|
||||||
xhttp.onreadystatechange = function() {
|
|
||||||
if (xhttp.readyState == 4) {
|
|
||||||
stopProgressTimer();
|
|
||||||
if (xhttp.status == 200) {
|
|
||||||
extract();
|
|
||||||
} else if (xhttp.status == 0) {
|
|
||||||
firework.launch('Server closed the connection abruptly!', 'danger', 30000);
|
|
||||||
document.getElementById("doUpdate").disabled = false;
|
|
||||||
} else {
|
|
||||||
firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
|
|
||||||
document.getElementById("doUpdate").disabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
startProgressTimer("Upload");
|
|
||||||
|
|
||||||
var fileInput = document.getElementById("newfile").files;
|
/* Check if the fillename matches our expected pattern
|
||||||
var file = fileInput[0];
|
* - AI-on-the-edge-device__update__*.zip
|
||||||
var upload_path = "/upload/firmware/" + filePath;
|
* - firmware__*.bin
|
||||||
|
* - *.ftl
|
||||||
xhttp.open("POST", upload_path, true);
|
* - *.tflite */
|
||||||
document.getElementById("status").innerText = "Status: Uploading (takes up to 60s)...";
|
if ( /(^AI-on-the-edge-device__update__)[a-z0-9()_\-.]*(\.zip$)/.test(filename) || // OK
|
||||||
xhttp.send(file);
|
( /(^AI-on-the-edge-device__firmware)[a-z0-9()_\-.]*(\.bin$)/.test(filename)) ||
|
||||||
}
|
( /[a-z0-9()_\-.]*(\.tfl$)/.test(filename)) ||
|
||||||
|
( /[a-z0-9()_\-.]*(\.tflite$)/.test(filename))) {
|
||||||
|
firework.launch('Great, the filename matches our expectations. You can now press "Upload and update".', 'success', 5000);
|
||||||
function extract() {
|
|
||||||
document.getElementById("status").innerText = "Status: Processing on device (takes up to 3 minutes)...";
|
|
||||||
|
|
||||||
var xhttp = new XMLHttpRequest();
|
|
||||||
/* first delete the old firmware */
|
|
||||||
xhttp.onreadystatechange = function() {
|
|
||||||
if (xhttp.readyState == 4) {
|
|
||||||
stopProgressTimer();
|
|
||||||
if (xhttp.status == 200) {
|
|
||||||
document.getElementById("status").innerText = "Status: Update completed!";
|
|
||||||
document.getElementById("doUpdate").disabled = true;
|
|
||||||
document.getElementById("newfile").disabled = false;
|
|
||||||
document.cookie = "page=overview.html"; // Make sure after the reboot we go to the overview page
|
|
||||||
|
|
||||||
if (xhttp.responseText.startsWith("reboot"))
|
|
||||||
{
|
|
||||||
doRebootAfterUpdate();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
firework.launch('Processing done', 'success', 5000);
|
|
||||||
}
|
|
||||||
} else if (xhttp.status == 0) {
|
|
||||||
firework.launch('Server closed the connection abruptly!', 'danger', 30000);
|
|
||||||
UpdatePage();
|
|
||||||
} else {
|
|
||||||
firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
|
|
||||||
UpdatePage();
|
|
||||||
}
|
}
|
||||||
|
/* Following filenames are acceptiod but not prefered:
|
||||||
|
* - *.bin
|
||||||
|
* - *.zip */
|
||||||
|
else if (filename.endsWith(".zip") || filename.endsWith(".bin")) { // Warning but still accepted
|
||||||
|
firework.launch('The filename does not match the suggested file name pattern, but is nevertheless accepted. You can now press "Upload and install', 'warning', 10000);
|
||||||
|
}
|
||||||
|
/* Any other file name format is not accepted */
|
||||||
|
else { // invalid
|
||||||
|
firework.launch('The filename does not match our expectations!', 'danger', 30000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("start_OTA_button").disabled = false;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
startProgressTimer("Extraction");
|
|
||||||
|
|
||||||
|
|
||||||
var nameneu = document.getElementById("newfile").value;
|
function start_OTA() {
|
||||||
filePath = nameneu.split(/[\\\/]/).pop();
|
document.getElementById("start_OTA_button").disabled = true;
|
||||||
var _toDo = domainname + "/ota?task=update&file=" + filePath;
|
|
||||||
xhttp.open("GET", _toDo, true);
|
var file_name = document.getElementById("file_selector").value;
|
||||||
xhttp.send();
|
document.getElementById("file_selector").disabled = true;
|
||||||
}
|
file_name = file_name.split(/[\\\/]/).pop();
|
||||||
|
document.getElementById("status").innerText = "Status: File selected";
|
||||||
|
|
||||||
|
prepareOnServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function startProgressTimer(step) {
|
function doRebootAfterUpdate() {
|
||||||
console.log(step + "...");
|
var xhttp = new XMLHttpRequest();
|
||||||
document.getElementById('progress').innerHTML = "(0s)";
|
xhttp.open("GET", "/reboot", true);
|
||||||
action_runtime = 0;
|
xhttp.send();
|
||||||
progressTimerHandle = setInterval(function() {
|
}
|
||||||
action_runtime += 1;
|
|
||||||
console.log("Progress: " + action_runtime + "s");
|
|
||||||
document.getElementById('progress').innerHTML = "(" + action_runtime + "s)";
|
|
||||||
}, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function stopProgressTimer() {
|
function prepareOnServer() {
|
||||||
clearInterval(progressTimerHandle);
|
document.getElementById("status").innerText = "Status: Preparing device...";
|
||||||
document.getElementById('progress').innerHTML = "";
|
|
||||||
}
|
var xhttp = new XMLHttpRequest();
|
||||||
|
|
||||||
|
var file_name = document.getElementById("file_selector").value;
|
||||||
|
filePath = file_name.split(/[\\\/]/).pop();
|
||||||
|
|
||||||
|
/* first delete the old firmware AND empty the /firmware directory*/
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (xhttp.readyState == 4) {
|
||||||
|
if (xhttp.status == 200) {
|
||||||
|
/* keine Reaktion, damit sich das Dokument nicht ändert */
|
||||||
|
upload();
|
||||||
|
} 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 _toDo = domainname + "/ota?task=emptyfirmwaredir";
|
||||||
|
xhttp.open("GET", _toDo, true);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
init();
|
function extract() {
|
||||||
|
document.getElementById("status").innerText = "Status: Processing on device...";
|
||||||
|
|
||||||
</script>
|
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;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user