| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   FSWebServer - Example WebServer with FS backend for esp8266/esp32 | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   upload the contents of the data folder with MkSPIFFS Tool ("ESP32 Sketch Data Upload" in Tools menu in Arduino IDE) | 
					
						
							|  |  |  |   or you can upload the contents of a folder if you CD in that folder and run the following command: | 
					
						
							|  |  |  |   for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp32fs.local/edit; done | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   access the sample web page at http://esp32fs.local
 | 
					
						
							|  |  |  |   edit the page by going to http://esp32fs.local/edit
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | #include <WiFi.h>
 | 
					
						
							|  |  |  | #include <WiFiClient.h>
 | 
					
						
							|  |  |  | #include <WebServer.h>
 | 
					
						
							|  |  |  | #include <ESPmDNS.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  | #define FILESYSTEM SPIFFS
 | 
					
						
							|  |  |  | #define FORMAT_FILESYSTEM true
 | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  | #define DBG_OUTPUT_PORT Serial
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  | #if FILESYSTEM == FFat
 | 
					
						
							|  |  |  | #include <FFat.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | #if FILESYSTEM == SPIFFS
 | 
					
						
							|  |  |  | #include <SPIFFS.h>
 | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  | const char* ssid = "wifi-ssid"; | 
					
						
							|  |  |  | const char* password = "wifi-password"; | 
					
						
							|  |  |  | const char* host = "esp32fs"; | 
					
						
							|  |  |  | WebServer server(80); | 
					
						
							|  |  |  | //holds the current upload
 | 
					
						
							|  |  |  | File fsUploadFile; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //format bytes
 | 
					
						
							|  |  |  | String formatBytes(size_t bytes) { | 
					
						
							|  |  |  |   if (bytes < 1024) { | 
					
						
							|  |  |  |     return String(bytes) + "B"; | 
					
						
							|  |  |  |   } else if (bytes < (1024 * 1024)) { | 
					
						
							|  |  |  |     return String(bytes / 1024.0) + "KB"; | 
					
						
							|  |  |  |   } else if (bytes < (1024 * 1024 * 1024)) { | 
					
						
							|  |  |  |     return String(bytes / 1024.0 / 1024.0) + "MB"; | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | String getContentType(String filename) { | 
					
						
							|  |  |  |   if (server.hasArg("download")) { | 
					
						
							|  |  |  |     return "application/octet-stream"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".htm")) { | 
					
						
							|  |  |  |     return "text/html"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".html")) { | 
					
						
							|  |  |  |     return "text/html"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".css")) { | 
					
						
							|  |  |  |     return "text/css"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".js")) { | 
					
						
							|  |  |  |     return "application/javascript"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".png")) { | 
					
						
							|  |  |  |     return "image/png"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".gif")) { | 
					
						
							|  |  |  |     return "image/gif"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".jpg")) { | 
					
						
							|  |  |  |     return "image/jpeg"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".ico")) { | 
					
						
							|  |  |  |     return "image/x-icon"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".xml")) { | 
					
						
							|  |  |  |     return "text/xml"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".pdf")) { | 
					
						
							|  |  |  |     return "application/x-pdf"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".zip")) { | 
					
						
							|  |  |  |     return "application/x-zip"; | 
					
						
							|  |  |  |   } else if (filename.endsWith(".gz")) { | 
					
						
							|  |  |  |     return "application/x-gzip"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return "text/plain"; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool exists(String path){ | 
					
						
							|  |  |  |   bool yes = false; | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   File file = FILESYSTEM.open(path, "r"); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   if(!file.isDirectory()){ | 
					
						
							|  |  |  |     yes = true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   file.close(); | 
					
						
							|  |  |  |   return yes; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool handleFileRead(String path) { | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("handleFileRead: " + path); | 
					
						
							|  |  |  |   if (path.endsWith("/")) { | 
					
						
							|  |  |  |     path += "index.htm"; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String contentType = getContentType(path); | 
					
						
							|  |  |  |   String pathWithGz = path + ".gz"; | 
					
						
							|  |  |  |   if (exists(pathWithGz) || exists(path)) { | 
					
						
							|  |  |  |     if (exists(pathWithGz)) { | 
					
						
							|  |  |  |       path += ".gz"; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |     File file = FILESYSTEM.open(path, "r"); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |     server.streamFile(file, contentType); | 
					
						
							|  |  |  |     file.close(); | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleFileUpload() { | 
					
						
							|  |  |  |   if (server.uri() != "/edit") { | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   HTTPUpload& upload = server.upload(); | 
					
						
							|  |  |  |   if (upload.status == UPLOAD_FILE_START) { | 
					
						
							|  |  |  |     String filename = upload.filename; | 
					
						
							|  |  |  |     if (!filename.startsWith("/")) { | 
					
						
							|  |  |  |       filename = "/" + filename; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("handleFileUpload Name: "); DBG_OUTPUT_PORT.println(filename); | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |     fsUploadFile = FILESYSTEM.open(filename, "w"); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |     filename = String(); | 
					
						
							|  |  |  |   } else if (upload.status == UPLOAD_FILE_WRITE) { | 
					
						
							|  |  |  |     //DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize);
 | 
					
						
							|  |  |  |     if (fsUploadFile) { | 
					
						
							|  |  |  |       fsUploadFile.write(upload.buf, upload.currentSize); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } else if (upload.status == UPLOAD_FILE_END) { | 
					
						
							|  |  |  |     if (fsUploadFile) { | 
					
						
							|  |  |  |       fsUploadFile.close(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleFileDelete() { | 
					
						
							|  |  |  |   if (server.args() == 0) { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "BAD ARGS"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String path = server.arg(0); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("handleFileDelete: " + path); | 
					
						
							|  |  |  |   if (path == "/") { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "BAD PATH"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!exists(path)) { | 
					
						
							|  |  |  |     return server.send(404, "text/plain", "FileNotFound"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   FILESYSTEM.remove(path); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   server.send(200, "text/plain", ""); | 
					
						
							|  |  |  |   path = String(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleFileCreate() { | 
					
						
							|  |  |  |   if (server.args() == 0) { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "BAD ARGS"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   String path = server.arg(0); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("handleFileCreate: " + path); | 
					
						
							|  |  |  |   if (path == "/") { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "BAD PATH"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (exists(path)) { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "FILE EXISTS"); | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   File file = FILESYSTEM.open(path, "w"); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   if (file) { | 
					
						
							|  |  |  |     file.close(); | 
					
						
							|  |  |  |   } else { | 
					
						
							|  |  |  |     return server.send(500, "text/plain", "CREATE FAILED"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   server.send(200, "text/plain", ""); | 
					
						
							|  |  |  |   path = String(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void handleFileList() { | 
					
						
							|  |  |  |   if (!server.hasArg("dir")) { | 
					
						
							|  |  |  |     server.send(500, "text/plain", "BAD ARGS"); | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   String path = server.arg("dir"); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("handleFileList: " + path); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   File root = FILESYSTEM.open(path); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   path = String(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   String output = "["; | 
					
						
							|  |  |  |   if(root.isDirectory()){ | 
					
						
							|  |  |  |       File file = root.openNextFile(); | 
					
						
							|  |  |  |       while(file){ | 
					
						
							|  |  |  |           if (output != "[") { | 
					
						
							|  |  |  |             output += ','; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |           output += "{\"type\":\""; | 
					
						
							|  |  |  |           output += (file.isDirectory()) ? "dir" : "file"; | 
					
						
							|  |  |  |           output += "\",\"name\":\""; | 
					
						
							|  |  |  |           output += String(file.name()).substring(1); | 
					
						
							|  |  |  |           output += "\"}"; | 
					
						
							|  |  |  |           file = root.openNextFile(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   output += "]"; | 
					
						
							|  |  |  |   server.send(200, "text/json", output); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void setup(void) { | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.begin(115200); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("\n"); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.setDebugOutput(true); | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   if (FORMAT_FILESYSTEM) FILESYSTEM.format(); | 
					
						
							|  |  |  |   FILESYSTEM.begin(); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   { | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |       File root = FILESYSTEM.open("/"); | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |       File file = root.openNextFile(); | 
					
						
							|  |  |  |       while(file){ | 
					
						
							|  |  |  |           String fileName = file.name(); | 
					
						
							|  |  |  |           size_t fileSize = file.size(); | 
					
						
							|  |  |  |           DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); | 
					
						
							|  |  |  |           file = root.openNextFile(); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       DBG_OUTPUT_PORT.printf("\n"); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //WIFI INIT
 | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid); | 
					
						
							|  |  |  |   if (String(WiFi.SSID()) != String(ssid)) { | 
					
						
							|  |  |  |     WiFi.mode(WIFI_STA); | 
					
						
							|  |  |  |     WiFi.begin(ssid, password); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   while (WiFi.status() != WL_CONNECTED) { | 
					
						
							|  |  |  |     delay(500); | 
					
						
							|  |  |  |     DBG_OUTPUT_PORT.print("."); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println(""); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("Connected! IP address: "); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println(WiFi.localIP()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   MDNS.begin(host); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print("Open http://"); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.print(host); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println(".local/edit to see the file browser"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //SERVER INIT
 | 
					
						
							|  |  |  |   //list directory
 | 
					
						
							|  |  |  |   server.on("/list", HTTP_GET, handleFileList); | 
					
						
							|  |  |  |   //load editor
 | 
					
						
							|  |  |  |   server.on("/edit", HTTP_GET, []() { | 
					
						
							|  |  |  |     if (!handleFileRead("/edit.htm")) { | 
					
						
							|  |  |  |       server.send(404, "text/plain", "FileNotFound"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   //create file
 | 
					
						
							|  |  |  |   server.on("/edit", HTTP_PUT, handleFileCreate); | 
					
						
							|  |  |  |   //delete file
 | 
					
						
							|  |  |  |   server.on("/edit", HTTP_DELETE, handleFileDelete); | 
					
						
							|  |  |  |   //first callback is called after the request has ended with all parsed arguments
 | 
					
						
							|  |  |  |   //second callback handles file uploads at that location
 | 
					
						
							|  |  |  |   server.on("/edit", HTTP_POST, []() { | 
					
						
							|  |  |  |     server.send(200, "text/plain", ""); | 
					
						
							|  |  |  |   }, handleFileUpload); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //called when the url is not defined here
 | 
					
						
							| 
									
										
										
										
											2018-09-17 14:06:04 -07:00
										 |  |  |   //use it to load content from FILESYSTEM
 | 
					
						
							| 
									
										
										
										
											2018-06-27 09:01:06 +02:00
										 |  |  |   server.onNotFound([]() { | 
					
						
							|  |  |  |     if (!handleFileRead(server.uri())) { | 
					
						
							|  |  |  |       server.send(404, "text/plain", "FileNotFound"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   //get heap status, analog input value and all GPIO statuses in one json call
 | 
					
						
							|  |  |  |   server.on("/all", HTTP_GET, []() { | 
					
						
							|  |  |  |     String json = "{"; | 
					
						
							|  |  |  |     json += "\"heap\":" + String(ESP.getFreeHeap()); | 
					
						
							|  |  |  |     json += ", \"analog\":" + String(analogRead(A0)); | 
					
						
							|  |  |  |     json += ", \"gpio\":" + String((uint32_t)(0)); | 
					
						
							|  |  |  |     json += "}"; | 
					
						
							|  |  |  |     server.send(200, "text/json", json); | 
					
						
							|  |  |  |     json = String(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   server.begin(); | 
					
						
							|  |  |  |   DBG_OUTPUT_PORT.println("HTTP server started"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void loop(void) { | 
					
						
							|  |  |  |   server.handleClient(); | 
					
						
							|  |  |  | } |