From c8a753715792998c4570569a8007385f708a31f2 Mon Sep 17 00:00:00 2001 From: cschwinne Date: Sat, 16 Mar 2019 02:09:37 +0100 Subject: [PATCH] Added support for SPIFFS Fixed ESP32 --- wled00/data/edit.htm | 589 ++++++++++++++++++++++++++++++++++++++- wled00/html_other.h | 12 - wled00/wled00.ino | 28 +- wled00/wled01_eeprom.ino | 10 +- wled00/wled02_xml.ino | 34 ++- wled00/wled04_file.ino | 130 ++------- wled00/wled05_init.ino | 7 +- wled00/wled10_ntp.ino | 23 +- wled00/wled17_mqtt.ino | 4 +- wled00/wled18_server.ino | 66 +++-- wled00/wled19_json.ino | 2 +- 11 files changed, 705 insertions(+), 200 deletions(-) diff --git a/wled00/data/edit.htm b/wled00/data/edit.htm index cfd70baf7..4f0664233 100644 --- a/wled00/data/edit.htm +++ b/wled00/data/edit.htm @@ -1,3 +1,586 @@ -ESP Editor
+ + + + +ESP8266 SPIFFS File Editor + + + + + + + + +
+
+
+
+ + + + \ No newline at end of file diff --git a/wled00/html_other.h b/wled00/html_other.h index 90b661640..720b01168 100644 --- a/wled00/html_other.h +++ b/wled00/html_other.h @@ -49,18 +49,6 @@ const char PAGE_welcome[] PROGMEM = ""; #endif -/* - * SPIFFS editor html - */ -#ifdef USEFS -const char PAGE_edit[] PROGMEM = R"=====(ESP
)====="; -#else -const char PAGE_edit[] PROGMEM = R"=====(SPIFFS disabled)====="; -#endif - - /* * favicon */ diff --git a/wled00/wled00.ino b/wled00/wled00.ino index a79fb35dc..a552c415e 100644 --- a/wled00/wled00.ino +++ b/wled00/wled00.ino @@ -24,15 +24,21 @@ //#define WLED_DISABLE_INFRARED //there is no pin left for this on ESP8266-01 //#define WLED_DISABLE_MOBILE_UI -//to toggle usb serial debug (un)comment following line(s) +#define WLED_DISABLE_FILESYSTEM //SPIFFS is not used by any WLED feature yet +//#define WLED_ENABLE_FS_SERVING //Enable sending html file from SPIFFS before serving progmem version +//#define WLED_ENABLE_FS_EDITOR //enable /edit page for editing SPIFFS content. Will also be disabled with OTA lock + +//to toggle usb serial debug (un)comment the following line //#define WLED_DEBUG + //library inclusions #include #ifdef ARDUINO_ARCH_ESP32 #include #include #include + #include "SPIFFS.h" #else #include #include @@ -46,6 +52,7 @@ #ifndef WLED_DISABLE_OTA #include #endif +#include #include "src/dependencies/time/Time.h" #include "src/dependencies/time/TimeLib.h" #include "src/dependencies/timezone/Timezone.h" @@ -69,6 +76,7 @@ #include "WS2812FX.h" #include "ir_codes.h" + #if IR_PIN < 0 #ifndef WLED_DISABLE_INFRARED #define WLED_DISABLE_INFRARED @@ -89,7 +97,7 @@ //version code in format yymmddb (b = daily build) -#define VERSION 1903131 +#define VERSION 1903161 char versionString[] = "0.8.4-dev"; @@ -98,10 +106,6 @@ char apPass[65] = "wled1234"; char otaPass[33] = "wledota"; -//spiffs FS only useful for debug (only ESP8266) -//#define USEFS - - //Hardware CONFIG (only changeble HERE, not at runtime) //LED strip pin, button pin and IR pin changeable in NpbWrapper.h! @@ -438,9 +442,12 @@ WS2812FX strip = WS2812FX(); #endif //filesystem -#ifdef USEFS - #include ; - File fsUploadFile; +#ifndef WLED_DISABLE_FILESYSTEM + #include + #ifdef ARDUINO_ARCH_ESP32 + #include "SPIFFS.h" + #endif + #include "SPIFFSEditor.h" #endif //gamma 2.4 lookup table used for color correction @@ -465,6 +472,7 @@ const byte gamma8[] = { //function prototypes void serveMessage(AsyncWebServerRequest*,uint16_t,String,String,byte); + //turns all LEDs off and restarts ESP void reset() { @@ -514,7 +522,7 @@ void loop() { userLoop(); yield(); - handleButton(); + handleIO(); handleIR(); handleNetworkTime(); if (!onlyAP) handleAlexa(); diff --git a/wled00/wled01_eeprom.ino b/wled00/wled01_eeprom.ino index 3a8219842..19e9cc0db 100644 --- a/wled00/wled01_eeprom.ino +++ b/wled00/wled01_eeprom.ino @@ -577,13 +577,11 @@ void savePreset(byte index) } -char* loadMacro(byte index) +void loadMacro(byte index, char* m) { index-=1; - char m[65]; - if (index > 15) return m; + if (index > 15) return; readStringFromEEPROM(1024+64*index, m, 64); - return m; } @@ -592,7 +590,9 @@ void applyMacro(byte index) index-=1; if (index > 15) return; String mc="win&"; - mc += loadMacro(index+1); + char m[65]; + loadMacro(index+1, m); + mc += m; mc += "&IN"; //internal, no XML response if (!notifyMacro) mc += "&NN"; String forbidden = "&M="; //dont apply if called by the macro itself to prevent loop diff --git a/wled00/wled02_xml.ino b/wled00/wled02_xml.ino index afe6831f1..603734c90 100644 --- a/wled00/wled02_xml.ino +++ b/wled00/wled02_xml.ino @@ -3,10 +3,17 @@ */ //build XML response to HTTP /win API request -char* XML_response(AsyncWebServerRequest *request, bool includeTheme) +char* XML_response(AsyncWebServerRequest *request, bool includeTheme, char* dest = nullptr) { - char sbuf[1024]; - olen = 0; obuf = sbuf; + if (dest == nullptr) //allocate local buffer if none passed + { + char sbuf[1024]; + obuf = sbuf; + } else { + obuf = dest; + } + + olen = 0; oappend(""); oappendi((nightlightActive && nightlightFade) ? briT : bri); oappend(""); @@ -98,8 +105,7 @@ char* XML_response(AsyncWebServerRequest *request, bool includeTheme) oappend(""); } oappend(""); - if (request != nullptr) request->send(200, "text/xml", sbuf); - return sbuf; + if (request != nullptr) request->send(200, "text/xml", obuf); } //append a numeric setting to string buffer @@ -157,15 +163,15 @@ void sappends(char stype, char* key, char* val) //get values for settings form in javascript -char* getSettingsJS(byte subPage) +void getSettingsJS(byte subPage, char* dest) { //0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec DEBUG_PRINT("settings resp"); DEBUG_PRINTLN(subPage); - char sbuf[2048]; - olen = 0; obuf = sbuf; + obuf = dest; + olen = 0; - if (subPage <1 || subPage >6) return sbuf; + if (subPage <1 || subPage >6) return; if (subPage == 1) { sappends('s',"CS",clientSSID); @@ -328,7 +334,9 @@ char* getSettingsJS(byte subPage) sappend('c',"CF",!useAMPM); sappend('i',"TZ",currentTimezone); sappend('v',"UO",utcOffsetSecs); - sappends('m',"(\"times\")[0]",getTimeString()); + char tm[32]; + getTimeString(tm); + sappends('m',"(\"times\")[0]",tm); sappend('i',"OL",overlayCurrent); sappend('v',"O1",overlayMin); sappend('v',"O2",overlayMax); @@ -344,12 +352,13 @@ char* getSettingsJS(byte subPage) sappend('v',"CH",countdownHour); sappend('v',"CM",countdownMin); sappend('v',"CS",countdownSec); - char k[4]; k[0]= 'M'; for (int i=1;i<17;i++) { + char m[65]; + loadMacro(i, m); sprintf(k+1,"%i",i); - sappends('s',k,loadMacro(i)); + sappends('s',k,m); } sappend('v',"MB",macroBoot); @@ -386,7 +395,6 @@ char* getSettingsJS(byte subPage) oappend(") OK\";"); } oappend("}"); - return sbuf; } diff --git a/wled00/wled04_file.ino b/wled00/wled04_file.ino index 0c9f3d5d8..384e5c2da 100644 --- a/wled00/wled04_file.ino +++ b/wled00/wled04_file.ino @@ -37,129 +37,43 @@ void handleSerial() } } -#ifdef USEFS -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"; +#if !defined WLED_DISABLE_FILESYSTEM && defined WLED_ENABLE_FS_SERVING +//Un-comment any file types you need +String getContentType(AsyncWebServerRequest* request, String filename){ + if(request->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(".css")) return "text/css"; +// else if(filename.endsWith(".js")) return "application/javascript"; + else if(filename.endsWith(".json")) return "application/json"; else if(filename.endsWith(".png")) return "image/png"; - else if(filename.endsWith(".gif")) return "image/gif"; +// 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"; +// 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){ - DEBUG_PRINTLN("handleFileRead: " + path); +bool handleFileRead(AsyncWebServerRequest* request, String path){ + DEBUG_PRINTLN("FileRead: " + path); if(path.endsWith("/")) path += "index.htm"; - String contentType = getContentType(path); + String contentType = getContentType(request, 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(); + if(SPIFFS.exists(pathWithGz)){ + request->send(SPIFFS, pathWithGz, contentType); + return true; + } + if(SPIFFS.exists(path)) { + request->send(SPIFFS, path, contentType); 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; - DEBUG_PRINT("handleFileUpload Name: "); DEBUG_PRINTLN(filename); - fsUploadFile = SPIFFS.open(filename, "w"); - filename = String(); - } else if(upload.status == UPLOAD_FILE_WRITE){ - //DEBUG_PRINT("handleFileUpload Data: "); DEBUG_PRINTLN(upload.currentSize); - if(fsUploadFile) - fsUploadFile.write(upload.buf, upload.currentSize); - } else if(upload.status == UPLOAD_FILE_END){ - if(fsUploadFile) - fsUploadFile.close(); - DEBUG_PRINT("handleFileUpload Size: "); DEBUG_PRINTLN(upload.totalSize); - } -} - -void handleFileDelete(){ - if(server->args() == 0) return server->send(500, "text/plain", "BAD ARGS"); - String path = server->arg(0); - DEBUG_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 handleFileList() { - if(!server->hasArg("dir")) {server->send(500, "text/plain", "BAD ARGS"); return;} - - String path = server->arg("dir"); - DEBUG_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); -} - -void handleFileCreate(){ - if(server->args() == 0) - return server->send(500, "text/plain", "BAD ARGS"); - String path = server->arg(0); - DEBUG_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(); -} - #else -bool handleFileRead(String path){return false;} +bool handleFileRead(AsyncWebServerRequest*, String path){return false;} #endif diff --git a/wled00/wled05_init.ino b/wled00/wled05_init.ino index 015f4284c..75818aa38 100644 --- a/wled00/wled05_init.ino +++ b/wled00/wled05_init.ino @@ -30,8 +30,11 @@ void wledInit() DEBUG_PRINT("LEDs inited. heap usage ~"); DEBUG_PRINTLN(heapPreAlloc - ESP.getFreeHeap()); - #ifdef USEFS - SPIFFS.begin(); + #ifndef WLED_DISABLE_FILESYSTEM + #ifdef ARDUINO_ARCH_ESP32 + SPIFFS.begin(true); + #endif + SPIFFS.begin(); #endif DEBUG_PRINTLN("Load EEPROM"); diff --git a/wled00/wled10_ntp.ino b/wled00/wled10_ntp.ino index 23eb4b6b4..49679119c 100644 --- a/wled00/wled10_ntp.ino +++ b/wled00/wled10_ntp.ino @@ -123,10 +123,9 @@ void updateLocalTime() local = timezones[currentTimezone]->toLocal(tmc); } -char* getTimeString() +void getTimeString(char* out) { updateLocalTime(); - char out[32]; sprintf(out,"%i-%i-%i, %i:%s%i:%s%i",year(local), month(local), day(local), (useAMPM)? hour(local)%12:hour(local), (minute(local)<10)?"0":"",minute(local), @@ -135,26 +134,6 @@ char* getTimeString() { strcat(out,(hour(local) > 11)? " PM":" AM"); } - return out; - /* - String ret = year(local) + "-"; - ret = ret + month(local); - ret = ret + "-"; - ret = ret + day(local); - ret = ret + ", "; - ret += (useAMPM)? hour(local)%12:hour(local); - ret = ret + ":"; - if (minute(local) < 10) ret = ret + "0"; - ret = ret + minute(local); - ret = ret + ":"; - if (second(local) < 10) ret = ret + "0"; - ret = ret + second(local); - if (useAMPM) - { - ret += (hour(local) > 11)? " PM":" AM"; - } - return ret; - */ } void setCountdown() diff --git a/wled00/wled17_mqtt.ino b/wled00/wled17_mqtt.ino index d8be91e48..191e70ff6 100644 --- a/wled00/wled17_mqtt.ino +++ b/wled00/wled17_mqtt.ino @@ -88,9 +88,11 @@ void publishMqtt() strcat(subuf, "/c"); mqtt->publish(subuf, 0, true, s); + char apires[1024]; + XML_response(nullptr, false, apires); strcpy(subuf, mqttDeviceTopic); strcat(subuf, "/v"); - mqtt->publish(subuf, 0, true, XML_response(nullptr, false)); + mqtt->publish(subuf, 0, true, apires); } diff --git a/wled00/wled18_server.ino b/wled00/wled18_server.ino index efccbdde4..2cfc0d5d0 100644 --- a/wled00/wled18_server.ino +++ b/wled00/wled18_server.ino @@ -15,7 +15,7 @@ void initServer() }); server.on("/favicon.ico", HTTP_GET, [](AsyncWebServerRequest *request){ - if(!handleFileRead("/favicon.ico")) + if(!handleFileRead(request, "/favicon.ico")) { request->send_P(200, "image/x-icon", favicon, 156); } @@ -102,14 +102,16 @@ void initServer() //if OTA is allowed if (!otaLock){ + #if !defined WLED_DISABLE_FILESYSTEM && defined WLED_ENABLE_FS_EDITOR + #ifdef ARDUINO_ARCH_ESP32 + server.addHandler(new SPIFFSEditor(SPIFFS));//http_username,http_password)); + #else + server.addHandler(new SPIFFSEditor());//http_username,http_password)); + #endif + #else server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){ - request->send(200, "text/html", PAGE_edit); + serveMessage(request, 501, "Not implemented", "The SPIFFS editor is disabled in this build.", 254); }); - #ifdef USEFS - server.on("/edit", HTTP_PUT, handleFileCreate); - server.on("/edit", HTTP_DELETE, handleFileDelete); - server.on("/edit", HTTP_POST, [](){ server->send(200, "text/plain", ""); }, handleFileUpload); - server.on("/list", HTTP_GET, handleFileList); #endif //init ota page #ifndef WLED_DISABLE_OTA @@ -146,19 +148,16 @@ void initServer() #else server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){ - serveMessage(request, 500, "Not implemented", "OTA updates are unsupported in this build.", 254); + serveMessage(request, 501, "Not implemented", "OTA updates are disabled in this build.", 254); }); #endif } else { server.on("/edit", HTTP_GET, [](AsyncWebServerRequest *request){ - serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); + serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); }); server.on("/update", HTTP_GET, [](AsyncWebServerRequest *request){ - serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); - }); - server.on("/list", HTTP_GET, [](AsyncWebServerRequest *request){ - serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); + serveMessage(request, 500, "Access Denied", "Please unlock OTA in security settings!", 254); }); } @@ -177,12 +176,14 @@ void initServer() request->send(200); return; } - if(!handleSet(request, request->url())){ - #ifndef WLED_DISABLE_ALEXA - if(!espalexa.handleAlexaApiCall(request)) - #endif - request->send(404, "text/plain", "Not Found"); - } + if(handleSet(request, request->url())) return; + #ifndef WLED_DISABLE_ALEXA + if(espalexa.handleAlexaApiCall(request)) return; + #endif + #ifdef WLED_ENABLE_FS_SERVING + if(handleFileRead(request, request->url())) return; + #endif + request->send(404, "text/plain", "Not Found"); }); } @@ -218,6 +219,16 @@ void serveIndex(AsyncWebServerRequest* request) if (uiConfiguration == 0 && request->hasHeader("User-Agent")) serveMobile = checkClientIsMobile(request->getHeader("User-Agent")->value()); else if (uiConfiguration == 2) serveMobile = true; + #ifdef WLED_ENABLE_FS_SERVING + if (serveMobile) + { + if (handleFileRead(request, "/index_mobile.htm")) return; + } else + { + if (handleFileRead(request, "/index.htm")) return; + } + #endif + AsyncWebServerResponse *response = request->beginResponse_P(200, "text/html", (serveMobile) ? (uint8_t*)PAGE_indexM : PAGE_index, (serveMobile) ? PAGE_indexM_L : PAGE_index_L); @@ -235,7 +246,13 @@ void serveIndex(AsyncWebServerRequest* request) String msgProcessor(const String& var) { - if (var == "CSS") return String(obuf); + if (var == "CSS") { + char css[512]; + obuf = css; + olen = 0; + getCSSColors(); + return String(obuf); + } if (var == "MSG") { String messageBody = messageHead; messageBody += ""; @@ -266,8 +283,10 @@ String msgProcessor(const String& var) void serveMessage(AsyncWebServerRequest* request, uint16_t code, String headl, String subl="", byte optionT=255) { - char buf[512]; + #ifndef ARDUINO_ARCH_ESP32 + char buf[256]; obuf = buf; + #endif olen = 0; getCSSColors(); messageHead = headl; @@ -281,9 +300,10 @@ void serveMessage(AsyncWebServerRequest* request, uint16_t code, String headl, S String settingsProcessor(const String& var) { if (var == "CSS") { - char* buf = getSettingsJS(optionType); + char buf[2048]; + getSettingsJS(optionType, buf); getCSSColors(); - return buf; + return String(buf); } if (var == "SCSS") return String(PAGE_settingsCss); return String(); diff --git a/wled00/wled19_json.ino b/wled00/wled19_json.ino index 15bb63152..caa3dd829 100644 --- a/wled00/wled19_json.ino +++ b/wled00/wled19_json.ino @@ -195,7 +195,7 @@ void serializeInfo(JsonObject& root) #ifndef WLED_DISABLE_CRONIXIE os += 0x10; #endif - #ifdef USEFS + #ifndef WLED_DISABLE_FILESYSTEM os += 0x08; #endif #ifndef WLED_DISABLE_HUESYNC