From 21cf58779814716a20d45aaf34f2aac3850e8505 Mon Sep 17 00:00:00 2001 From: Ray Jones Date: Tue, 21 May 2019 22:01:42 +1000 Subject: [PATCH] Can push SPIFFS files now via the firmware upload browser form. However only works as a flat file system for now... --- Arduino/BTCDieselHeater/BTCDieselHeater.ino | 4 +- .../BTCDieselHeater/src/WiFi/BTCWebServer.cpp | 165 ++++++++++++++++-- README.md | 7 +- 3 files changed, 154 insertions(+), 22 deletions(-) diff --git a/Arduino/BTCDieselHeater/BTCDieselHeater.ino b/Arduino/BTCDieselHeater/BTCDieselHeater.ino index 600d9c4..cac3b63 100644 --- a/Arduino/BTCDieselHeater/BTCDieselHeater.ino +++ b/Arduino/BTCDieselHeater/BTCDieselHeater.ino @@ -110,8 +110,8 @@ #if USE_SPIFFS == 1 #include #endif -//#include "esp_system.h" +// SSID & password now stored in NV storage - these are still the default values. //#define AP_SSID "Afterburner" //#define AP_PASSWORD "thereisnospoon" @@ -119,7 +119,7 @@ const int FirmwareRevision = 23; const int FirmwareSubRevision = 0; -const char* FirmwareDate = "12 May 2019"; +const char* FirmwareDate = "21 May 2019"; #ifdef ESP32 diff --git a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp index 78d64ef..c59a4c5 100644 --- a/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp +++ b/Arduino/BTCDieselHeater/src/WiFi/BTCWebServer.cpp @@ -32,6 +32,7 @@ #include "../Utility/Moderator.h" #include #if USE_SPIFFS == 1 +#include #include #endif #include "../Utility/NVStorage.h" @@ -40,6 +41,9 @@ extern void ShowOTAScreen(int percent=0, bool webpdate=false); extern WiFiManager wm; +File fsUploadFile; // a File object to temporarily store the received file +int SPIFFSupload = 0; + WebServer server(80); WebSocketsServer webSocket = WebSocketsServer(81); @@ -56,6 +60,7 @@ String getContentType(String filename) { // convert the file extension to the MI else if (filename.endsWith(".css")) return "text/css"; else if (filename.endsWith(".js")) return "application/javascript"; else if (filename.endsWith(".ico")) return "image/x-icon"; + else if (filename.endsWith(".bin")) return "application/octet-stream"; return "text/plain"; } @@ -127,6 +132,90 @@ void handleBTCNotFound() { } const char* serverIndex = R"=====( + + + + + + + Afterburner firmware update + + +

Afterburner firmware update

+
+
+ +
+

+

