Skip to content

Commit 3054bdf

Browse files
authored
HTTPUpdateServer library (espressif#4244)
1 parent 1014ba4 commit 3054bdf

File tree

4 files changed

+246
-0
lines changed

4 files changed

+246
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/*
2+
To upload through terminal you can use: curl -F "image=@firmware.bin" esp32-webupdate.local/update
3+
*/
4+
5+
#include <WiFi.h>
6+
#include <WiFiClient.h>
7+
#include <WebServer.h>
8+
#include <ESPmDNS.h>
9+
#include <HTTPUpdateServer.h>
10+
11+
#ifndef STASSID
12+
#define STASSID "your-ssid"
13+
#define STAPSK "your-password"
14+
#endif
15+
16+
const char* host = "esp32-webupdate";
17+
const char* ssid = STASSID;
18+
const char* password = STAPSK;
19+
20+
WebServer httpServer(80);
21+
HTTPUpdateServer httpUpdater;
22+
23+
void setup(void) {
24+
25+
Serial.begin(115200);
26+
Serial.println();
27+
Serial.println("Booting Sketch...");
28+
WiFi.mode(WIFI_AP_STA);
29+
WiFi.begin(ssid, password);
30+
31+
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
32+
WiFi.begin(ssid, password);
33+
Serial.println("WiFi failed, retrying.");
34+
}
35+
36+
MDNS.begin(host);
37+
if (MDNS.begin("esp32")) {
38+
Serial.println("mDNS responder started");
39+
}
40+
41+
42+
httpUpdater.setup(&httpServer);
43+
httpServer.begin();
44+
45+
MDNS.addService("http", "tcp", 80);
46+
Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
47+
}
48+
49+
void loop(void) {
50+
httpServer.handleClient();
51+
}

Diff for: libraries/HTTPUpdateServer/keywords.txt

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#######################################
2+
# Syntax Coloring Map For HTTPUpdateServer
3+
#######################################
4+
5+
#######################################
6+
# Datatypes (KEYWORD1)
7+
#######################################
8+
9+
ESP32HTTPUpdateServer KEYWORD1
10+
11+
#######################################
12+
# Methods and Functions (KEYWORD2)
13+
#######################################
14+
15+
begin KEYWORD2
16+
setup KEYWORD2
17+
18+
#######################################
19+
# Constants (LITERAL1)
20+
#######################################

Diff for: libraries/HTTPUpdateServer/library.properties

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name=HTTPUpdateServer
2+
version=1.0
3+
author=Hristo Kapanakov
4+
maintainer=
5+
sentence=Simple HTTP Update server based on the WebServer
6+
paragraph=The library accepts HTTP post requests to the /update url, and updates the ESP32 firmware.
7+
category=Communication
8+
url=
9+
architectures=esp32

Diff for: libraries/HTTPUpdateServer/src/HTTPUpdateServer.h

