/** * Ported the ESP8266HTTPUpdateServer published by Arduino-core to * provide the web browser based OTA update on the ESP32 platform. * @file HTTPUpdateServer.cpp * @author hieromon@gmail.com * @version 0.9.10 * @date 2019-06-06 * @copyright MIT license. */ #ifdef ARDUINO_ARCH_ESP32 // This class will available only EPS32 actually. #include #include #include #include #include #include #include "StreamString.h" #include "HTTPUpdateServer.h" static const char serverIndex[] PROGMEM = R"(
)"; static const char successResponse[] PROGMEM = "Update Success! Rebooting...\n"; /** * Setup for the web update. Register the authentication procedure and * binary file upload handler required to update the actual sketch binary by OTA. * @param server A pointer to the WebServer instance * @param path URI of the update handler * @param username Username for authentication * @arama password Password for authentication */ void HTTPUpdateServer::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.println("Unauthenticated Update"); return; } 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 _setUpdaterError(); } } else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()) { if (_serial_output) Serial.print('.'); 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); }); } /** * Convert the update error code to string for notation. */ void HTTPUpdateServer::_setUpdaterError() { if (_serial_output) Update.printError(Serial); StreamString str; Update.printError(str); _updaterError = str.c_str(); } /** * Shared empty String instance */ const String HTTPUpdateServer::_emptyString; #endif // !ARDUINO_ARCH_ESP32