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\n Rebooting...\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