+166
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#ifndef __HTTP_UPDATE_SERVER_H
2+
#define __HTTP_UPDATE_SERVER_H
3+
4+
#include<SPIFFS.h>
5+
#include <StreamString.h>
6+
#include <Update.h>
7+
#include <WebServer.h>
8+
9+
10+
static const char serverIndex[] PROGMEM =
11+
R"(<!DOCTYPE html>
12+
<html lang='en'>
13+
<head>
14+
<meta charset='utf-8'>
15+
<meta name='viewport' content='width=device-width,initial-scale=1'/>
16+
</head>
17+
<body>
18+
<form method='POST' action='' enctype='multipart/form-data'>
19+
Firmware:<br>
20+
<input type='file' accept='.bin,.bin.gz' name='firmware'>
21+
<input type='submit' value='Update Firmware'>
22+
</form>
23+
<form method='POST' action='' enctype='multipart/form-data'>
24+
FileSystem:<br>
25+
<input type='file' accept='.bin,.bin.gz,.image' name='filesystem'>
26+
<input type='submit' value='Update FileSystem'>
27+
</form>
28+
</body>
29+
</html>)";
30+
static const char successResponse[] PROGMEM =
31+
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update Success! Rebooting...";
32+
33+
class HTTPUpdateServer
34+
{
35+
public:
36+
HTTPUpdateServer(bool serial_debug=false) {
37+
_serial_output = serial_debug;
38+
_server = NULL;
39+
_username = emptyString;
40+
_password = emptyString;
41+
_authenticated = false;
42+
}
43+
44+
void setup(WebServer *server)
45+
{
46+
setup(server, emptyString, emptyString);
47+
}
48+
49+
void setup(WebServer *server, const String& path)
50+
{
51+
setup(server, path, emptyString, emptyString);
52+
}
53+
54+
void setup(WebServer *server, const String& username, const String& password)
55+
{
56+
setup(server, "/update", username, password);
57+
}
58+
59+
void setup(WebServer *server, const String& path, const String& username, const String& password)
60+
{
61+
62+
_server = server;
63+
_username = username;
64+
_password = password;
65+
66+
// handler for the /update form page
67+
_server->on(path.c_str(), HTTP_GET, [&]() {
68+
if (_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
69+
return _server->requestAuthentication();
70+
_server->send_P(200, PSTR("text/html"), serverIndex);
71+
});
72+
73+
// handler for the /update form POST (once file upload finishes)
74+
_server->on(path.c_str(), HTTP_POST, [&]() {
75+
if (!_authenticated)
76+
return _server->requestAuthentication();
77+
if (Update.hasError()) {
78+
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
79+
}
80+
else {
81+
_server->client().setNoDelay(true);
82+
_server->send_P(200, PSTR("text/html"), successResponse);
83+
delay(100);
84+
_server->client().stop();
85+
ESP.restart();
86+
}
87+
}, [&]() {
88+
// handler for the file upload, get's the sketch bytes, and writes
89+
// them through the Update object
90+
HTTPUpload& upload = _server->upload();
91+
92+
if (upload.status == UPLOAD_FILE_START) {
93+
_updaterError.clear();
94+
if (_serial_output)
95+
Serial.setDebugOutput(true);
96+
97+
_authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
98+
if (!_authenticated) {
99+
if (_serial_output)
100+
Serial.printf("Unauthenticated Update\n");
101+
return;
102+
}
103+
104+
if (_serial_output)
105+
Serial.printf("Update: %s\n", upload.filename.c_str());
106+
if (upload.name == "filesystem") {
107+
if (!Update.begin(SPIFFS.totalBytes(), U_SPIFFS)) {//start with max available size
108+
if (_serial_output) Update.printError(Serial);
109+
}
110+
}
111+
else {
112+
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
113+
if (!Update.begin(maxSketchSpace, U_FLASH)) {//start with max available size
114+
_setUpdaterError();
115+
}
116+
}
117+
}
118+
else if (_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()) {
119+
if (_serial_output) Serial.printf(".");
120+
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
121+
_setUpdaterError();
122+
}
123+
}
124+
else if (_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()) {
125+
if (Update.end(true)) { //true to set the size to the current progress
126+
if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
127+
}
128+
else {
129+
_setUpdaterError();
130+
}
131+
if (_serial_output) Serial.setDebugOutput(false);
132+
}
133+
else if (_authenticated && upload.status == UPLOAD_FILE_ABORTED) {
134+
Update.end();
135+
if (_serial_output) Serial.println("Update was aborted");
136+
}
137+
delay(0);
138+
});
139+
}
140+
141+
void updateCredentials(const String& username, const String& password)
142+
{
143+
_username = username;
144+
_password = password;
145+
}
146+
147+
protected:
148+
void _setUpdaterError()
149+
{
150+
if (_serial_output) Update.printError(Serial);
151+
StreamString str;
152+
Update.printError(str);
153+
_updaterError = str.c_str();
154+
}
155+
156+
private:
157+
bool _serial_output;
158+
WebServer *_server;
159+
String _username;
160+
String _password;
161+
bool _authenticated;
162+
String _updaterError;
163+
};
164+
165+
166+
#endif

0 commit comments

Comments
 (0)