/**************************************************************************************************************************** ESP32_FSWebServer - Example WebServer with SPIFFS backend for esp8266 For ESP32 boards ESP_WiFiManager is a library for the ESP8266/ESP32 platform (https://github.com/esp8266/Arduino) to enable easy configuration and reconfiguration of WiFi credentials using a Captive Portal. Modified from Tzapu https://github.com/tzapu/WiFiManager and from Ken Taylor https://github.com/kentaylor Built by Khoi Hoang https://github.com/khoih-prog/ESP_WiFiManager Licensed under MIT license Example modified from https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino Copyright (c) 2015 Hristo Gochkov. All rights reserved. This file is part of the ESP8266WebServer 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 Version: 1.2.0 Version Modified By Date Comments ------- ----------- ---------- ----------- 1.0.0 K Hoang 07/10/2019 Initial coding 1.0.1 K Hoang 13/12/2019 Fix bug. Add features. Add support for ESP32 1.0.2 K Hoang 19/12/2019 Fix bug thatkeeps ConfigPortal in endless loop if Portal/Router SSID or Password is NULL. 1.0.3 K Hoang 05/01/2020 Option not displaying AvailablePages in Info page. Enhance README.md. Modify examples 1.0.4 K Hoang 07/01/2020 Add RFC952 setHostname feature. 1.0.5 K Hoang 15/01/2020 Add configurable DNS feature. Thanks to @Amorphous of https://community.blynk.cc 1.0.6 K Hoang 03/02/2020 Add support for ArduinoJson version 6.0.0+ ( tested with v6.14.1 ) 1.0.7 K Hoang 13/04/2020 Reduce start time, fix SPIFFS bug in examples, update README.md 1.0.8 K Hoang 10/06/2020 Fix STAstaticIP issue. Restructure code. Add LittleFS support for ESP8266 core 2.7.1+ 1.0.9 K Hoang 29/07/2020 Fix ESP32 STAstaticIP bug. Permit changing from DHCP <-> static IP using Config Portal. Add, enhance examples (fix MDNS for ESP32) 1.0.10 K Hoang 08/08/2020 Add more features to Config Portal. Use random WiFi AP channel to avoid conflict. 1.0.11 K Hoang 17/08/2020 Add CORS feature. Fix bug in softAP, autoConnect, resetSettings. 1.1.0 K Hoang 28/08/2020 Add MultiWiFi feature to autoconnect to best WiFi at runtime 1.1.1 K Hoang 30/08/2020 Add setCORSHeader function to allow flexible CORS. Fix typo and minor improvement. 1.1.2 K Hoang 17/08/2020 Fix bug. Add example. 1.2.0 K Hoang 09/10/2020 Restore cpp code besides Impl.h code to use if linker error. Fix bug. *****************************************************************************************************************************/ /***************************************************************************************************************************** How To Use: 1) Upload the contents of the data folder with MkSPIFFS Tool ("ESP32 Sketch Data Upload" in Tools menu in Arduino IDE) 2) 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" esp32-fs-browser.local/edit; done 3) access the sample web page at http://esp32-fs-browser.local 4) edit the page by going to http://esp32-fs-browser.local/edit *****************************************************************************************************************************/ #if !defined(ESP32) #error This code is intended to run on the ESP32 platform! Please check your Tools->Board setting. #endif // Use from 0 to 4. Higher number, more debugging messages and memory usage. #define _WIFIMGR_LOGLEVEL_ 3 #include #include #include #include // From v1.1.0 #include WiFiMulti wifiMulti; ////// // You only need to format the filesystem once //#define FORMAT_FILESYSTEM true #define FORMAT_FILESYSTEM false #define USE_SPIFFS true #if USE_SPIFFS #include FS* filesystem = &SPIFFS; #define FileFS SPIFFS #define FS_Name "SPIFFS" #else // Use FFat #include FS* filesystem = &FFat; #define FileFS FFat #define FS_Name "FFat" #endif #define DBG_OUTPUT_PORT Serial // SSID and PW for Config Portal String ssid = "ESP_" + String((uint32_t)ESP.getEfuseMac(), HEX); const char* password = "your_password"; // SSID and PW for your Router String Router_SSID; String Router_Pass; // From v1.1.0 #define MIN_AP_PASSWORD_SIZE 8 #define SSID_MAX_LEN 32 //From v1.0.10, WPA2 passwords can be up to 63 characters long. #define PASS_MAX_LEN 64 typedef struct { char wifi_ssid[SSID_MAX_LEN]; char wifi_pw [PASS_MAX_LEN]; } WiFi_Credentials; typedef struct { String wifi_ssid; String wifi_pw; } WiFi_Credentials_String; #define NUM_WIFI_CREDENTIALS 2 typedef struct { WiFi_Credentials WiFi_Creds [NUM_WIFI_CREDENTIALS]; } WM_Config; WM_Config WM_config; #define CONFIG_FILENAME F("/wifi_cred.dat") ////// // Indicates whether ESP has WiFi credentials saved from previous session, or double reset detected bool initialConfig = false; // Use false if you don't like to display Available Pages in Information Page of Config Portal // Comment out or use true to display Available Pages in Information Page of Config Portal // Must be placed before #include #define USE_AVAILABLE_PAGES false // From v1.0.10 to permit disable/enable StaticIP configuration in Config Portal from sketch. Valid only if DHCP is used. // You'll loose the feature of dynamically changing from DHCP to static IP, or vice versa // You have to explicitly specify false to disable the feature. //#define USE_STATIC_IP_CONFIG_IN_CP false // Use false to disable NTP config. Advisable when using Cellphone, Tablet to access Config Portal. // See Issue 23: On Android phone ConfigPortal is unresponsive (https://github.com/khoih-prog/ESP_WiFiManager/issues/23) #define USE_ESP_WIFIMANAGER_NTP false // Use true to enable CloudFlare NTP service. System can hang if you don't have Internet access while accessing CloudFlare // See Issue #21: CloudFlare link in the default portal (https://github.com/khoih-prog/ESP_WiFiManager/issues/21) #define USE_CLOUDFLARE_NTP false // New in v1.0.11 #define USING_CORS_FEATURE true ////// // Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network #if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) // Force DHCP to be true #if defined(USE_DHCP_IP) #undef USE_DHCP_IP #endif #define USE_DHCP_IP true #else // You can select DHCP or Static IP here //#define USE_DHCP_IP true #define USE_DHCP_IP false #endif // Use USE_DHCP_IP == true for dynamic DHCP IP, false to use static IP which you have to change accordingly to your network #if (defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP) // Force DHCP to be true #if defined(USE_DHCP_IP) #undef USE_DHCP_IP #endif #define USE_DHCP_IP true #else // You can select DHCP or Static IP here //#define USE_DHCP_IP true #define USE_DHCP_IP false #endif #if ( USE_DHCP_IP || ( defined(USE_STATIC_IP_CONFIG_IN_CP) && !USE_STATIC_IP_CONFIG_IN_CP ) ) // Use DHCP #warning Using DHCP IP IPAddress stationIP = IPAddress(0, 0, 0, 0); IPAddress gatewayIP = IPAddress(192, 168, 2, 1); IPAddress netMask = IPAddress(255, 255, 255, 0); #else // Use static IP #warning Using static IP #ifdef ESP32 IPAddress stationIP = IPAddress(192, 168, 2, 232); #else IPAddress stationIP = IPAddress(192, 168, 2, 186); #endif IPAddress gatewayIP = IPAddress(192, 168, 2, 1); IPAddress netMask = IPAddress(255, 255, 255, 0); #endif #define USE_CONFIGURABLE_DNS true IPAddress dns1IP = gatewayIP; IPAddress dns2IP = IPAddress(8, 8, 8, 8); #include //https://github.com/khoih-prog/ESP_WiFiManager const char* host = "esp32-fs-browser"; #define HTTP_PORT 80 WebServer server(HTTP_PORT); //holds the current upload File fsUploadFile; // Function Prototypes uint8_t connectMultiWiFi(void); void heartBeatPrint(void) { static int num = 1; if (WiFi.status() == WL_CONNECTED) Serial.print("H"); // H means connected to WiFi else Serial.print("F"); // F means not connected to WiFi if (num == 80) { Serial.println(); num = 1; } else if (num++ % 10 == 0) { Serial.print(" "); } } void check_WiFi(void) { if ( (WiFi.status() != WL_CONNECTED) ) { Serial.println("\nWiFi lost. Call connectMultiWiFi in loop"); connectMultiWiFi(); } } void check_status(void) { static ulong checkstatus_timeout = 0; static ulong checkwifi_timeout = 0; static ulong current_millis; #define WIFICHECK_INTERVAL 1000L #define HEARTBEAT_INTERVAL 10000L current_millis = millis(); // Check WiFi every WIFICHECK_INTERVAL (1) seconds. if ((current_millis > checkwifi_timeout) || (checkwifi_timeout == 0)) { check_WiFi(); checkwifi_timeout = current_millis + WIFICHECK_INTERVAL; } // Print hearbeat every HEARTBEAT_INTERVAL (10) seconds. if ((current_millis > checkstatus_timeout) || (checkstatus_timeout == 0)) { heartBeatPrint(); checkstatus_timeout = current_millis + HEARTBEAT_INTERVAL; } } //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 (filesystem->exists(pathWithGz) || filesystem->exists(path)) { if (filesystem->exists(pathWithGz)) { path += ".gz"; } File file = filesystem->open(path, "r"); 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 = filesystem->open(filename, "w"); filename.clear(); } 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 (!filesystem->exists(path)) { return server.send(404, "text/plain", "FileNotFound"); } filesystem->remove(path); server.send(200, "text/plain", ""); path.clear(); } 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 (filesystem->exists(path)) { return server.send(500, "text/plain", "FILE EXISTS"); } File file = filesystem->open(path, "w"); if (file) { file.close(); } else { return server.send(500, "text/plain", "CREATE FAILED"); } server.send(200, "text/plain", ""); path.clear(); } 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); File root = FileFS.open(path); 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 += "]"; DBG_OUTPUT_PORT.println("handleFileList: " + output); server.send(200, "text/json", output); } void loadConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "r"); LOGERROR(F("LoadWiFiCfgFile ")); if (file) { file.readBytes((char *) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } void saveConfigData(void) { File file = FileFS.open(CONFIG_FILENAME, "w"); LOGERROR(F("SaveWiFiCfgFile ")); if (file) { file.write((uint8_t*) &WM_config, sizeof(WM_config)); file.close(); LOGERROR(F("OK")); } else { LOGERROR(F("failed")); } } uint8_t connectMultiWiFi(void) { #if ESP32 // For ESP32, this better be 0 to shorten the connect time #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 0 #else // For ESP8266, this better be 2200 to enable connect the 1st time #define WIFI_MULTI_1ST_CONNECT_WAITING_MS 2200L #endif #define WIFI_MULTI_CONNECT_WAITING_MS 100L uint8_t status; LOGERROR(F("ConnectMultiWiFi with :")); if ( (Router_SSID != "") && (Router_Pass != "") ) { LOGERROR3(F("* Flash-stored Router_SSID = "), Router_SSID, F(", Router_Pass = "), Router_Pass ); } for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Additional SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); } } LOGERROR(F("Connecting MultiWifi...")); WiFi.mode(WIFI_STA); #if !USE_DHCP_IP #if USE_CONFIGURABLE_DNS // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 WiFi.config(stationIP, gatewayIP, netMask, dns1IP, dns2IP); #else // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. WiFi.config(stationIP, gatewayIP, netMask); #endif #endif int i = 0; status = wifiMulti.run(); delay(WIFI_MULTI_1ST_CONNECT_WAITING_MS); while ( ( i++ < 10 ) && ( status != WL_CONNECTED ) ) { status = wifiMulti.run(); if ( status == WL_CONNECTED ) break; else delay(WIFI_MULTI_CONNECT_WAITING_MS); } if ( status == WL_CONNECTED ) { LOGERROR1(F("WiFi connected after time: "), i); LOGERROR3(F("SSID:"), WiFi.SSID(), F(",RSSI="), WiFi.RSSI()); LOGERROR3(F("Channel:"), WiFi.channel(), F(",IP address:"), WiFi.localIP() ); } else LOGERROR(F("WiFi not connected")); return status; } void setup(void) { DBG_OUTPUT_PORT.begin(115200); while (!DBG_OUTPUT_PORT); DBG_OUTPUT_PORT.print("\nStarting ESP32_FSWebServer with DoubleResetDetect using " + String(FS_Name)); DBG_OUTPUT_PORT.println(" on " + String(ARDUINO_BOARD)); DBG_OUTPUT_PORT.setDebugOutput(false); if (FORMAT_FILESYSTEM) FileFS.format(); // Format SPIFFS if not yet if (!FileFS.begin(true)) { DBG_OUTPUT_PORT.print(FS_Name); DBG_OUTPUT_PORT.println(F(" failed! AutoFormatting.")); } File root = FileFS.open("/"); 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.println(); unsigned long startedAt = millis(); //Local intialization. Once its business is done, there is no need to keep it around // Use this to default DHCP hostname to ESP8266-XXXXXX or ESP32-XXXXXX //ESP_WiFiManager ESP_wifiManager; // Use this to personalize DHCP hostname (RFC952 conformed) ESP_WiFiManager ESP_wifiManager("ESP32-FSWebServer"); //set custom ip for portal ESP_wifiManager.setAPStaticIPConfig(IPAddress(192, 168, 100, 1), IPAddress(192, 168, 100, 1), IPAddress(255, 255, 255, 0)); ESP_wifiManager.setMinimumSignalQuality(-1); // From v1.0.10 only // Set config portal channel, default = 1. Use 0 => random channel from 1-13 ESP_wifiManager.setConfigPortalChannel(0); ////// #if !USE_DHCP_IP #if USE_CONFIGURABLE_DNS // Set static IP, Gateway, Subnetmask, DNS1 and DNS2. New in v1.0.5 ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask, dns1IP, dns2IP); #else // Set static IP, Gateway, Subnetmask, Use auto DNS1 and DNS2. ESP_wifiManager.setSTAStaticIPConfig(stationIP, gatewayIP, netMask); #endif #endif // New from v1.1.1 #if USING_CORS_FEATURE ESP_wifiManager.setCORSHeader("Your Access-Control-Allow-Origin"); #endif // We can't use WiFi.SSID() in ESP32as it's only valid after connected. // SSID and Password stored in ESP32 wifi_ap_record_t and wifi_config_t are also cleared in reboot // Have to create a new function to store in EEPROM/SPIFFS for this purpose Router_SSID = ESP_wifiManager.WiFi_SSID(); Router_Pass = ESP_wifiManager.WiFi_Pass(); //Remove this line if you do not want to see WiFi password printed DBG_OUTPUT_PORT.println("Stored: SSID = " + Router_SSID + ", Pass = " + Router_Pass); // SSID to uppercase ssid.toUpperCase(); // From v1.1.0, Don't permit NULL password if ( (Router_SSID == "") || (Router_Pass == "") ) { DBG_OUTPUT_PORT.println("We haven't got any access point credentials, so get them now"); initialConfig = true; // Starts an access point if (!ESP_wifiManager.startConfigPortal((const char *) ssid.c_str(), password)) DBG_OUTPUT_PORT.println("Not connected to WiFi but continuing anyway."); else DBG_OUTPUT_PORT.println("WiFi connected...yeey :)"); // Stored for later usage, from v1.1.0, but clear first memset(&WM_config, 0, sizeof(WM_config)); for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { String tempSSID = ESP_wifiManager.getSSID(i); String tempPW = ESP_wifiManager.getPW(i); if (strlen(tempSSID.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str()); else strncpy(WM_config.WiFi_Creds[i].wifi_ssid, tempSSID.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_ssid) - 1); if (strlen(tempPW.c_str()) < sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1) strcpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str()); else strncpy(WM_config.WiFi_Creds[i].wifi_pw, tempPW.c_str(), sizeof(WM_config.WiFi_Creds[i].wifi_pw) - 1); // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); } } saveConfigData(); } else { wifiMulti.addAP(Router_SSID.c_str(), Router_Pass.c_str()); } startedAt = millis(); if (!initialConfig) { // Load stored data, the addAP ready for MultiWiFi reconnection loadConfigData(); for (uint8_t i = 0; i < NUM_WIFI_CREDENTIALS; i++) { // Don't permit NULL SSID and password len < MIN_AP_PASSWORD_SIZE (8) if ( (String(WM_config.WiFi_Creds[i].wifi_ssid) != "") && (strlen(WM_config.WiFi_Creds[i].wifi_pw) >= MIN_AP_PASSWORD_SIZE) ) { LOGERROR3(F("* Add SSID = "), WM_config.WiFi_Creds[i].wifi_ssid, F(", PW = "), WM_config.WiFi_Creds[i].wifi_pw ); wifiMulti.addAP(WM_config.WiFi_Creds[i].wifi_ssid, WM_config.WiFi_Creds[i].wifi_pw); } } if ( WiFi.status() != WL_CONNECTED ) { DBG_OUTPUT_PORT.println("ConnectMultiWiFi in setup"); connectMultiWiFi(); } } DBG_OUTPUT_PORT.print("After waiting "); DBG_OUTPUT_PORT.print((float) (millis() - startedAt) / 1000L); DBG_OUTPUT_PORT.print(" secs more in setup(), connection result is "); if (WiFi.status() == WL_CONNECTED) { DBG_OUTPUT_PORT.print("connected. Local IP: "); DBG_OUTPUT_PORT.println(WiFi.localIP()); } else DBG_OUTPUT_PORT.println(ESP_wifiManager.getStatus(WiFi.status())); //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)); json += ", \"gpio\":" + String((uint32_t)(0)); json += "}"; server.send(200, "text/json", json); json = String(); }); server.begin(); DBG_OUTPUT_PORT.print("HTTP server started @ "); DBG_OUTPUT_PORT.println(WiFi.localIP()); MDNS.begin(host); // Add service to MDNS-SD MDNS.addService("http", "tcp", HTTP_PORT); DBG_OUTPUT_PORT.print("Open http://"); DBG_OUTPUT_PORT.print(host); DBG_OUTPUT_PORT.println(".local/edit to see the file browser"); } void loop(void) { server.handleClient(); // this is just for checking if we are alive and connected to WiFi check_status(); }