From f718611bd6c507b861c6ba778f34c51e5a2f738f Mon Sep 17 00:00:00 2001 From: Ray Jones Date: Sun, 30 Jun 2019 10:37:24 +1000 Subject: [PATCH] HTML'd up the inbuilt helper web pages /formatspiffs and 404 handling, adds next steps required etc Added inbuilt /spiffs webpage to show WTF is stored in there, and usage. Added HTML file test before attempting to send. This would hang when SPIFFS gets corrupted causing WD reboot. --- Arduino/BTCDieselHeater/BTCDieselHeater.ino | 46 +---- .../BTCDieselHeater/src/WiFi/BTCWebServer.cpp | 189 ++++++++++++++---- .../BTCDieselHeater/src/WiFi/BTCWebServer.h | 1 + Arduino/BTCDieselHeater/src/WiFi/BTCota.cpp | 2 - Arduino/BTCDieselHeater/src/cfg/BTCConfig.h | 1 - 5 files changed, 156 insertions(+), 83 deletions(-) diff --git a/Arduino/BTCDieselHeater/BTCDieselHeater.ino b/Arduino/BTCDieselHeater/BTCDieselHeater.ino index 1adc31e..5c7eee8 100644 --- a/Arduino/BTCDieselHeater/BTCDieselHeater.ino +++ b/Arduino/BTCDieselHeater/BTCDieselHeater.ino @@ -106,11 +106,8 @@ #include "src/OLED/keypad.h" #include "src/Utility/TempSense.h" #include - -#if USE_SPIFFS == 1 #include #include -#endif // SSID & password now stored in NV storage - these are still the default values. //#define AP_SSID "Afterburner" @@ -119,8 +116,8 @@ #define RX_DATA_TIMOUT 50 const int FirmwareRevision = 23; -const int FirmwareSubRevision = 4; -const char* FirmwareDate = "29 Jun 2019"; +const int FirmwareSubRevision = 5; +const char* FirmwareDate = "30 Jun 2019"; #ifdef ESP32 @@ -264,37 +261,6 @@ void parentKeyHandler(uint8_t event) } -#if USE_SPIFFS == 1 -void listDir(fs::FS &fs, const char * dirname, uint8_t levels) -{ - - DebugPort.printf("Listing directory: %s\r\n", dirname); - - File root = fs.open(dirname); - if (!root) { - DebugPort.println("Failed to open directory"); - return; - } - if (!root.isDirectory()) { - DebugPort.println("Not a directory"); - return; - } - - File file = root.openNextFile(); - while (file) { - if (file.isDirectory()) { - DebugPort.printf(" DIR : %s\r\n", file.name()); - if (levels) { - listDir(fs, file.name(), levels - 1); - } - } else { - DebugPort.printf(" FILE: %s SIZE: %d\r\n", file.name(), file.size()); - } - file = root.openNextFile(); - } -} -#endif - void interruptReboot() { ets_printf("Software watchdog reboot......\r\n"); @@ -303,7 +269,7 @@ void interruptReboot() void setup() { - // ensure proper initialisation of persistent vars after power on + // ensure cyclic mode is disabled after power on if(rtc_get_reset_reason(0) == 1 || bForceInit) { bForceInit = false; bUserON = false; @@ -346,7 +312,6 @@ void setup() { DebugPort.printf("ESP32 IDF Version: %s\r\n", esp_get_idf_version()); -#if USE_SPIFFS == 1 // Initialize SPIFFS if(!SPIFFS.begin(true)){ DebugPort.println("An Error has occurred while mounting SPIFFS"); @@ -354,9 +319,10 @@ void setup() { else { DebugPort.println("Mounted SPIFFS OK"); DebugPort.printf("SPIFFS usage: %d/%d\r\n", SPIFFS.usedBytes(), SPIFFS.totalBytes()); - listDir(SPIFFS, "/", 2); + DebugPort.println("Listing SPIFFS contents:"); + String report; + listDir(SPIFFS, "/", 2, report); } -#endif NVstore.init(); NVstore.load(); diff --git a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp index 67c6b6b..32cc7d8 100644 --- a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp +++ b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp @@ -32,10 +32,8 @@ #include "../Utility/BTC_JSON.h" #include "../Utility/Moderator.h" #include -#if USE_SPIFFS == 1 #include #include -#endif #include "../Utility/NVStorage.h" extern WiFiManager wm; @@ -51,9 +49,9 @@ bool bTxWebData = false; bool bUpdateAccessed = false; // flag used to ensure web update always starts via /update. direct accesses to /updatenow will FAIL long _SuppliedFileSize = 0; -const int led = 13; +void handleBTCNotFound(); +bool checkFile(File &file); -#if USE_SPIFFS == 1 String getContentType(String filename) { // convert the file extension to the MIME type if (filename.endsWith(".html")) return "text/html"; @@ -70,25 +68,35 @@ bool handleFileRead(String path) { // send the right file to the client (if it e String contentType = getContentType(path); // Get the MIME type if (SPIFFS.exists(path)) { // If the file exists File file = SPIFFS.open(path, "r"); // Open it - server.streamFile(file, contentType); // And send it to the client - file.close(); // Then close the file again + if(!checkFile(file)) { // check it is readable + file.close(); // Then close the file again + } + if(!file) { + DebugPort.println("\tFile exists, but could not be read?"); + String SPIFFSfmtpath = "http://" + server.client().localIP().toString() + "/formatspiffs"; + String Updatepath = "http://" + server.client().localIP().toString() + "/update"; + String message = "