+
+ +
+ + )====="; const char* rootIndex = R"=====( @@ -175,7 +264,9 @@ void initWebServer(void) { server.on("/formatspiffs", handleFormat); server.on("/tst", HTTP_GET, []() { - rootRedirect(); + server.sendHeader("Location","/"); // reselect the update page + server.send(303); +// rootRedirect(); }); // Magical code originally shamelessly lifted from Arduino WebUpdate example, then modified @@ -191,7 +282,8 @@ void initWebServer(void) { bUpdateAccessed = true; server.sendHeader("Connection", "close"); server.sendHeader("Cache-Control", "no-cache"); - handleFileRead("/uploadfirmware.html"); + server.send(200, "text/html", serverIndex); + // handleFileRead("/uploadfirmware.html"); }); server.on("/updatenow", HTTP_GET, []() { // handle attempts to just browse the /updatenow path - force redirect to root rootRedirect(); @@ -199,22 +291,46 @@ void initWebServer(void) { // actual guts that manages the new firmware upload server.on("/updatenow", HTTP_POST, []() { // completion functionality - if(Update.hasError()) - server.send(200, "text/plain", "FAIL - Afterburner will reboot shortly"); - else - server.send(200, "OK - Afterburner will reboot shortly"); - delay(1000); - ESP.restart(); // reboot + if(SPIFFSupload) { + if(SPIFFSupload == 1) { + server.send(200, "OK"); + server.sendHeader("Location","/update"); // reselect the update page + server.send(303); + } + else { + server.send(500, "text/plain", "500: couldn't create file"); + } + SPIFFSupload = 0; + } + else { + if(Update.hasError()) + server.send(200, "text/plain", "FAIL - Afterburner will reboot shortly"); + else + server.send(200, "OK - Afterburner will reboot shortly"); + delay(1000); + ESP.restart(); // reboot + } }, []() { if(bUpdateAccessed) { // only allow progression via /update, attempts to directly access /updatenow will fail HTTPUpload& upload = server.upload(); if (upload.status == UPLOAD_FILE_START) { + String filename = upload.filename; DebugPort.setDebugOutput(true); - DebugPort.printf("Update: %s\r\n", upload.filename.c_str()); - if (!Update.begin()) { //start with max available size - Update.printError(DebugPort); + if(filename.endsWith(".bin")) { + DebugPort.printf("Update: %s\r\n", filename.c_str()); + if (!Update.begin()) { //start with max available size + Update.printError(DebugPort); + } + } + else { + if(!filename.startsWith("/")) filename = "/"+filename; + DebugPort.printf("handleFileUpload Name: %s\r\n", filename.c_str()); + fsUploadFile = SPIFFS.open(filename, "w"); // Open the file for writing in SPIFFS (create if it doesn't exist) + SPIFFSupload = fsUploadFile ? 1 : 2; + //filename = String(); } } else if (upload.status == UPLOAD_FILE_WRITE) { + // handle upload segments #if USE_SW_WATCHDOG == 1 feedWatchdog(); // we get stuck here for a while, don't let the watchdog bite! #endif @@ -222,17 +338,30 @@ void initWebServer(void) { char JSON[64]; sprintf(JSON, "{\"progress\":%d}", upload.totalSize); sendWebServerString(JSON); // feedback proper byte count of update -// DebugPort.print(JSON); } DebugPort.print("."); - if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { - Update.printError(DebugPort); + if(fsUploadFile) { + fsUploadFile.write(upload.buf, upload.currentSize); // Write the received bytes to the file + } + else { + if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { + Update.printError(DebugPort); + } } } else if (upload.status == UPLOAD_FILE_END) { - if (Update.end(true)) { //true to set the size to the current progress - DebugPort.printf("Update Success: %u\r\nRebooting...\r\n", upload.totalSize); - } else { - Update.printError(DebugPort); + // handle end of upload + if(SPIFFSupload) { + if(fsUploadFile) { + fsUploadFile.close(); // Close the file again + DebugPort.printf("handleFileUpload Size: %d\r\n", upload.totalSize); + } + } + else { + if (Update.end(true)) { //true to set the size to the current progress + DebugPort.printf("Update Success: %u\r\nRebooting...\r\n", upload.totalSize); + } else { + Update.printError(DebugPort); + } } DebugPort.setDebugOutput(false); bUpdateAccessed = false; diff --git a/README.md b/README.md index 9092beb..122d21f 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,11 @@ Working so far: Request a linear change in Hz according to the deviation from the setpoint * 2 external digital inputs, 2 digital outputs, analogue input * New Mk2 "Red PCB" that properly fits into an off the shelf case (requires machining) +* Software updates over WiFi: + Native OTA via espota.exe or espota.py (AP or STA mode) + Web browser upload new binary to controller (AP or STA mode) + Direct discovery and download of updates from internet server (STA mode) +* Factory default menu option To be implemented @@ -55,8 +60,6 @@ To be implemented * Temperature probe offset or mapping to correct adverse readings. * MQTT pub/sub * "fuel gauge" - Integrate pump frequency, assuming a repeatable dose of fuel per pump cycle... -* Expand hardware compatability with different MCU setups. IE Arduino Due/Mega/Pro ESP8266 & ESP32 -* Documentation * Regular Hot Burn cycle (DPF mode!) * list under construction.....