/* FSWebServer - Example WebServer with SPIFFS backend for esp8266 Copyright (c) 2015 Hristo Gochkov. All rights reserved. This file is part of the ESP8266/ESP32 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 ("ESP8266 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" esp8266fs.local/edit; done access the sample web page at http://esp8266fs.local edit the page by going to http://esp8266fs.local/edit */ /* * Uploading html, css, javascript, etc. * Use curl to upload the files from the SPIFFS data directory. * cd data/ * curl -X POST -F "data=@index.htm" http:///edit >/dev/null * curl -X POST -F "data=@graphs.js.gz" http:///edit >/dev/null * curl -X POST -F "data=@favicon.ico" http:///edit >/dev/null * curl -X POST -F "data=@edit.htm.gz" http:///edit >/dev/null */ #ifdef ESP8266 #include #include #include #include #include ESP8266WebServer server(80); #else #include #include #include #include #include WebServer server(80); #endif #define DBG_OUTPUT_PORT Serial const char* ssid = "wifi-ssid"; const char* password = "wifi-password"; const char* host = "esp8266fs"; //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 handleFileRead(String path){ DBG_OUTPUT_PORT.println("handleFileRead: " + path); if(path.endsWith("/")) path += "index.htm"; String contentType = getContentType(path); String pathWithGz = path + ".gz"; if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ if(SPIFFS.exists(pathWithGz)) path += ".gz"; File file = SPIFFS.open(path, "r"); size_t sent = 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); fsUploadFile = SPIFFS.open(filename, "w"); 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(!SPIFFS.exists(path)) return server.send(404, "text/plain", "FileNotFound"); SPIFFS.remove(path); 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(SPIFFS.exists(path)) return server.send(500, "text/plain", "FILE EXISTS"); File file = SPIFFS.open(path, "w"); if(file) file.close(); else return server.send(500, "text/plain", "CREATE FAILED"); server.send(200, "text/plain", ""); path = String(); } void returnFail(String msg) { server.send(500, "text/plain", msg + "\r\n"); } #ifdef ESP8266 void handleFileList() { if(!server.hasArg("dir")) { returnFail("BAD ARGS"); return; } String path = server.arg("dir"); DBG_OUTPUT_PORT.println("handleFileList: " + path); Dir dir = SPIFFS.openDir(path); path = String(); String output = "["; while(dir.next()){ File entry = dir.openFile("r"); if (output != "[") output += ','; bool isDir = false; output += "{\"type\":\""; output += (isDir)?"dir":"file"; output += "\",\"name\":\""; output += String(entry.name()).substring(1); output += "\"}"; entry.close(); } output += "]"; server.send(200, "text/json", output); } #else void handleFileList() { if(!server.hasArg("dir")) { returnFail("BAD ARGS"); return; } String path = server.arg("dir"); if(path != "/" && !SPIFFS.exists((char *)path.c_str())) { returnFail("BAD PATH"); return; } File dir = SPIFFS.open((char *)path.c_str()); path = String(); if(!dir.isDirectory()){ dir.close(); returnFail("NOT DIR"); return; } dir.rewindDirectory(); String output = "["; for (int cnt = 0; true; ++cnt) { File entry = dir.openNextFile(); if (!entry) break; if (cnt > 0) output += ','; output += "{\"type\":\""; output += (entry.isDirectory()) ? "dir" : "file"; output += "\",\"name\":\""; // Ignore '/' prefix output += entry.name()+1; output += "\""; output += "}"; entry.close(); } output += "]"; server.send(200, "text/json", output); dir.close(); } void listDir(fs::FS &fs, const char * dirname, uint8_t levels) { DBG_OUTPUT_PORT.printf("Listing directory: %s\n", dirname); File root = fs.open(dirname); if (!root) { DBG_OUTPUT_PORT.println("Failed to open directory"); return; } if (!root.isDirectory()) { DBG_OUTPUT_PORT.println("Not a directory"); return; } File file = root.openNextFile(); while (file) { if (file.isDirectory()) { DBG_OUTPUT_PORT.print(" DIR : "); DBG_OUTPUT_PORT.println(file.name()); if (levels) { listDir(fs, file.name(), levels - 1); } } else { DBG_OUTPUT_PORT.print(" FILE: "); DBG_OUTPUT_PORT.print(file.name()); DBG_OUTPUT_PORT.print(" SIZE: "); DBG_OUTPUT_PORT.println(file.size()); } file = root.openNextFile(); } } #endif void setup(void){ DBG_OUTPUT_PORT.begin(115200); DBG_OUTPUT_PORT.print("\n"); DBG_OUTPUT_PORT.setDebugOutput(true); SPIFFS.begin(); { #ifdef ESP8266 Dir dir = SPIFFS.openDir("/"); while (dir.next()) { String fileName = dir.fileName(); size_t fileSize = dir.fileSize(); DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str()); } #else listDir(SPIFFS, "/", 0); #endif DBG_OUTPUT_PORT.printf("\n"); } //WIFI INIT DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid); if (String(WiFi.SSID()) != String(ssid)) { 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 //use it to load content from SPIFFS 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)); #ifdef ESP8266 json += ", \"gpio\":"+String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16))); #endif json += "}"; server.send(200, "text/json", json); json = String(); }); server.begin(); DBG_OUTPUT_PORT.println("HTTP server started"); } void loop(void){ server.handleClient(); }