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