Internal Server Error

"; + message += "

Sorry, cannot open file

"; + message += "

" + path + " exists, but cannot be opened?
"; + message += "Recommended remedy is to re-format SPIFFS, then reload the web content."; + message += "

Use:
" + SPIFFSfmtpath + "
to format SPIFFS."; + message += "

Then:
" + Updatepath + "
to upload each file of the web content.
"; + message += "

Latest web content can be downloaded from http://www.mrjones.id.au/afterburner/firmware.html"; + message += "

Please ensure you unzip the web page content, then upload all the contained files."; + server.send(500, "text/html", message); + } + else { + server.streamFile(file, contentType); // And send it to the client + file.close(); // Then close the file again + } return true; } DebugPort.println("\tFile Not Found"); return false; // If the file doesn't exist, return false } -void handleBTCRoot() { - handleFileRead("/index.html"); -} -#else -void handleBTCRoot() { - String s = MAIN_PAGE; //Read HTML contents - server.send(200, "text/html", s); //Send web page -} -#endif - -void handleWMConfig() { +void handleWMConfig() +{ DebugPort.println("WEB: GET /wmconfig"); server.send(200, "text/plain", "Start Config Portal - Retaining credential"); DebugPort.println("Starting web portal for wifi config"); @@ -96,7 +104,8 @@ void handleWMConfig() { wifiEnterConfigPortal(true, false, 3000); } -void handleReset() { +void handleReset() +{ DebugPort.println("WEB: GET /resetwifi"); server.send(200, "text/plain", "Start Config Portal - Resetting Wifi credentials!"); DebugPort.println("diconnecting client and wifi, then rebooting"); @@ -104,29 +113,67 @@ void handleReset() { wifiEnterConfigPortal(true, true, 3000); } -void handleFormat() { +void handleFormat() +{ DebugPort.println("WEB: GET /formatspiffs"); - server.send(200, "text/plain", "Formatting SPIFFS partition!"); + String Updatepath = "http://" + server.client().localIP().toString() + "/update"; + String message = "

SPIFFS partition formatted

"; + message += "

You must now upload the web content.

"; + message += "

Latest web content can be downloaded from http://www.mrjones.id.au/afterburner/firmware.html"; + message += "

Use:
" + Updatepath + "
to then upload each file of the web content.
"; + message += "

Please ensure you unzip the web page content, then upload all the contained files."; + server.send(200, "text/html", message); + DebugPort.println("Formatting SPIFFS partition"); delay(500); SPIFFS.format(); } -void handleBTCNotFound() { - digitalWrite(led, 1); - String message = "File Not Found\n\n"; - message += "URI: "; - message += server.uri(); - message += "\nMethod: "; +void handleSpiffs() +{ + String report; + String message; + listDir(SPIFFS, "/", 2, report, true); + message += "

Current SPIFFS contents:

"; + char usage[128]; + sprintf(usage, "Usage: %d/%d

", SPIFFS.usedBytes(), SPIFFS.totalBytes()); + message += usage; + message += report; + message += "

Add more files
"; + message += "

Home"; + + server.send(200, "text/html", message); +} + +void handleBTCNotFound() +{ + String path = server.uri(); + if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file + String Updatepath = "http://" + server.client().localIP().toString() + "/update"; + + String message = "

404: File Not Found

"; + message += "

URI: " + path + ""; + message += "
Method: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; - message += "\nArguments: "; - message += server.args(); - message += "\n"; + message += "
Arguments: "; for (uint8_t i = 0; i < server.args(); i++) { - message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; + message += " " + server.argName(i) + ": " + server.arg(i) + "
"; } - server.send(404, "text/plain", message); - digitalWrite(led, 0); + message += "


"; + message += "

Please try uploading the file from the web content."; + message += "

Latest web content can be downloaded from http://www.mrjones.id.au/afterburner/firmware.html"; + message += "

Use:
" + Updatepath + "
to upload the web content.
"; + message += "

Please ensure you unzip the web page content, then upload all the contained files."; + + String report; + listDir(SPIFFS, "/", 2, report); + message += "


Current SPIFFS contents:

"; + char usage[128]; + sprintf(usage, "Usage: %d/%d

