Adds HTTPUpdateServer for ESP32

pull/123/head
Hieromon Ikasamo 6 years ago
parent da8bf23e93
commit 324c6b7d5c
  1. 130
      examples/WebUpdate/HTTPUpdateServer.cpp
  2. 42
      examples/WebUpdate/HTTPUpdateServer.h
  3. 48
      examples/WebUpdate/WebUpdate.ino

@ -0,0 +1,130 @@
/**
* 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 <Arduino.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <WebServer.h>
#include <WiFiUdp.h>
#include <Update.h>
#include "StreamString.h"
#include "HTTPUpdateServer.h"
static const char serverIndex[] PROGMEM = R"(
<html><body>
<form method='POST' action='' enctype='multipart/form-data'>
<input type='file' name='update'>
<input type='submit' value='Update'>
</form>
</body></html>
)";
static const char successResponse[] PROGMEM =
"<meta http-equiv=\"refresh\" content=\"15;URL=/\">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();
}
#endif // !ARDUINO_ARCH_ESP32

@ -0,0 +1,42 @@
/**
* Ported the ESP8266HTTPUpdateServer published by Arduino-core to
* provide the web browser based OTA update on the ESP32 platform.
* @file HTTPUpdateServer.h
* @author hieromon@gmail.com
* @version 0.9.10
* @date 2019-06-06
* @copyright MIT license.
*/
#ifndef __HTTP_UPDATE_SERVER_H
#define __HTTP_UPDATE_SERVER_H
#ifdef ARDUINO_ARCH_ESP32
// This class will available only EPS32 actually.
class WebServer;
class HTTPUpdateServer {
public:
explicit HTTPUpdateServer(bool serial_debug = false) : _serial_output(serial_debug), _server(nullptr), _username(emptyString), _password(emptyString), _authenticated(false) {}
~HTTPUpdateServer() {}
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);
void updateCredentials(const String& username, const String& password) { _username = username; _password = password; }
protected:
void _setUpdaterError();
private:
bool _serial_output;
WebServer* _server;
String _username;
String _password;
bool _authenticated;
String _updaterError;
};
#endif // !ARDUINO_ARCH_ESP32
#endif // !__HTTP_UPDATE_SERVER_H

@ -12,19 +12,13 @@
file on the update UI page to update the firmware. file on the update UI page to update the firmware.
Notes: Notes:
1. This example is valid only for ESP8266. In order to apply this 1. To experience this example, your client OS needs to be running a
example to ESP32, it is necessary to quote WebUpdate.ino included
in the ESP32 arduino core distribution and implement a class
equivalent to ESP8266HTTPUpdateServer. But it is not included in this
example.
2. To experience this example, your client OS needs to be running a
service that can respond to multicast DNS. service that can respond to multicast DNS.
For Mac OSX support is built in through Bonjour already. For Mac OSX support is built in through Bonjour already.
For Linux, install Avahi. For Linux, install Avahi.
For Windows10, available since Windows10 1803(April 2018 Update/RS4). For Windows10, available since Windows10 1803(April 2018 Update/RS4).
3. If you receive an error as follows: 2. If you receive an error as follows:
Update error: ERROR[11]: Invalid bootstrapping state, reset ESP8266 before updating. Update error: ERROR[11]: Invalid bootstrapping state, reset ESP8266 before updating.
You need reset the module before sketch running. You need reset the module before sketch running.
Refer to https://hieromon.github.io/AutoConnect/faq.html#hang-up-after-reset for details. Refer to https://hieromon.github.io/AutoConnect/faq.html#hang-up-after-reset for details.
@ -32,13 +26,27 @@
This software is released under the MIT License. This software is released under the MIT License.
https://opensource.org/licenses/MIT https://opensource.org/licenses/MIT
*/ */
#ifdef ARDUINO_ARCH_ESP8266
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <ESP8266mDNS.h> #include <ESP8266mDNS.h>
#include <ESP8266HTTPUpdateServer.h> #include <ESP8266HTTPUpdateServer.h>
#define HOSTIDENTIFY "esp8266"
#define mDNSUpdate(c) do { c.update(); } while(0)
using WebServerClass = ESP8266WebServer;
using HTTPUpdateServerClass = ESP8266HTTPUpdateServer;
#elif defined(ARDUINO_ARCH_ESP32)
#include <WiFi.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include "HTTPUpdateServer.h"
#define HOSTIDENTIFY "esp32"
#define mDNSUpdate(c) do {} while(0)
using WebServerClass = WebServer;
using HTTPUpdateServerClass = HTTPUpdateServer;
#endif
#include <WiFiClient.h>
#include <AutoConnect.h> #include <AutoConnect.h>
// This page for an example only, you can prepare the other for your application. // This page for an example only, you can prepare the other for your application.
@ -64,17 +72,19 @@ static const char AUX_AppPage[] PROGMEM = R"(
)"; )";
// Fix hostname for mDNS. It is a requirement for the lightweight update feature. // Fix hostname for mDNS. It is a requirement for the lightweight update feature.
static const char* host = "esp8266-webupdate"; static const char* host = HOSTIDENTIFY "-webupdate";
#define HTTP_PORT 80 #define HTTP_PORT 80
// ESP8266WebServer instance will be shared both AutoConnect and UpdateServer. // ESP8266WebServer instance will be shared both AutoConnect and UpdateServer.
ESP8266WebServer httpServer(HTTP_PORT); WebServerClass httpServer(HTTP_PORT);
#define USERNAME "user" //*< Replace the actual username you want */
#define PASSWORD "pass" //*< Replace the actual password you want */
// Declare AutoConnectAux to bind the HTTPWebUpdateServer via /update url // Declare AutoConnectAux to bind the HTTPWebUpdateServer via /update url
// and call it from the menu. // and call it from the menu.
// The custom web page is an empty page that does not contain AutoConnectElements. // The custom web page is an empty page that does not contain AutoConnectElements.
// Its content will be emitted by ESP8266HTTPUpdateServer. // Its content will be emitted by ESP8266HTTPUpdateServer.
ESP8266HTTPUpdateServer httpUpdater; HTTPUpdateServerClass httpUpdater;
AutoConnectAux update("/update", "Update"); AutoConnectAux update("/update", "Update");
// Declare AutoConnect and the custom web pages for an application sketch. // Declare AutoConnect and the custom web pages for an application sketch.
@ -88,7 +98,7 @@ void setup() {
// Prepare the ESP8266HTTPUpdateServer // Prepare the ESP8266HTTPUpdateServer
// The /update handler will be registered during this function. // The /update handler will be registered during this function.
httpUpdater.setup(&httpServer); httpUpdater.setup(&httpServer, USERNAME, PASSWORD);
// Load a custom web page for a sketch and a dummy page for the updater. // Load a custom web page for a sketch and a dummy page for the updater.
hello.load(AUX_AppPage); hello.load(AUX_AppPage);
@ -105,14 +115,10 @@ void setup() {
} }
void loop() { void loop() {
// Sketch the application here. // Sketches the application here.
// Invokes mDNS::update and AutoConnect::handleClient() for the menu processing. // Invokes mDNS::update and AutoConnect::handleClient() for the menu processing.
MDNS.update(); mDNSUpdate(MDNS);
portal.handleClient(); portal.handleClient();
delay(1);
} }
#else
void setup() {}
void loop() {}
#endif

Loading…
Cancel
Save