Open societyofrobots opened 2 years ago
I hacked together some code to improve the firmware update page with a progress bar, and better scaling for small devices.
Replace IotWebConfESP32HTTPUpdateServer.h with the below code (only added code is the bottom third).
/** * IotWebConfESP32HTTPUpdateServer.h -- IotWebConf is an ESP8266/ESP32 * non blocking WiFi/AP web configuration library for Arduino. * https://github.com/prampec/IotWebConf * * Copyright (C) 2020 Balazs Kelemen <prampec+arduino@gmail.com> * * This software may be modified and distributed under the terms * of the MIT license. See the LICENSE file for details. * * Notes on IotWebConfESP32HTTPUpdateServer: * ESP32 doesn't implement a HTTPUpdateServer. However it seams, that to code * from ESP8266 covers nearly all the same functionality. * So we need to implement our own HTTPUpdateServer for ESP32, and code is * reused from * https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266HTTPUpdateServer/src/ * version: 41de43a26381d7c9d29ce879dd5d7c027528371b */ #ifdef ESP32 #ifndef __HTTP_UPDATE_SERVER_H #define __HTTP_UPDATE_SERVER_H #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <StreamString.h> #include <Update.h> #define emptyString F("") class WebServer; class HTTPUpdateServer { public: HTTPUpdateServer(bool serial_debug=false) { _serial_output = serial_debug; _server = nullptr; _username = emptyString; _password = emptyString; _authenticated = false; } void setup(WebServer *server) { setup(server, emptyString, emptyString); } void setup(WebServer *server, const String& path) { setup(server, path, emptyString, emptyString); } void setup(WebServer *server, const String& username, const String& password) { setup(server, "/update", username, password); } void setup(WebServer *server, const String& path, const String& username, const String& password) { _server = server; _username = username; _password = password; // handler for the /update form page _server->on(path.c_str(), HTTP_GET, [&](){ if(_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str())) return _server->requestAuthentication(); _server->send_P(200, PSTR("text/html"), serverIndex); }); // handler for the /update form POST (once file upload finishes) _server->on(path.c_str(), HTTP_POST, [&](){ if(!_authenticated) return _server->requestAuthentication(); if (Update.hasError()) { _server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError); } else { _server->client().setNoDelay(true); _server->send_P(200, PSTR("text/html"), successResponse); delay(100); _server->client().stop(); ESP.restart(); } },[&](){ // handler for the file upload, get's the sketch bytes, and writes // them through the Update object HTTPUpload& upload = _server->upload(); if(upload.status == UPLOAD_FILE_START){ _updaterError = String(); if (_serial_output) Serial.setDebugOutput(true); _authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str())); if(!_authenticated){ if (_serial_output) Serial.printf("Unauthenticated Update\n"); return; } /// WiFiUDP::stopAll(); if (_serial_output) Serial.printf("Update: %s\n", upload.filename.c_str()); /// uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; /// if(!Update.begin(maxSketchSpace)){//start with max available size if(!Update.begin(UPDATE_SIZE_UNKNOWN)){//start with max available size _setUpdaterError(); } } else if(_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()){ if (_serial_output) Serial.printf("."); if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){ _setUpdaterError(); } } else if(_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()){ if(Update.end(true)){ //true to set the size to the current progress if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); } else { _setUpdaterError(); } if (_serial_output) Serial.setDebugOutput(false); } else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){ Update.end(); if (_serial_output) Serial.println("Update was aborted"); } delay(0); }); } void updateCredentials(const String& username, const String& password) { _username = username; _password = password; } protected: void _setUpdaterError() { if (_serial_output) Update.printError(Serial); StreamString str; Update.printError(str); _updaterError = str.c_str(); } private: bool _serial_output; WebServer *_server; String _username; String _password; bool _authenticated; String _updaterError; const char* serverIndex PROGMEM = R"=====(<html><body> <!-- <form method='POST' action='' enctype='multipart/form-data'> <p style="font-size:30%;"><input type='file' name='update'></p> <p style="font-size:30%;"><input type='submit' value='Update'></p> </form> below script from https://codepen.io/PerfectIsShit/pen/zogMXP --> <p style="font-size:8vw;">Firmware Updater</p> <form id="upload_form" enctype="multipart/form-data" method="post"> <input type="file" name="update" id="update" onchange="uploadFile()" value="Update" style="width:100%;font-size:3vw;"><br> <progress id="progressBar" value="0" max="100" style="width:300px;"></progress> <h3 id="status"></h3> <p id="loaded_n_total"></p> </form> <script id="rendered-js" > function _(el) { return document.getElementById(el); } function uploadFile() { var file = _("update").files[0]; // alert(file.name+" | "+file.size+" | "+file.type); var formdata = new FormData(); formdata.append("update", 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", ""); //use file_upload_parser.php from above url ajax.send(formdata); } function progressHandler(event) { _("loaded_n_total").innerHTML = "Uploaded " + event.loaded + " bytes of " + event.total; var percent = event.loaded / event.total * 100; _("progressBar").value = Math.round(percent); _("status").innerHTML = Math.round(percent) + "% uploaded... please wait"; } function completeHandler(event) { _("status").innerHTML = event.target.responseText; _("progressBar").value = 0; //wil clear progress bar after successful upload } function errorHandler(event) { _("status").innerHTML = "Upload Failed"; } function abortHandler(event) { _("status").innerHTML = "Upload Aborted"; } //# sourceURL=pen.js </script> </body></html>)====="; const char* successResponse PROGMEM = "<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...\n"; }; ///////////////////////////////////////////////////////////////////////////////// #endif #endif
I hacked together some code to improve the firmware update page with a progress bar, and better scaling for small devices.
Replace IotWebConfESP32HTTPUpdateServer.h with the below code (only added code is the bottom third).