", SPIFFS.usedBytes(), SPIFFS.totalBytes()); + message += usage; + message += report; + + server.send(404, "text/html", message); } // embedded HTML & Javascript to perform browser based updates of firmware or SPIFFS @@ -254,11 +301,10 @@ void initWebServer(void) { DebugPort.println("MDNS responder started"); } -// server.on("/", handleBTCRoot); - server.on("/wmconfig", handleWMConfig); server.on("/resetwifi", handleReset); server.on("/formatspiffs", handleFormat); + server.on("/spiffs", handleSpiffs); server.on("/tst", HTTP_GET, []() { DebugPort.println("WEB: GET /tst"); @@ -397,20 +443,16 @@ void initWebServer(void) { } }); -#if USE_SPIFFS == 1 // NOTE: this serves the default home page, and favicon.ico server.onNotFound([]() { // If the client requests any URI if (!handleFileRead(server.uri())) { // send it if it exists - DebugPort.printf("WEB: NOT FOUND : %s\r\n", server.uri().c_str()); - server.send(404, "text/plain", "404: Not Found"); // otherwise, respond with a 404 (Not Found) error + handleBTCNotFound(); } }); -#else - server.onNotFound(handleBTCNotFound); -#endif server.begin(); + webSocket.begin(); webSocket.onEvent(webSocketEvent); @@ -488,3 +530,70 @@ void setUploadSize(long val) { _SuppliedFileSize = val; }; + +// Sometimes SPIFFS gets corrupted (WTF?) +// When this happens, you can see the files exist, but you cannot read them +// This routine checks the file is readable. +// Typical failure mechanism is read returns 0, and the WifiClient upload never progresses +// The software watchdog then steps in after 15 seconds of that nonsense +bool checkFile(File &file) +{ + uint8_t buf[128]; + bool bOK = true; + + size_t available = file.available(); + while(available) { + int toRead = (available > 128) ? 128 : available; + int Read = file.read(buf, toRead); + if(Read != toRead) { + bOK = false; + DebugPort.printf("SPIFFS precautionary file check failed for %s\r\n", file.name()); + break; + } + available = file.available(); + } + file.seek(0); + return bOK; +} + +void listDir(fs::FS &fs, const char * dirname, uint8_t levels, String& HTMLreport, bool withHTMLanchors) +{ + char msg[128]; + File root = fs.open(dirname); + if (!root) { + sprintf(msg, "Failed to open directory \"%s\"", dirname); + DebugPort.println(msg); + HTMLreport += msg; HTMLreport += "
"; + return; + } + if (!root.isDirectory()) { + sprintf(msg, "\"%s\" is not a directory", dirname); + DebugPort.println(msg); + HTMLreport += msg; HTMLreport += "
"; + return; + } + + File file = root.openNextFile(); + while (file) { + if (file.isDirectory()) { + sprintf(msg, " DIR : %s", file.name()); + DebugPort.println(msg); + HTMLreport += msg; HTMLreport += "
"; + if (levels) { + listDir(fs, file.name(), levels - 1, HTMLreport); + } + } else { + String fn = file.name(); + if(withHTMLanchors) { + if(fn.endsWith(".html") || fn.endsWith(".htm")) { + String fn2(fn); + fn = "" + fn2 + ""; + } + } + sprintf(msg, " FILE: %s SIZE: %d", fn.c_str(), file.size()); + DebugPort.println(msg); + HTMLreport += msg; HTMLreport += "
"; + } + file = root.openNextFile(); + } +} diff --git a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.h b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.h index 04f3d46..e726559 100644 --- a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.h +++ b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.h @@ -55,3 +55,4 @@ void webturnOff(); bool sendWebServerString(const char* Str); bool isWebServerClientChange(); +void listDir(fs::FS &fs, const char * dirname, uint8_t levels, String& HTMLreport, bool withHTMLanchors=false); diff --git a/Arduino/BTCDieselHeater/src/WiFi/BTCota.cpp b/Arduino/BTCDieselHeater/src/WiFi/BTCota.cpp index 0ebbb4b..002231e 100644 --- a/Arduino/BTCDieselHeater/src/WiFi/BTCota.cpp +++ b/Arduino/BTCDieselHeater/src/WiFi/BTCota.cpp @@ -21,9 +21,7 @@ #include "BTCota.h" #include "../cfg/BTCConfig.h" -#if USE_SPIFFS == 1 #include -#endif #include "../Libraries/esp32FOTA/src/esp32fota.h" // local copy used due to a couple of issues #include "../Utility/helpers.h" diff --git a/Arduino/BTCDieselHeater/src/cfg/BTCConfig.h b/Arduino/BTCDieselHeater/src/cfg/BTCConfig.h index 647514e..348cd6e 100644 --- a/Arduino/BTCDieselHeater/src/cfg/BTCConfig.h +++ b/Arduino/BTCDieselHeater/src/cfg/BTCConfig.h @@ -42,7 +42,6 @@ #define USE_WIFI 1 #define USE_OTA 1 #define USE_WEBSERVER 1 -#define USE_SPIFFS 1 #define USE_PORTAL_TRIGGER_PIN 0