| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |   SDWebServer - Example WebServer with SD Card backend for esp8266 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Copyright (c) 2015 Hristo Gochkov. All rights reserved. | 
					
						
							|  |  |  |   This file is part of the WebServer library for Arduino environment. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |   modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |   License as published by the Free Software Foundation; either | 
					
						
							|  |  |  |   version 2.1 of the License, or (at your option) any later version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |   but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |   Lesser General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   You should have received a copy of the GNU Lesser General Public | 
					
						
							|  |  |  |   License along with this library; if not, write to the Free Software | 
					
						
							|  |  |  |   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Have a FAT Formatted SD Card connected to the SPI port of the ESP8266 | 
					
						
							|  |  |  |   The web root is the SD Card root folder | 
					
						
							|  |  |  |   File extensions with more than 3 charecters are not supported by the SD Library | 
					
						
							|  |  |  |   File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter | 
					
						
							|  |  |  |   index.htm is the default index (works on subfolders as well) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #include <WiFi.h>
 | 
					
						
							|  |  |  | #include <WiFiClient.h>
 | 
					
						
							|  |  |  | #include <WebServer.h>
 | 
					
						
							|  |  |  | #include <ESPmDNS.h>
 | 
					
						
							|  |  |  | #include <SPI.h>
 | 
					
						
							|  |  |  | #include <SD.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define DBG_OUTPUT_PORT Serial
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const char* ssid = "**********"; | 
					
						
							|  |  |  | const char* password = "**********"; | 
					
						
							|  |  |  | const char* host = "esp32sd"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebServer server(80); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool hasSD = false; | 
					
						
							|  |  |  | File uploadFile; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void returnOK() { | 
					
						
							|  |  |  |   server.send(200, "text/plain", ""); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void returnFail(String msg) { | 
					
						
							|  |  |  |   server.send(500, "text/plain", msg + "\r\n"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool loadFromSdCard(String path) { | 
					
						
							|  |  |  |   String dataType = "text/plain"; | 
					
						
							|  |  |  |   if (path.endsWith("/")) { | 
					
						
							|  |  |  |     path += "index.htm"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (path.endsWith(".src")) { | 
					
						
							|  |  |  |     path = path.substring(0, path.lastIndexOf(".")); | 
					
						
							|  |  |  |   } else if (path.endsWith(".htm")) { | 
					
						
							|  |  |  |     dataType = "text/html"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".css")) { | 
					
						
							|  |  |  |     dataType = "text/css"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".js")) { | 
					
						
							|  |  |  |     dataType = "application/javascript"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".png")) { | 
					
						
							|  |  |  |     dataType = "image/png"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".gif")) { | 
					
						
							|  |  |  |     dataType = "image/gif"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".jpg")) { | 
					
						
							|  |  |  |     dataType = "image/jpeg"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".ico")) { | 
					
						
							|  |  |  |     dataType = "image/x-icon"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".xml")) { | 
					
						
							|  |  |  |     dataType = "text/xml"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".pdf")) { | 
					
						
							|  |  |  |     dataType = "application/pdf"; | 
					
						
							|  |  |  |   } else if (path.endsWith(".zip")) { | 
					
						
							|  |  |  |     dataType = "application/zip"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   File dataFile = SD.open(path.c_str()); | 
					
						
							|  |  |  |   if (dataFile.isDirectory()) { | 
					
						
							|  |  |  |     path += "/index.htm"; | 
					
						
							|  |  |  |     dataType = "text/html"; | 
					
						
							|  |  |  |     dataFile = SD.open(path.c_str()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (!dataFile) { | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (server.hasArg("download")) { | 
					
						
							|  |  |  |     dataType = "application/octet-stream"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (server.streamFile(dataFile, dataType) != dataFile.size()) { | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.println("Sent less data than expected!"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   dataFile.close(); | 
					
						
							|  |  |  |   return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleFileUpload() { | 
					
						
							|  |  |  |   if (server.uri() != "/edit") { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   HTTPUpload& upload = server.upload(); | 
					
						
							|  |  |  |   if (upload.status == UPLOAD_FILE_START) { | 
					
						
							|  |  |  |     if (SD.exists((char *)upload.filename.c_str())) { | 
					
						
							|  |  |  |       SD.remove((char *)upload.filename.c_str()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename); | 
					
						
							|  |  |  |   } else if (upload.status == UPLOAD_FILE_WRITE) { | 
					
						
							|  |  |  |     if (uploadFile) { | 
					
						
							|  |  |  |       uploadFile.write(upload.buf, upload.currentSize); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize); | 
					
						
							|  |  |  |   } else if (upload.status == UPLOAD_FILE_END) { | 
					
						
							|  |  |  |     if (uploadFile) { | 
					
						
							|  |  |  |       uploadFile.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void deleteRecursive(String path) { | 
					
						
							|  |  |  |   File file = SD.open((char *)path.c_str()); | 
					
						
							|  |  |  |   if (!file.isDirectory()) { | 
					
						
							|  |  |  |     file.close(); | 
					
						
							|  |  |  |     SD.remove((char *)path.c_str()); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   file.rewindDirectory(); | 
					
						
							|  |  |  |   while (true) { | 
					
						
							|  |  |  |     File entry = file.openNextFile(); | 
					
						
							|  |  |  |     if (!entry) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     String entryPath = path + "/" + entry.name(); | 
					
						
							|  |  |  |     if (entry.isDirectory()) { | 
					
						
							|  |  |  |       entry.close(); | 
					
						
							|  |  |  |       deleteRecursive(entryPath); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       entry.close(); | 
					
						
							|  |  |  |       SD.remove((char *)entryPath.c_str()); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     yield(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   SD.rmdir((char *)path.c_str()); | 
					
						
							|  |  |  |   file.close(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleDelete() { | 
					
						
							|  |  |  |   if (server.args() == 0) { | 
					
						
							|  |  |  |     return returnFail("BAD ARGS"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String path = server.arg(0); | 
					
						
							|  |  |  |   if (path == "/" || !SD.exists((char *)path.c_str())) { | 
					
						
							|  |  |  |     returnFail("BAD PATH"); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   deleteRecursive(path); | 
					
						
							|  |  |  |   returnOK(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleCreate() { | 
					
						
							|  |  |  |   if (server.args() == 0) { | 
					
						
							|  |  |  |     return returnFail("BAD ARGS"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String path = server.arg(0); | 
					
						
							|  |  |  |   if (path == "/" || SD.exists((char *)path.c_str())) { | 
					
						
							|  |  |  |     returnFail("BAD PATH"); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (path.indexOf('.') > 0) { | 
					
						
							|  |  |  |     File file = SD.open((char *)path.c_str(), FILE_WRITE); | 
					
						
							|  |  |  |     if (file) { | 
					
						
							|  |  |  |       file.write(0); | 
					
						
							|  |  |  |       file.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     SD.mkdir((char *)path.c_str()); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   returnOK(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void printDirectory() { | 
					
						
							|  |  |  |   if (!server.hasArg("dir")) { | 
					
						
							|  |  |  |     return returnFail("BAD ARGS"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String path = server.arg("dir"); | 
					
						
							|  |  |  |   if (path != "/" && !SD.exists((char *)path.c_str())) { | 
					
						
							|  |  |  |     return returnFail("BAD PATH"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   File dir = SD.open((char *)path.c_str()); | 
					
						
							|  |  |  |   path = String(); | 
					
						
							|  |  |  |   if (!dir.isDirectory()) { | 
					
						
							|  |  |  |     dir.close(); | 
					
						
							|  |  |  |     return returnFail("NOT DIR"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   dir.rewindDirectory(); | 
					
						
							|  |  |  |   server.setContentLength(CONTENT_LENGTH_UNKNOWN); | 
					
						
							|  |  |  |   server.send(200, "text/json", ""); | 
					
						
							|  |  |  |   WiFiClient client = server.client(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   server.sendContent("["); | 
					
						
							|  |  |  |   for (int cnt = 0; true; ++cnt) { | 
					
						
							|  |  |  |     File entry = dir.openNextFile(); | 
					
						
							|  |  |  |     if (!entry) { | 
					
						
							|  |  |  |       break; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     String output; | 
					
						
							|  |  |  |     if (cnt > 0) { | 
					
						
							|  |  |  |       output = ','; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     output += "{\"type\":\""; | 
					
						
							|  |  |  |     output += (entry.isDirectory()) ? "dir" : "file"; | 
					
						
							|  |  |  |     output += "\",\"name\":\""; | 
					
						
							| 
									
										
										
										
											2021-04-15 17:25:01 +03:00
										 |  |  |     output += entry.path(); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |     output += "\""; | 
					
						
							|  |  |  |     output += "}"; | 
					
						
							|  |  |  |     server.sendContent(output); | 
					
						
							|  |  |  |     entry.close(); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   server.sendContent("]"); | 
					
						
							|  |  |  |   dir.close(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleNotFound() { | 
					
						
							|  |  |  |   if (hasSD && loadFromSdCard(server.uri())) { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String message = "SDCARD Not Detected\n\n"; | 
					
						
							|  |  |  |   message += "URI: "; | 
					
						
							|  |  |  |   message += server.uri(); | 
					
						
							|  |  |  |   message += "\nMethod: "; | 
					
						
							|  |  |  |   message += (server.method() == HTTP_GET) ? "GET" : "POST"; | 
					
						
							|  |  |  |   message += "\nArguments: "; | 
					
						
							|  |  |  |   message += server.args(); | 
					
						
							|  |  |  |   message += "\n"; | 
					
						
							|  |  |  |   for (uint8_t i = 0; i < server.args(); i++) { | 
					
						
							|  |  |  |     message += " NAME:" + server.argName(i) + "\n VALUE:" + server.arg(i) + "\n"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   server.send(404, "text/plain", message); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print(message); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void setup(void) { | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.begin(115200); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.setDebugOutput(true); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("\n"); | 
					
						
							|  |  |  |   WiFi.mode(WIFI_STA); | 
					
						
							|  |  |  |   WiFi.begin(ssid, password); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("Connecting to "); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println(ssid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // Wait for connection
 | 
					
						
							|  |  |  |   uint8_t i = 0; | 
					
						
							|  |  |  |   while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
 | 
					
						
							|  |  |  |     delay(500); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (i == 21) { | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("Could not connect to"); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.println(ssid); | 
					
						
							|  |  |  |     while (1) { | 
					
						
							|  |  |  |       delay(500); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("Connected! IP address: "); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println(WiFi.localIP()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (MDNS.begin(host)) { | 
					
						
							|  |  |  |     MDNS.addService("http", "tcp", 80); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.println("MDNS responder started"); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("You can now connect to http://"); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print(host); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.println(".local"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   server.on("/list", HTTP_GET, printDirectory); | 
					
						
							|  |  |  |   server.on("/edit", HTTP_DELETE, handleDelete); | 
					
						
							|  |  |  |   server.on("/edit", HTTP_PUT, handleCreate); | 
					
						
							|  |  |  |   server.on("/edit", HTTP_POST, []() { | 
					
						
							|  |  |  |     returnOK(); | 
					
						
							|  |  |  |   }, handleFileUpload); | 
					
						
							|  |  |  |   server.onNotFound(handleNotFound); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   server.begin(); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("HTTP server started"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (SD.begin(SS)) { | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.println("SD Card initialized."); | 
					
						
							|  |  |  |     hasSD = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void loop(void) { | 
					
						
							|  |  |  |   server.handleClient(); | 
					
						
							| 
									
										
										
										
											2021-03-05 13:40:52 +02:00
										 |  |  |   delay(2);//allow the cpu to switch to other tasks
 | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  | } |