├── CSS.h ├── ESP_File_Download_Upload_Dir_Stream_V01.ino ├── ESP_File_Download_Upload_Dir_Stream_V04_SPIFFS.ino ├── ESP_File_Download_Upload_Dir_Strream_V02.ino ├── ESP_File_Download_Upload_Dir_Strream_V03.ino ├── Licence.txt ├── Network.h ├── README.md └── Sys_Variables.h /CSS.h: -------------------------------------------------------------------------------- 1 | void append_page_header() { 2 | webpage = F(""); 3 | webpage += F(""); 4 | webpage += F("File Server"); // NOTE: 1em = 16px 5 | webpage += F(""); 6 | webpage += F("

File Server "); webpage += String(ServerVersion) + "

"; 34 | } 35 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | void append_page_footer(){ // Saves repeating many lines of code for HTML page footers 37 | webpage += F(""); 45 | webpage += ""; 48 | webpage += F(""); 49 | } 50 | -------------------------------------------------------------------------------- /ESP_File_Download_Upload_Dir_Stream_V01.ino: -------------------------------------------------------------------------------- 1 | /* Version 1 2 | * ESP32/ESP8266 example of downloading, uploading, deleting, streaming and a file directory of a device's Filing System 3 | 4 | This software, the ideas and concepts is Copyright (c) David Bird 2018. All rights to this software are reserved. 5 | 6 | Any redistribution or reproduction of any part or all of the contents in any form is prohibited other than the following: 7 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 8 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 9 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 10 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 11 | 12 | The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the 13 | software use is visible to an end-user. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY 16 | OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | See more at http://www.dsbird.org.uk 20 | 21 | */ 22 | #ifdef ESP8266 23 | #include // Built-in 24 | #include // Built-in 25 | #include // Built-in 26 | #include 27 | #else 28 | #include // Built-in 29 | #include // Built-in 30 | #include // https://github.com/Pedroalbuquerque/ESP32WebServer download and place in your Libraries folder 31 | #include 32 | #include "FS.h" 33 | #endif 34 | 35 | #include "Network.h" 36 | #include "Sys_Variables.h" 37 | #include "CSS.h" 38 | #include 39 | #include 40 | 41 | #ifdef ESP8266 42 | ESP8266WiFiMulti wifiMulti; 43 | ESP8266WebServer server(80); 44 | #else 45 | WiFiMulti wifiMulti; 46 | ESP32WebServer server(80); 47 | #endif 48 | 49 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 | void setup(void){ 51 | Serial.begin(115200); 52 | if (!WiFi.config(local_IP, gateway, subnet, dns)) { //WiFi.config(ip, gateway, subnet, dns1, dns2); 53 | Serial.println("WiFi STATION Failed to configure Correctly"); 54 | } 55 | wifiMulti.addAP(ssid_1, password_1); // add Wi-Fi networks you want to connect to, it connects strongest to weakest 56 | wifiMulti.addAP(ssid_2, password_2); // Adjust the values in the Network tab 57 | wifiMulti.addAP(ssid_3, password_3); 58 | wifiMulti.addAP(ssid_4, password_4); // You don't need 4 entries, this is for example! 59 | 60 | Serial.println("Connecting ..."); 61 | while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above 62 | delay(250); Serial.print('.'); 63 | } 64 | Serial.println("\nConnected to "+WiFi.SSID()+" Use IP address: "+WiFi.localIP().toString()); // Report which SSID and IP is in use 65 | // The logical name http://fileserver.local will also access the device if you have 'Bonjour' running or your system supports multicast dns 66 | if (!MDNS.begin(servername)) { // Set your preferred server name, if you use "myserver" the address would be http://myserver.local/ 67 | Serial.println(F("Error setting up MDNS responder!")); 68 | ESP.restart(); 69 | } 70 | #ifdef ESP32 71 | // Note: SD_Card readers on the ESP32 will NOT work unless there is a pull-up on MISO, either do this or wire one on (1K to 4K7) 72 | Serial.println(MISO); 73 | pinMode(19,INPUT_PULLUP); 74 | #endif 75 | Serial.print(F("Initializing SD card...")); 76 | if (!SD.begin(SD_CS_pin)) { // see if the card is present and can be initialised. Wemos SD-Card CS uses D8 77 | Serial.println(F("Card failed or not present, no SD Card data logging possible...")); 78 | SD_present = false; 79 | } 80 | else 81 | { 82 | Serial.println(F("Card initialised... file access enabled...")); 83 | SD_present = true; 84 | } 85 | // Note: Using the ESP32 and SD_Card readers requires a 1K to 4K7 pull-up to 3v3 on the MISO line, otherwise they do-not function. 86 | //---------------------------------------------------------------------- 87 | ///////////////////////////// Server Commands 88 | server.on("/", HomePage); 89 | server.on("/download", File_Download); 90 | server.on("/upload", File_Upload); 91 | server.on("/fupload", HTTP_POST,[](){ server.send(200);}, handleFileUpload); 92 | server.on("/stream", File_Stream); 93 | server.on("/delete", File_Delete); 94 | server.on("/dir", SD_dir); 95 | 96 | ///////////////////////////// End of Request commands 97 | server.begin(); 98 | Serial.println("HTTP server started"); 99 | } 100 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 101 | void loop(void){ 102 | server.handleClient(); // Listen for client connections 103 | } 104 | 105 | // All supporting functions from here... 106 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 107 | void HomePage(){ 108 | SendHTML_Header(); 109 | webpage += F(""); 110 | webpage += F(""); 111 | webpage += F(""); 112 | webpage += F(""); 113 | webpage += F(""); 114 | append_page_footer(); 115 | SendHTML_Content(); 116 | SendHTML_Stop(); // Stop is needed because no content length was sent 117 | } 118 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 119 | void File_Download(){ // This gets called twice, the first pass selects the input, the second pass then processes the command line arguments 120 | if (server.args() > 0 ) { // Arguments were received 121 | if (server.hasArg("download")) SD_file_download(server.arg(0)); 122 | } 123 | else SelectInput("Enter filename to download","download","download"); 124 | } 125 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 126 | void SD_file_download(String filename){ 127 | if (SD_present) { 128 | File download = SD.open("/"+filename); 129 | if (download) { 130 | server.sendHeader("Content-Type", "text/text"); 131 | server.sendHeader("Content-Disposition", "attachment; filename="+filename); 132 | server.sendHeader("Connection", "close"); 133 | server.streamFile(download, "application/octet-stream"); 134 | download.close(); 135 | } else ReportFileNotPresent("download"); 136 | } else ReportSDNotPresent(); 137 | } 138 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 139 | void File_Upload(){ 140 | append_page_header(); 141 | webpage += F("

Select File to Upload

"); 142 | webpage += F("
"); 143 | webpage += F("
"); 144 | webpage += F("

"); 145 | webpage += F("[Back]

"); 146 | append_page_footer(); 147 | server.send(200, "text/html",webpage); 148 | } 149 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 150 | File UploadFile; 151 | void handleFileUpload(){ // upload a new file to the Filing system 152 | HTTPUpload& uploadfile = server.upload(); // See https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/srcv 153 | // For further information on 'status' structure, there are other reasons such as a failed transfer that could be used 154 | if(uploadfile.status == UPLOAD_FILE_START) 155 | { 156 | String filename = uploadfile.filename; 157 | if(!filename.startsWith("/")) filename = "/"+filename; 158 | Serial.print("Upload File Name: "); Serial.println(filename); 159 | SD.remove(filename); // Remove a previous version, otherwise data is appended the file again 160 | UploadFile = SD.open(filename, FILE_WRITE); // Open the file for writing in SPIFFS (create it, if doesn't exist) 161 | filename = String(); 162 | } 163 | else if (uploadfile.status == UPLOAD_FILE_WRITE) 164 | { 165 | if(UploadFile) UploadFile.write(uploadfile.buf, uploadfile.currentSize); // Write the received bytes to the file 166 | } 167 | else if (uploadfile.status == UPLOAD_FILE_END) 168 | { 169 | if(UploadFile) // If the file was successfully created 170 | { 171 | UploadFile.close(); // Close the file again 172 | Serial.print("Upload Size: "); Serial.println(uploadfile.totalSize); 173 | webpage = ""; 174 | append_page_header(); 175 | webpage += F("

File was successfully uploaded

"); 176 | webpage += F("

Uploaded File Name: "); webpage += uploadfile.filename+"

"; 177 | webpage += F("

File Size: "); webpage += file_size(uploadfile.totalSize) + "


"; 178 | append_page_footer(); 179 | server.send(200,"text/html",webpage); 180 | } 181 | else 182 | { 183 | ReportCouldNotCreateFile("upload"); 184 | } 185 | } 186 | } 187 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188 | void SD_dir(){ 189 | if (SD_present) { 190 | File root = SD.open("/"); 191 | if (root) { 192 | root.rewindDirectory(); 193 | SendHTML_Header(); 194 | webpage += F("

SD Card Contents


"); 195 | webpage += F(""); 196 | webpage += F(""); 197 | printDirectory("/",0); 198 | webpage += F("
Name/TypeType File/DirFile Size
"); 199 | SendHTML_Content(); 200 | root.close(); 201 | } 202 | else 203 | { 204 | SendHTML_Header(); 205 | webpage += F("

No Files Found

"); 206 | } 207 | append_page_footer(); 208 | SendHTML_Content(); 209 | SendHTML_Stop(); // Stop is needed because no content length was sent 210 | } else ReportSDNotPresent(); 211 | } 212 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 213 | void printDirectory(const char * dirname, uint8_t levels){ 214 | File root = SD.open(dirname); 215 | #ifdef ESP8266 216 | root.rewindDirectory(); //Only needed for ESP8266 217 | #endif 218 | if(!root){ 219 | return; 220 | } 221 | if(!root.isDirectory()){ 222 | return; 223 | } 224 | File file = root.openNextFile(); 225 | while(file){ 226 | if (webpage.length() > 1000) { 227 | SendHTML_Content(); 228 | } 229 | if(file.isDirectory()){ 230 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""+String(file.name())+""; 231 | printDirectory(file.name(), levels-1); 232 | } 233 | else 234 | { 235 | webpage += ""+String(file.name())+""; 236 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""; 237 | int bytes = file.size(); 238 | String fsize = ""; 239 | if (bytes < 1024) fsize = String(bytes)+" B"; 240 | else if(bytes < (1024 * 1024)) fsize = String(bytes/1024.0,3)+" KB"; 241 | else if(bytes < (1024 * 1024 * 1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 242 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 243 | webpage += ""+fsize+""; 244 | } 245 | file = root.openNextFile(); 246 | } 247 | file.close(); 248 | } 249 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 250 | void File_Stream(){ 251 | if (server.args() > 0 ) { // Arguments were received 252 | if (server.hasArg("stream")) SD_file_stream(server.arg(0)); 253 | } 254 | else SelectInput("Enter a File to Stream","stream","stream"); 255 | } 256 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 257 | void SD_file_stream(String filename) { 258 | if (SD_present) { 259 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 260 | if (dataFile) { 261 | if (dataFile.available()) { // If data is available and present 262 | String dataType = "application/octet-stream"; 263 | if (server.streamFile(dataFile, dataType) != dataFile.size()) {Serial.print(F("Sent less data than expected!")); } 264 | } 265 | dataFile.close(); // close the file: 266 | } else ReportFileNotPresent("Cstream"); 267 | } else ReportSDNotPresent(); 268 | } 269 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 270 | void File_Delete(){ 271 | if (server.args() > 0 ) { // Arguments were received 272 | if (server.hasArg("delete")) SD_file_delete(server.arg(0)); 273 | } 274 | else SelectInput("Select a File to Delete","delete","delete"); 275 | } 276 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 277 | void SD_file_delete(String filename) { // Delete the file 278 | if (SD_present) { 279 | SendHTML_Header(); 280 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 281 | if (dataFile) 282 | { 283 | if (SD.remove("/"+filename)) { 284 | Serial.println(F("File deleted successfully")); 285 | webpage += "

File '"+filename+"' has been erased

"; 286 | webpage += F("[Back]

"); 287 | } 288 | else 289 | { 290 | webpage += F("

File was not deleted - error

"); 291 | webpage += F("[Back]

"); 292 | } 293 | } else ReportFileNotPresent("delete"); 294 | append_page_footer(); 295 | SendHTML_Content(); 296 | SendHTML_Stop(); 297 | } else ReportSDNotPresent(); 298 | } 299 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 300 | void SendHTML_Header(){ 301 | server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 302 | server.sendHeader("Pragma", "no-cache"); 303 | server.sendHeader("Expires", "-1"); 304 | server.setContentLength(CONTENT_LENGTH_UNKNOWN); 305 | server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 306 | append_page_header(); 307 | server.sendContent(webpage); 308 | webpage = ""; 309 | } 310 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 311 | void SendHTML_Content(){ 312 | server.sendContent(webpage); 313 | webpage = ""; 314 | } 315 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 316 | void SendHTML_Stop(){ 317 | server.sendContent(""); 318 | server.client().stop(); // Stop is needed because no content length was sent 319 | } 320 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 321 | void SelectInput(String heading1, String command, String arg_calling_name){ 322 | SendHTML_Header(); 323 | webpage += F("

"); webpage += heading1 + "

"; 324 | webpage += F(""; // Must match the calling argument e.g. '/chart' calls '/chart' after selection but with arguments! 325 | webpage += F("
"); 326 | webpage += F("

"); 327 | append_page_footer(); 328 | SendHTML_Content(); 329 | SendHTML_Stop(); 330 | } 331 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 332 | void ReportSDNotPresent(){ 333 | SendHTML_Header(); 334 | webpage += F("

No SD Card present

"); 335 | webpage += F("[Back]

"); 336 | append_page_footer(); 337 | SendHTML_Content(); 338 | SendHTML_Stop(); 339 | } 340 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 341 | void ReportFileNotPresent(String target){ 342 | SendHTML_Header(); 343 | webpage += F("

File does not exist

"); 344 | webpage += F("[Back]

"; 345 | append_page_footer(); 346 | SendHTML_Content(); 347 | SendHTML_Stop(); 348 | } 349 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 350 | void ReportCouldNotCreateFile(String target){ 351 | SendHTML_Header(); 352 | webpage += F("

Could Not Create Uploaded File (write-protected?)

"); 353 | webpage += F("[Back]

"; 354 | append_page_footer(); 355 | SendHTML_Content(); 356 | SendHTML_Stop(); 357 | } 358 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 359 | String file_size(int bytes){ 360 | String fsize = ""; 361 | if (bytes < 1024) fsize = String(bytes)+" B"; 362 | else if(bytes < (1024*1024)) fsize = String(bytes/1024.0,3)+" KB"; 363 | else if(bytes < (1024*1024*1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 364 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 365 | return fsize; 366 | } 367 | -------------------------------------------------------------------------------- /ESP_File_Download_Upload_Dir_Stream_V04_SPIFFS.ino: -------------------------------------------------------------------------------- 1 | /* Version 4 2 | * 3 | * ESP32/ESP8266 example of downloading and uploading a file from or to the device's Filing System, including Directory and Streaming of files. 4 | * 5 | This software, the ideas and concepts is Copyright (c) David Bird 2019. All rights to this software are reserved. 6 | 7 | Any redistribution or reproduction of any part or all of the contents in any form is prohibited other than the following: 8 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 9 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 10 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 11 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 12 | 13 | The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the 14 | software use is visible to an end-user. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY 17 | OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | See more at http://www.dsbird.org.uk 21 | * 22 | */ 23 | #ifdef ESP8266 24 | #include // Built-in 25 | #include // Built-in 26 | #else 27 | #include // Built-in 28 | #include 29 | #include "SPIFFS.h" 30 | #endif 31 | 32 | #define ServerVersion "1.0" 33 | String webpage = ""; 34 | bool SPIFFS_present = false; 35 | 36 | const char ssid[] = "your SSID"; 37 | const char password[] = "your PASSWORD"; 38 | 39 | #include "FS.h" 40 | #include "CSS.h" 41 | #include 42 | 43 | #ifdef ESP8266 44 | ESP8266WebServer server(80); 45 | #else 46 | WebServer server(80); 47 | #endif 48 | 49 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 50 | void setup(void){ 51 | Serial.begin(115200); 52 | 53 | WiFi.begin(ssid,password); 54 | while (WiFi.status() != WL_CONNECTED) { // Wait for the Wi-Fi to connect 55 | delay(250); Serial.print('.'); 56 | } 57 | Serial.println("\nConnected to "+WiFi.SSID()+" Use IP address: "+WiFi.localIP().toString()); // Report which SSID and IP is in use 58 | #ifdef ESP8266 59 | if (!SPIFFS.begin()) { 60 | #else 61 | if (!SPIFFS.begin(true)) { 62 | #endif 63 | Serial.println("SPIFFS initialisation failed..."); 64 | SPIFFS_present = false; 65 | } 66 | else 67 | { 68 | Serial.println(F("SPIFFS initialised... file access enabled...")); 69 | SPIFFS_present = true; 70 | } 71 | //---------------------------------------------------------------------- 72 | ///////////////////////////// Server Commands 73 | server.on("/", HomePage); 74 | server.on("/download", File_Download); 75 | server.on("/upload", File_Upload); 76 | server.on("/fupload", HTTP_POST,[](){ server.send(200);}, handleFileUpload); 77 | server.on("/stream", File_Stream); 78 | server.on("/delete", File_Delete); 79 | server.on("/dir", SPIFFS_dir); 80 | 81 | ///////////////////////////// End of Request commands 82 | server.begin(); 83 | Serial.println("HTTP server started"); 84 | } 85 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 86 | void loop(void){ 87 | server.handleClient(); // Listen for client connections 88 | } 89 | 90 | // All supporting functions from here... 91 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 92 | void HomePage(){ 93 | SendHTML_Header(); 94 | webpage += F(""); 95 | webpage += F(""); 96 | webpage += F(""); 97 | webpage += F(""); 98 | webpage += F(""); 99 | append_page_footer(); 100 | SendHTML_Content(); 101 | SendHTML_Stop(); // Stop is needed because no content length was sent 102 | } 103 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 | void File_Download(){ // This gets called twice, the first pass selects the input, the second pass then processes the command line arguments 105 | if (server.args() > 0 ) { // Arguments were received 106 | if (server.hasArg("download")) DownloadFile(server.arg(0)); 107 | } 108 | else SelectInput("Enter filename to download","download","download"); 109 | } 110 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 111 | void DownloadFile(String filename){ 112 | if (SPIFFS_present) { 113 | File download = SPIFFS.open("/"+filename, "r"); 114 | if (download) { 115 | server.sendHeader("Content-Type", "text/text"); 116 | server.sendHeader("Content-Disposition", "attachment; filename="+filename); 117 | server.sendHeader("Connection", "close"); 118 | server.streamFile(download, "application/octet-stream"); 119 | download.close(); 120 | } else ReportFileNotPresent("download"); 121 | } else ReportSPIFFSNotPresent(); 122 | } 123 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 124 | void File_Upload(){ 125 | append_page_header(); 126 | webpage += F("

Select File to Upload

"); 127 | webpage += F(""); 128 | webpage += F("
"); 129 | webpage += F("

"); 130 | webpage += F("[Back]

"); 131 | append_page_footer(); 132 | server.send(200, "text/html",webpage); 133 | } 134 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 135 | File UploadFile; 136 | void handleFileUpload(){ // upload a new file to the Filing system 137 | HTTPUpload& uploadfile = server.upload(); // See https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/srcv 138 | // For further information on 'status' structure, there are other reasons such as a failed transfer that could be used 139 | if(uploadfile.status == UPLOAD_FILE_START) 140 | { 141 | String filename = uploadfile.filename; 142 | if(!filename.startsWith("/")) filename = "/"+filename; 143 | Serial.print("Upload File Name: "); Serial.println(filename); 144 | SPIFFS.remove(filename); // Remove a previous version, otherwise data is appended the file again 145 | UploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create it, if doesn't exist) 146 | } 147 | else if (uploadfile.status == UPLOAD_FILE_WRITE) 148 | { 149 | if(UploadFile) UploadFile.write(uploadfile.buf, uploadfile.currentSize); // Write the received bytes to the file 150 | } 151 | else if (uploadfile.status == UPLOAD_FILE_END) 152 | { 153 | if(UploadFile) // If the file was successfully created 154 | { 155 | UploadFile.close(); // Close the file again 156 | Serial.print("Upload Size: "); Serial.println(uploadfile.totalSize); 157 | webpage = ""; 158 | append_page_header(); 159 | webpage += F("

File was successfully uploaded

"); 160 | webpage += F("

Uploaded File Name: "); webpage += uploadfile.filename+"

"; 161 | webpage += F("

File Size: "); webpage += file_size(uploadfile.totalSize) + "


"; 162 | append_page_footer(); 163 | server.send(200,"text/html",webpage); 164 | } 165 | else 166 | { 167 | ReportCouldNotCreateFile("upload"); 168 | } 169 | } 170 | } 171 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 172 | #ifdef ESP32 173 | void SPIFFS_dir(){ 174 | if (SPIFFS_present) { 175 | File root = SPIFFS.open("/"); 176 | if (root) { 177 | root.rewindDirectory(); 178 | SendHTML_Header(); 179 | webpage += F("

SD Card Contents


"); 180 | webpage += F(""); 181 | webpage += F(""); 182 | printDirectory("/",0); 183 | webpage += F("
Name/TypeType File/DirFile Size
"); 184 | SendHTML_Content(); 185 | root.close(); 186 | } 187 | else 188 | { 189 | SendHTML_Header(); 190 | webpage += F("

No Files Found

"); 191 | } 192 | append_page_footer(); 193 | SendHTML_Content(); 194 | SendHTML_Stop(); // Stop is needed because no content length was sent 195 | } else ReportSPIFFSNotPresent(); 196 | } 197 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 198 | void printDirectory(const char * dirname, uint8_t levels){ 199 | File root = SPIFFS.open(dirname); 200 | if(!root){ 201 | return; 202 | } 203 | if(!root.isDirectory()){ 204 | return; 205 | } 206 | File file = root.openNextFile(); 207 | while(file){ 208 | if (webpage.length() > 1000) { 209 | SendHTML_Content(); 210 | } 211 | if(file.isDirectory()){ 212 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""+String(file.name())+""; 213 | printDirectory(file.name(), levels-1); 214 | } 215 | else 216 | { 217 | webpage += ""+String(file.name())+""; 218 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""; 219 | int bytes = file.size(); 220 | String fsize = ""; 221 | if (bytes < 1024) fsize = String(bytes)+" B"; 222 | else if(bytes < (1024 * 1024)) fsize = String(bytes/1024.0,3)+" KB"; 223 | else if(bytes < (1024 * 1024 * 1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 224 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 225 | webpage += ""+fsize+""; 226 | } 227 | file = root.openNextFile(); 228 | } 229 | file.close(); 230 | } 231 | #endif 232 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 233 | #ifdef ESP8266 234 | void SPIFFS_dir(){ 235 | String str; 236 | if (SPIFFS_present) { 237 | Dir dir = SPIFFS.openDir("/"); 238 | SendHTML_Header(); 239 | webpage += F("

SPIFFS Card Contents


"); 240 | webpage += F(""); 241 | webpage += F(""); 242 | while (dir.next()) { 243 | Serial.print(dir.fileName()); 244 | webpage += ""; 245 | str = dir.fileName(); 246 | str += " / "; 247 | if(dir.fileSize()) { 248 | File f = dir.openFile("r"); 249 | Serial.println(f.size()); 250 | int bytes = f.size(); 251 | String fsize = ""; 252 | if (bytes < 1024) fsize = String(bytes)+" B"; 253 | else if(bytes < (1024 * 1024)) fsize = String(bytes/1024.0,3)+" KB"; 254 | else if(bytes < (1024 * 1024 * 1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 255 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 256 | webpage += ""; 257 | f.close(); 258 | } 259 | str += String(dir.fileSize()); 260 | str += "\r\n"; 261 | Serial.println(str); 262 | } 263 | webpage += F("
Name/TypeFile Size
"+String(dir.fileName())+""+fsize+"
"); 264 | SendHTML_Content(); 265 | append_page_footer(); 266 | SendHTML_Content(); 267 | SendHTML_Stop(); // Stop is needed because no content length was sent 268 | } else ReportSPIFFSNotPresent(); 269 | } 270 | #endif 271 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 272 | void File_Stream(){ 273 | if (server.args() > 0 ) { // Arguments were received 274 | if (server.hasArg("stream")) SPIFFS_file_stream(server.arg(0)); 275 | } 276 | else SelectInput("Enter a File to Stream","stream","stream"); 277 | } 278 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 279 | void SPIFFS_file_stream(String filename) { 280 | if (SPIFFS_present) { 281 | File dataFile = SPIFFS.open("/"+filename, "r"); // Now read data from SPIFFS Card 282 | if (dataFile) { 283 | if (dataFile.available()) { // If data is available and present 284 | String dataType = "application/octet-stream"; 285 | if (server.streamFile(dataFile, dataType) != dataFile.size()) {Serial.print(F("Sent less data than expected!")); } 286 | } 287 | dataFile.close(); // close the file: 288 | } else ReportFileNotPresent("Cstream"); 289 | } else ReportSPIFFSNotPresent(); 290 | } 291 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 292 | void File_Delete(){ 293 | if (server.args() > 0 ) { // Arguments were received 294 | if (server.hasArg("delete")) SPIFFS_file_delete(server.arg(0)); 295 | } 296 | else SelectInput("Select a File to Delete","delete","delete"); 297 | } 298 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 299 | void SPIFFS_file_delete(String filename) { // Delete the file 300 | if (SPIFFS_present) { 301 | SendHTML_Header(); 302 | File dataFile = SPIFFS.open("/"+filename, "r"); // Now read data from SPIFFS Card 303 | if (dataFile) 304 | { 305 | if (SPIFFS.remove("/"+filename)) { 306 | Serial.println(F("File deleted successfully")); 307 | webpage += "

File '"+filename+"' has been erased

"; 308 | webpage += F("[Back]

"); 309 | } 310 | else 311 | { 312 | webpage += F("

File was not deleted - error

"); 313 | webpage += F("[Back]

"); 314 | } 315 | } else ReportFileNotPresent("delete"); 316 | append_page_footer(); 317 | SendHTML_Content(); 318 | SendHTML_Stop(); 319 | } else ReportSPIFFSNotPresent(); 320 | } 321 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 322 | void SendHTML_Header(){ 323 | server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 324 | server.sendHeader("Pragma", "no-cache"); 325 | server.sendHeader("Expires", "-1"); 326 | server.setContentLength(CONTENT_LENGTH_UNKNOWN); 327 | server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 328 | append_page_header(); 329 | server.sendContent(webpage); 330 | webpage = ""; 331 | } 332 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 333 | void SendHTML_Content(){ 334 | server.sendContent(webpage); 335 | webpage = ""; 336 | } 337 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 338 | void SendHTML_Stop(){ 339 | server.sendContent(""); 340 | server.client().stop(); // Stop is needed because no content length was sent 341 | } 342 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 343 | void SelectInput(String heading1, String command, String arg_calling_name){ 344 | SendHTML_Header(); 345 | webpage += F("

"); webpage += heading1 + "

"; 346 | webpage += F(""; // Must match the calling argument e.g. '/chart' calls '/chart' after selection but with arguments! 347 | webpage += F("
"); 348 | webpage += F("

"); 349 | webpage += F("[Back]

"); 350 | append_page_footer(); 351 | SendHTML_Content(); 352 | SendHTML_Stop(); 353 | } 354 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 355 | void ReportSPIFFSNotPresent(){ 356 | SendHTML_Header(); 357 | webpage += F("

No SPIFFS Card present

"); 358 | webpage += F("[Back]

"); 359 | append_page_footer(); 360 | SendHTML_Content(); 361 | SendHTML_Stop(); 362 | } 363 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 364 | void ReportFileNotPresent(String target){ 365 | SendHTML_Header(); 366 | webpage += F("

File does not exist

"); 367 | webpage += F("[Back]

"; 368 | append_page_footer(); 369 | SendHTML_Content(); 370 | SendHTML_Stop(); 371 | } 372 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 373 | void ReportCouldNotCreateFile(String target){ 374 | SendHTML_Header(); 375 | webpage += F("

Could Not Create Uploaded File (write-protected?)

"); 376 | webpage += F("[Back]

"; 377 | append_page_footer(); 378 | SendHTML_Content(); 379 | SendHTML_Stop(); 380 | } 381 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 382 | String file_size(int bytes){ 383 | String fsize = ""; 384 | if (bytes < 1024) fsize = String(bytes)+" B"; 385 | else if(bytes < (1024*1024)) fsize = String(bytes/1024.0,3)+" KB"; 386 | else if(bytes < (1024*1024*1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 387 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 388 | return fsize; 389 | } 390 | -------------------------------------------------------------------------------- /ESP_File_Download_Upload_Dir_Strream_V02.ino: -------------------------------------------------------------------------------- 1 | /* Version 1 2 | * 3 | * ESP32/ESP8266 example of downloading and uploading a file from or to the device's Filing System 4 | * 5 | This software, the ideas and concepts is Copyright (c) David Bird 2018. All rights to this software are reserved. 6 | 7 | Any redistribution or reproduction of any part or all of the contents in any form is prohibited other than the following: 8 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 9 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 10 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 11 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 12 | 13 | The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the 14 | software use is visible to an end-user. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY 17 | OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | See more at http://www.dsbird.org.uk 21 | * 22 | */ 23 | #ifdef ESP8266 24 | #include // Built-in 25 | #include // Built-in 26 | #include // Built-in 27 | #include 28 | #else 29 | #include // Built-in 30 | #include // Built-in 31 | #include // https://github.com/Pedroalbuquerque/ESP32WebServer download and place in your Libraries folder 32 | #include 33 | #include "FS.h" 34 | #endif 35 | 36 | #include "Network.h" 37 | #include "Sys_Variables.h" 38 | #include "CSS.h" 39 | #include 40 | #include 41 | 42 | #ifdef ESP8266 43 | ESP8266WiFiMulti wifiMulti; 44 | ESP8266WebServer server(80); 45 | #else 46 | WiFiMulti wifiMulti; 47 | ESP32WebServer server(80); 48 | #endif 49 | 50 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | void setup(void){ 52 | Serial.begin(115200); 53 | if (!WiFi.config(local_IP, gateway, subnet, dns)) { //WiFi.config(ip, gateway, subnet, dns1, dns2); 54 | Serial.println("WiFi STATION Failed to configure Correctly"); 55 | } 56 | wifiMulti.addAP(ssid_1, password_1); // add Wi-Fi networks you want to connect to, it connects strongest to weakest 57 | wifiMulti.addAP(ssid_2, password_2); // Adjust the values in the Network tab 58 | wifiMulti.addAP(ssid_3, password_3); 59 | wifiMulti.addAP(ssid_4, password_4); // You don't need 4 entries, this is for example! 60 | 61 | Serial.println("Connecting ..."); 62 | while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above 63 | delay(250); Serial.print('.'); 64 | } 65 | Serial.println("\nConnected to "+WiFi.SSID()+" Use IP address: "+WiFi.localIP().toString()); // Report which SSID and IP is in use 66 | // The logical name http://fileserver.local will also access the device if you have 'Bonjour' running or your system supports multicast dns 67 | if (!MDNS.begin(servername)) { // Set your preferred server name, if you use "myserver" the address would be http://myserver.local/ 68 | Serial.println(F("Error setting up MDNS responder!")); 69 | ESP.restart(); 70 | } 71 | #ifdef ESP32 72 | // Note: SD_Card readers on the ESP32 will NOT work unless there is a pull-up on MISO, either do this or wire one on (1K to 4K7) 73 | Serial.println(MISO); 74 | pinMode(19,INPUT_PULLUP); 75 | #endif 76 | Serial.print(F("Initializing SD card...")); 77 | if (!SD.begin(SD_CS_pin)) { // see if the card is present and can be initialised. Wemos SD-Card CS uses D8 78 | Serial.println(F("Card failed or not present, no SD Card data logging possible...")); 79 | SD_present = false; 80 | } 81 | else 82 | { 83 | Serial.println(F("Card initialised... file access enabled...")); 84 | SD_present = true; 85 | } 86 | // Note: Using the ESP32 and SD_Card readers requires a 1K to 4K7 pull-up to 3v3 on the MISO line, otherwise they do-not function. 87 | //---------------------------------------------------------------------- 88 | ///////////////////////////// Server Commands 89 | server.on("/", HomePage); 90 | server.on("/download", File_Download); 91 | server.on("/upload", File_Upload); 92 | server.on("/fupload", HTTP_POST,[](){ server.send(200);}, handleFileUpload); 93 | server.on("/stream", File_Stream); 94 | server.on("/delete", File_Delete); 95 | server.on("/dir", SD_dir); 96 | 97 | ///////////////////////////// End of Request commands 98 | server.begin(); 99 | Serial.println("HTTP server started"); 100 | } 101 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 | void loop(void){ 103 | server.handleClient(); // Listen for client connections 104 | } 105 | 106 | // All supporting functions from here... 107 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 | void HomePage(){ 109 | SendHTML_Header(); 110 | webpage += F(""); 111 | webpage += F(""); 112 | webpage += F(""); 113 | webpage += F(""); 114 | webpage += F(""); 115 | append_page_footer(); 116 | SendHTML_Content(); 117 | SendHTML_Stop(); // Stop is needed because no content length was sent 118 | } 119 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 | void File_Download(){ // This gets called twice, the first pass selects the input, the second pass then processes the command line arguments 121 | if (server.args() > 0 ) { // Arguments were received 122 | if (server.hasArg("download")) SD_file_download(server.arg(0)); 123 | } 124 | else SelectInput("Enter filename to download","download","download"); 125 | } 126 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 | void SD_file_download(String filename){ 128 | if (SD_present) { 129 | File download = SD.open("/"+filename); 130 | if (download) { 131 | server.sendHeader("Content-Type", "text/text"); 132 | server.sendHeader("Content-Disposition", "attachment; filename="+filename); 133 | server.sendHeader("Connection", "close"); 134 | server.streamFile(download, "application/octet-stream"); 135 | download.close(); 136 | } else ReportFileNotPresent("download"); 137 | } else ReportSDNotPresent(); 138 | } 139 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 140 | void File_Upload(){ 141 | append_page_header(); 142 | webpage += F("

Select File to Upload

"); 143 | webpage += F(""); 144 | webpage += F("
"); 145 | webpage += F("

"); 146 | webpage += F("[Back]

"); 147 | append_page_footer(); 148 | server.send(200, "text/html",webpage); 149 | } 150 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 151 | File UploadFile; 152 | void handleFileUpload(){ // upload a new file to the Filing system 153 | HTTPUpload& uploadfile = server.upload(); // See https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/srcv 154 | // For further information on 'status' structure, there are other reasons such as a failed transfer that could be used 155 | if(uploadfile.status == UPLOAD_FILE_START) 156 | { 157 | String filename = uploadfile.filename; 158 | if(!filename.startsWith("/")) filename = "/"+filename; 159 | Serial.print("Upload File Name: "); Serial.println(filename); 160 | SD.remove(filename); // Remove a previous version, otherwise data is appended the file again 161 | UploadFile = SD.open(filename, FILE_WRITE); // Open the file for writing in SPIFFS (create it, if doesn't exist) 162 | filename = String(); 163 | } 164 | else if (uploadfile.status == UPLOAD_FILE_WRITE) 165 | { 166 | if(UploadFile) UploadFile.write(uploadfile.buf, uploadfile.currentSize); // Write the received bytes to the file 167 | } 168 | else if (uploadfile.status == UPLOAD_FILE_END) 169 | { 170 | if(UploadFile) // If the file was successfully created 171 | { 172 | UploadFile.close(); // Close the file again 173 | Serial.print("Upload Size: "); Serial.println(uploadfile.totalSize); 174 | webpage = ""; 175 | append_page_header(); 176 | webpage += F("

File was successfully uploaded

"); 177 | webpage += F("

Uploaded File Name: "); webpage += uploadfile.filename+"

"; 178 | webpage += F("

File Size: "); webpage += file_size(uploadfile.totalSize) + "


"; 179 | append_page_footer(); 180 | server.send(200,"text/html",webpage); 181 | } 182 | else 183 | { 184 | ReportCouldNotCreateFile("upload"); 185 | } 186 | } 187 | } 188 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 189 | void SD_dir(){ 190 | if (SD_present) { 191 | File root = SD.open("/"); 192 | if (root) { 193 | root.rewindDirectory(); 194 | SendHTML_Header(); 195 | webpage += F("

SD Card Contents


"); 196 | webpage += F(""); 197 | webpage += F(""); 198 | printDirectory("/",0); 199 | webpage += F("
Name/TypeType File/DirFile Size
"); 200 | SendHTML_Content(); 201 | root.close(); 202 | } 203 | else 204 | { 205 | SendHTML_Header(); 206 | webpage += F("

No Files Found

"); 207 | } 208 | append_page_footer(); 209 | SendHTML_Content(); 210 | SendHTML_Stop(); // Stop is needed because no content length was sent 211 | } else ReportSDNotPresent(); 212 | } 213 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 214 | void printDirectory(const char * dirname, uint8_t levels){ 215 | File root = SD.open(dirname); 216 | #ifdef ESP8266 217 | root.rewindDirectory(); //Only needed for ESP8266 218 | #endif 219 | if(!root){ 220 | return; 221 | } 222 | if(!root.isDirectory()){ 223 | return; 224 | } 225 | File file = root.openNextFile(); 226 | while(file){ 227 | if (webpage.length() > 1000) { 228 | SendHTML_Content(); 229 | } 230 | if(file.isDirectory()){ 231 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""+String(file.name())+""; 232 | printDirectory(file.name(), levels-1); 233 | } 234 | else 235 | { 236 | webpage += ""+String(file.name())+""; 237 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""; 238 | int bytes = file.size(); 239 | String fsize = ""; 240 | if (bytes < 1024) fsize = String(bytes)+" B"; 241 | else if(bytes < (1024 * 1024)) fsize = String(bytes/1024.0,3)+" KB"; 242 | else if(bytes < (1024 * 1024 * 1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 243 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 244 | webpage += ""+fsize+""; 245 | } 246 | file = root.openNextFile(); 247 | } 248 | file.close(); 249 | } 250 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 251 | void File_Stream(){ 252 | if (server.args() > 0 ) { // Arguments were received 253 | if (server.hasArg("stream")) SD_file_stream(server.arg(0)); 254 | } 255 | else SelectInput("Enter a File to Stream","stream","stream"); 256 | } 257 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 258 | void SD_file_stream(String filename) { 259 | if (SD_present) { 260 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 261 | if (dataFile) { 262 | if (dataFile.available()) { // If data is available and present 263 | String dataType = "application/octet-stream"; 264 | if (server.streamFile(dataFile, dataType) != dataFile.size()) {Serial.print(F("Sent less data than expected!")); } 265 | } 266 | dataFile.close(); // close the file: 267 | } else ReportFileNotPresent("Cstream"); 268 | } else ReportSDNotPresent(); 269 | } 270 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 271 | void File_Delete(){ 272 | if (server.args() > 0 ) { // Arguments were received 273 | if (server.hasArg("delete")) SD_file_delete(server.arg(0)); 274 | } 275 | else SelectInput("Select a File to Delete","delete","delete"); 276 | } 277 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 278 | void SD_file_delete(String filename) { // Delete the file 279 | if (SD_present) { 280 | SendHTML_Header(); 281 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 282 | if (dataFile) 283 | { 284 | if (SD.remove("/"+filename)) { 285 | Serial.println(F("File deleted successfully")); 286 | webpage += "

File '"+filename+"' has been erased

"; 287 | webpage += F("[Back]

"); 288 | } 289 | else 290 | { 291 | webpage += F("

File was not deleted - error

"); 292 | webpage += F("[Back]

"); 293 | } 294 | } else ReportFileNotPresent("delete"); 295 | append_page_footer(); 296 | SendHTML_Content(); 297 | SendHTML_Stop(); 298 | } else ReportSDNotPresent(); 299 | } 300 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 301 | void SendHTML_Header(){ 302 | server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 303 | server.sendHeader("Pragma", "no-cache"); 304 | server.sendHeader("Expires", "-1"); 305 | server.setContentLength(CONTENT_LENGTH_UNKNOWN); 306 | server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 307 | append_page_header(); 308 | server.sendContent(webpage); 309 | webpage = ""; 310 | } 311 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 312 | void SendHTML_Content(){ 313 | server.sendContent(webpage); 314 | webpage = ""; 315 | } 316 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 317 | void SendHTML_Stop(){ 318 | server.sendContent(""); 319 | server.client().stop(); // Stop is needed because no content length was sent 320 | } 321 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 322 | void SelectInput(String heading1, String command, String arg_calling_name){ 323 | SendHTML_Header(); 324 | webpage += F("

"); webpage += heading1 + "

"; 325 | webpage += F(""; // Must match the calling argument e.g. '/chart' calls '/chart' after selection but with arguments! 326 | webpage += F("
"); 327 | webpage += F("

"); 328 | append_page_footer(); 329 | SendHTML_Content(); 330 | SendHTML_Stop(); 331 | } 332 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 333 | void ReportSDNotPresent(){ 334 | SendHTML_Header(); 335 | webpage += F("

No SD Card present

"); 336 | webpage += F("[Back]

"); 337 | append_page_footer(); 338 | SendHTML_Content(); 339 | SendHTML_Stop(); 340 | } 341 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 342 | void ReportFileNotPresent(String target){ 343 | SendHTML_Header(); 344 | webpage += F("

File does not exist

"); 345 | webpage += F("[Back]

"; 346 | append_page_footer(); 347 | SendHTML_Content(); 348 | SendHTML_Stop(); 349 | } 350 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 351 | void ReportCouldNotCreateFile(String target){ 352 | SendHTML_Header(); 353 | webpage += F("

Could Not Create Uploaded File (write-protected?)

"); 354 | webpage += F("[Back]

"; 355 | append_page_footer(); 356 | SendHTML_Content(); 357 | SendHTML_Stop(); 358 | } 359 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 360 | String file_size(int bytes){ 361 | String fsize = ""; 362 | if (bytes < 1024) fsize = String(bytes)+" B"; 363 | else if(bytes < (1024*1024)) fsize = String(bytes/1024.0,3)+" KB"; 364 | else if(bytes < (1024*1024*1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 365 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 366 | return fsize; 367 | } 368 | -------------------------------------------------------------------------------- /ESP_File_Download_Upload_Dir_Strream_V03.ino: -------------------------------------------------------------------------------- 1 | /* Version 1 2 | * 3 | * ESP32/ESP8266 example of downloading and uploading a file from or to the device's Filing System 4 | * 5 | This software, the ideas and concepts is Copyright (c) David Bird 2018. All rights to this software are reserved. 6 | 7 | Any redistribution or reproduction of any part or all of the contents in any form is prohibited other than the following: 8 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 9 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 10 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 11 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 12 | 13 | The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the 14 | software use is visible to an end-user. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY 17 | OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | See more at http://www.dsbird.org.uk 21 | * 22 | */ 23 | #ifdef ESP8266 24 | #include // Built-in 25 | #include // Built-in 26 | #include // Built-in 27 | #include 28 | #else 29 | #include // Built-in 30 | #include // Built-in 31 | #include // https://github.com/Pedroalbuquerque/ESP32WebServer download and place in your Libraries folder 32 | #include 33 | #include "FS.h" 34 | #endif 35 | 36 | #include "Network.h" 37 | #include "Sys_Variables.h" 38 | #include "CSS.h" 39 | #include 40 | #include 41 | 42 | #ifdef ESP8266 43 | ESP8266WiFiMulti wifiMulti; 44 | ESP8266WebServer server(80); 45 | #else 46 | WiFiMulti wifiMulti; 47 | ESP32WebServer server(80); 48 | #endif 49 | 50 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 51 | void setup(void){ 52 | Serial.begin(115200); 53 | if (!WiFi.config(local_IP, gateway, subnet, dns)) { //WiFi.config(ip, gateway, subnet, dns1, dns2); 54 | Serial.println("WiFi STATION Failed to configure Correctly"); 55 | } 56 | wifiMulti.addAP(ssid_1, password_1); // add Wi-Fi networks you want to connect to, it connects strongest to weakest 57 | wifiMulti.addAP(ssid_2, password_2); // Adjust the values in the Network tab 58 | wifiMulti.addAP(ssid_3, password_3); 59 | wifiMulti.addAP(ssid_4, password_4); // You don't need 4 entries, this is for example! 60 | 61 | Serial.println("Connecting ..."); 62 | while (wifiMulti.run() != WL_CONNECTED) { // Wait for the Wi-Fi to connect: scan for Wi-Fi networks, and connect to the strongest of the networks above 63 | delay(250); Serial.print('.'); 64 | } 65 | Serial.println("\nConnected to "+WiFi.SSID()+" Use IP address: "+WiFi.localIP().toString()); // Report which SSID and IP is in use 66 | // The logical name http://fileserver.local will also access the device if you have 'Bonjour' running or your system supports multicast dns 67 | if (!MDNS.begin(servername)) { // Set your preferred server name, if you use "myserver" the address would be http://myserver.local/ 68 | Serial.println(F("Error setting up MDNS responder!")); 69 | ESP.restart(); 70 | } 71 | #ifdef ESP32 72 | // Note: SD_Card readers on the ESP32 will NOT work unless there is a pull-up on MISO, either do this or wire one on (1K to 4K7) 73 | Serial.println(MISO); 74 | pinMode(19,INPUT_PULLUP); 75 | #endif 76 | Serial.print(F("Initializing SD card...")); 77 | if (!SD.begin(SD_CS_pin)) { // see if the card is present and can be initialised. Wemos SD-Card CS uses D8 78 | Serial.println(F("Card failed or not present, no SD Card data logging possible...")); 79 | SD_present = false; 80 | } 81 | else 82 | { 83 | Serial.println(F("Card initialised... file access enabled...")); 84 | SD_present = true; 85 | } 86 | // Note: Using the ESP32 and SD_Card readers requires a 1K to 4K7 pull-up to 3v3 on the MISO line, otherwise they do-not function. 87 | //---------------------------------------------------------------------- 88 | ///////////////////////////// Server Commands 89 | server.on("/", HomePage); 90 | server.on("/download", File_Download); 91 | server.on("/upload", File_Upload); 92 | server.on("/fupload", HTTP_POST,[](){ server.send(200);}, handleFileUpload); 93 | server.on("/stream", File_Stream); 94 | server.on("/delete", File_Delete); 95 | server.on("/dir", SD_dir); 96 | 97 | ///////////////////////////// End of Request commands 98 | server.begin(); 99 | Serial.println("HTTP server started"); 100 | } 101 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 | void loop(void){ 103 | server.handleClient(); // Listen for client connections 104 | } 105 | 106 | // All supporting functions from here... 107 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 | void HomePage(){ 109 | SendHTML_Header(); 110 | webpage += F(""); 111 | webpage += F(""); 112 | webpage += F(""); 113 | webpage += F(""); 114 | webpage += F(""); 115 | append_page_footer(); 116 | SendHTML_Content(); 117 | SendHTML_Stop(); // Stop is needed because no content length was sent 118 | } 119 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 120 | void File_Download(){ // This gets called twice, the first pass selects the input, the second pass then processes the command line arguments 121 | if (server.args() > 0 ) { // Arguments were received 122 | if (server.hasArg("download")) SD_file_download(server.arg(0)); 123 | } 124 | else SelectInput("Enter filename to download","download","download"); 125 | } 126 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 127 | void SD_file_download(String filename){ 128 | if (SD_present) { 129 | File download = SD.open("/"+filename); 130 | if (download) { 131 | server.sendHeader("Content-Type", "text/text"); 132 | server.sendHeader("Content-Disposition", "attachment; filename="+filename); 133 | server.sendHeader("Connection", "close"); 134 | server.streamFile(download, "application/octet-stream"); 135 | download.close(); 136 | } else ReportFileNotPresent("download"); 137 | } else ReportSDNotPresent(); 138 | } 139 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 140 | void File_Upload(){ 141 | Serial.println("File upload stage-1"); 142 | append_page_header(); 143 | webpage += F("

Select File to Upload

"); 144 | webpage += F(""); 145 | webpage += F("
"); 146 | webpage += F("

"); 147 | webpage += F("[Back]

"); 148 | append_page_footer(); 149 | Serial.println("File upload stage-2"); 150 | server.send(200, "text/html",webpage); 151 | } 152 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 153 | File UploadFile; 154 | void handleFileUpload(){ // upload a new file to the Filing system 155 | Serial.println("File upload stage-3"); 156 | HTTPUpload& uploadfile = server.upload(); // See https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/srcv 157 | // For further information on 'status' structure, there are other reasons such as a failed transfer that could be used 158 | if(uploadfile.status == UPLOAD_FILE_START) 159 | { 160 | Serial.println("File upload stage-4"); 161 | String filename = uploadfile.filename; 162 | if(!filename.startsWith("/")) filename = "/"+filename; 163 | Serial.print("Upload File Name: "); Serial.println(filename); 164 | SD.remove(filename); // Remove a previous version, otherwise data is appended the file again 165 | UploadFile = SD.open(filename, FILE_WRITE); // Open the file for writing in SPIFFS (create it, if doesn't exist) 166 | filename = String(); 167 | } 168 | else if (uploadfile.status == UPLOAD_FILE_WRITE) 169 | { 170 | Serial.println("File upload stage-5"); 171 | if(UploadFile) UploadFile.write(uploadfile.buf, uploadfile.currentSize); // Write the received bytes to the file 172 | } 173 | else if (uploadfile.status == UPLOAD_FILE_END) 174 | { 175 | if(UploadFile) // If the file was successfully created 176 | { 177 | UploadFile.close(); // Close the file again 178 | Serial.print("Upload Size: "); Serial.println(uploadfile.totalSize); 179 | webpage = ""; 180 | append_page_header(); 181 | webpage += F("

File was successfully uploaded

"); 182 | webpage += F("

Uploaded File Name: "); webpage += uploadfile.filename+"

"; 183 | webpage += F("

File Size: "); webpage += file_size(uploadfile.totalSize) + "


"; 184 | append_page_footer(); 185 | server.send(200,"text/html",webpage); 186 | } 187 | else 188 | { 189 | ReportCouldNotCreateFile("upload"); 190 | } 191 | } 192 | } 193 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 194 | void SD_dir(){ 195 | if (SD_present) { 196 | File root = SD.open("/"); 197 | if (root) { 198 | root.rewindDirectory(); 199 | SendHTML_Header(); 200 | webpage += F("

SD Card Contents


"); 201 | webpage += F(""); 202 | webpage += F(""); 203 | printDirectory("/",0); 204 | webpage += F("
Name/TypeType File/DirFile Size
"); 205 | SendHTML_Content(); 206 | root.close(); 207 | } 208 | else 209 | { 210 | SendHTML_Header(); 211 | webpage += F("

No Files Found

"); 212 | } 213 | append_page_footer(); 214 | SendHTML_Content(); 215 | SendHTML_Stop(); // Stop is needed because no content length was sent 216 | } else ReportSDNotPresent(); 217 | } 218 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 219 | void printDirectory(const char * dirname, uint8_t levels){ 220 | File root = SD.open(dirname); 221 | #ifdef ESP8266 222 | root.rewindDirectory(); //Only needed for ESP8266 223 | #endif 224 | if(!root){ 225 | return; 226 | } 227 | if(!root.isDirectory()){ 228 | return; 229 | } 230 | File file = root.openNextFile(); 231 | while(file){ 232 | if (webpage.length() > 1000) { 233 | SendHTML_Content(); 234 | } 235 | if(file.isDirectory()){ 236 | Serial.println(String(file.isDirectory()?"Dir ":"File ")+String(file.name())); 237 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""+String(file.name())+""; 238 | printDirectory(file.name(), levels-1); 239 | } 240 | else 241 | { 242 | //Serial.print(String(file.name())+"\t"); 243 | webpage += ""+String(file.name())+""; 244 | Serial.print(String(file.isDirectory()?"Dir ":"File ")+String(file.name())+"\t"); 245 | webpage += ""+String(file.isDirectory()?"Dir":"File")+""; 246 | int bytes = file.size(); 247 | String fsize = ""; 248 | if (bytes < 1024) fsize = String(bytes)+" B"; 249 | else if(bytes < (1024 * 1024)) fsize = String(bytes/1024.0,3)+" KB"; 250 | else if(bytes < (1024 * 1024 * 1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 251 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 252 | webpage += ""+fsize+""; 253 | Serial.println(String(fsize)); 254 | } 255 | file = root.openNextFile(); 256 | } 257 | file.close(); 258 | } 259 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 260 | void File_Stream(){ 261 | if (server.args() > 0 ) { // Arguments were received 262 | if (server.hasArg("stream")) SD_file_stream(server.arg(0)); 263 | } 264 | else SelectInput("Enter a File to Stream","stream","stream"); 265 | } 266 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 267 | void SD_file_stream(String filename) { 268 | if (SD_present) { 269 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 270 | Serial.print("Streaming file: "); Serial.println(filename); 271 | if (dataFile) { 272 | if (dataFile.available()) { // If data is available and present 273 | String dataType = "application/octet-stream"; 274 | if (server.streamFile(dataFile, dataType) != dataFile.size()) {Serial.print(F("Sent less data than expected!")); } 275 | } 276 | dataFile.close(); // close the file: 277 | } else ReportFileNotPresent("Cstream"); 278 | } else ReportSDNotPresent(); 279 | } 280 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 281 | void File_Delete(){ 282 | if (server.args() > 0 ) { // Arguments were received 283 | if (server.hasArg("delete")) SD_file_delete(server.arg(0)); 284 | } 285 | else SelectInput("Select a File to Delete","delete","delete"); 286 | } 287 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 288 | void SD_file_delete(String filename) { // Delete the file 289 | if (SD_present) { 290 | SendHTML_Header(); 291 | File dataFile = SD.open("/"+filename, FILE_READ); // Now read data from SD Card 292 | Serial.print("Deleting file: "); Serial.println(filename); 293 | if (dataFile) 294 | { 295 | if (SD.remove("/"+filename)) { 296 | Serial.println(F("File deleted successfully")); 297 | webpage += "

File '"+filename+"' has been erased

"; 298 | webpage += F("[Back]

"); 299 | } 300 | else 301 | { 302 | webpage += F("

File was not deleted - error

"); 303 | webpage += F("[Back]

"); 304 | } 305 | } else ReportFileNotPresent("delete"); 306 | append_page_footer(); 307 | SendHTML_Content(); 308 | SendHTML_Stop(); 309 | } else ReportSDNotPresent(); 310 | } 311 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 312 | void SendHTML_Header(){ 313 | server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate"); 314 | server.sendHeader("Pragma", "no-cache"); 315 | server.sendHeader("Expires", "-1"); 316 | server.setContentLength(CONTENT_LENGTH_UNKNOWN); 317 | server.send(200, "text/html", ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. 318 | append_page_header(); 319 | server.sendContent(webpage); 320 | webpage = ""; 321 | } 322 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 323 | void SendHTML_Content(){ 324 | server.sendContent(webpage); 325 | webpage = ""; 326 | } 327 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 328 | void SendHTML_Stop(){ 329 | server.sendContent(""); 330 | server.client().stop(); // Stop is needed because no content length was sent 331 | } 332 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 333 | void SelectInput(String heading1, String command, String arg_calling_name){ 334 | SendHTML_Header(); 335 | webpage += F("

"); webpage += heading1 + "

"; 336 | webpage += F(""; // Must match the calling argument e.g. '/chart' calls '/chart' after selection but with arguments! 337 | webpage += F("
"); 338 | webpage += F("

"); 339 | append_page_footer(); 340 | SendHTML_Content(); 341 | SendHTML_Stop(); 342 | } 343 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 344 | void ReportSDNotPresent(){ 345 | SendHTML_Header(); 346 | webpage += F("

No SD Card present

"); 347 | webpage += F("[Back]

"); 348 | append_page_footer(); 349 | SendHTML_Content(); 350 | SendHTML_Stop(); 351 | } 352 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 353 | void ReportFileNotPresent(String target){ 354 | SendHTML_Header(); 355 | webpage += F("

File does not exist

"); 356 | webpage += F("[Back]

"; 357 | append_page_footer(); 358 | SendHTML_Content(); 359 | SendHTML_Stop(); 360 | } 361 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 362 | void ReportCouldNotCreateFile(String target){ 363 | SendHTML_Header(); 364 | webpage += F("

Could Not Create Uploaded File (write-protected?)

"); 365 | webpage += F("[Back]

"; 366 | append_page_footer(); 367 | SendHTML_Content(); 368 | SendHTML_Stop(); 369 | } 370 | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 371 | String file_size(int bytes){ 372 | String fsize = ""; 373 | if (bytes < 1024) fsize = String(bytes)+" B"; 374 | else if(bytes < (1024*1024)) fsize = String(bytes/1024.0,3)+" KB"; 375 | else if(bytes < (1024*1024*1024)) fsize = String(bytes/1024.0/1024.0,3)+" MB"; 376 | else fsize = String(bytes/1024.0/1024.0/1024.0,3)+" GB"; 377 | return fsize; 378 | } 379 | -------------------------------------------------------------------------------- /Licence.txt: -------------------------------------------------------------------------------- 1 | This software, the ideas and concepts is Copyright (c) David Bird 2014 and beyond. 2 | 3 | All rights to this software are reserved. 4 | 5 | It is prohibited to redistribute or reproduce of any part or all of the software contents in any form other than the following: 6 | 7 | 1. You may print or download to a local hard disk extracts for your personal and non-commercial use only. 8 | 9 | 2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material. 10 | 11 | 3. You may not, except with my express written permission, distribute or commercially exploit the content. 12 | 13 | 4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes. 14 | 15 | 5. You MUST include all of this copyright and permission notice ('as annotated') and this shall be included in all copies or substantial portions of the software and where the software use is visible to an end-user. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. 18 | 19 | FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20 | 21 | IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Network.h: -------------------------------------------------------------------------------- 1 | // Adjust the following values to match your needs 2 | // ----------------------------------------------- 3 | #define servername "fileserver" // Set your server's logical name here e.g. if 'myserver' then address is http://myserver.local/ 4 | IPAddress local_IP(192, 168, 0, 150); // Set your server's fixed IP address here 5 | IPAddress gateway(192, 168, 0, 1); // Set your network Gateway usually your Router base address 6 | IPAddress subnet(255, 255, 255, 0); // Set your network sub-network mask here 7 | IPAddress dns(192,168,0,1); // Set your network DNS usually your Router base address 8 | const char ssid_1[] = "your_SSID1"; 9 | const char password_1[] = "your_PASSWORD_for SSID1"; 10 | 11 | const char ssid_2[] = "your_SSID2"; 12 | const char password_2[] = "your_PASSWORD_for SSID2"; 13 | 14 | const char ssid_3[] = "your_SSID3"; 15 | const char password_3[] = "your_PASSWORD_for SSID3"; 16 | 17 | const char ssid_4[] = "your_SSID4"; 18 | const char password_4[] = "your_PASSWORD_for SSID4"; 19 | 20 | 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32-ESP8266-File-Download-Upload-Delete-Stream-and-Directory 2 | 3 | SPIFFS Version 4 | Copy sketch to a folder, including CSS. 5 | 6 | SD-Card Version 7 | Copy Sketch to a folder, including CSS and Network and Sys_Variables files all to same directory. 8 | 9 | For all versions adjust your netwrok credentials accordingly. 10 | 11 | ~~ 12 | 13 | ESP (32/8266) File Services in one application, enables management of files on an ESP using SD-Filing System 14 | 15 | Using HTTP and an HTML interface to download files from an ESP32/ESP8266 16 | 17 | Download all files to a sketch folder. 18 | 19 | Edit the Network tab and add in your SSID and PASSWORD, more if you have them. 20 | 21 | Choose your IP address, currently it is fixed to 192.168.0.150 22 | 23 | You can edit the logical name 'fileserver' to your requirements then access the device with http://fileserver.local but only if your browser has mDNS support otherwise use http://192.168.0.150/ 24 | 25 | NOTES:The ESP32 is not reliable when using SD Cards, please ensure you know how to connect the SPI bus to the SD-Card if not using an MH-ET Live ESP32 board and a Wemos SD-Card Shield. Although pull-ups are enabled, you may need to add an external 4k7 pull-up too on the MISO line 26 | -------------------------------------------------------------------------------- /Sys_Variables.h: -------------------------------------------------------------------------------- 1 | #define ServerVersion "1.0" 2 | String webpage = ""; 3 | bool SD_present = false; 4 | 5 | #ifdef ESP8266 6 | #define SD_CS_pin D8 // The pin on Wemos D1 Mini for SD Card Chip-Select 7 | #else 8 | #define SD_CS_pin 5 // Use pin 5 on MH-T Live ESP32 version of Wemos D1 Mini for SD Card Chip-Select 9 | #endif // Use pin 13 on Wemos ESP32 Pro 10 | 11 | 12 | --------------------------------------------------------------------------------