Allow for SDCard based OTA update

Signed-off-by: Mimoja <git@mimoja.de>
This commit is contained in:
Mimoja
2023-07-05 17:15:57 +02:00
parent 7ea0321548
commit db214c674b
5 changed files with 79 additions and 53 deletions

View File

@@ -8,6 +8,7 @@ void handleGetExtUrl(AsyncWebServerRequest* request);
void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final); void handleLittleFSUpload(AsyncWebServerRequest* request, String filename, size_t index, uint8_t* data, size_t len, bool final);
void handleUpdateOTA(AsyncWebServerRequest* request); void handleUpdateOTA(AsyncWebServerRequest* request);
void firmwareUpdateTask(void* parameter); void firmwareUpdateTask(void* parameter);
void updateFirmware(const char* url, const char* expectedMd5, size_t size); void updateFirmwareFromURL(const char* url, const char* expectedMd5, size_t size);
bool executeUpdate(const char* expectedMd5, size_t size, Stream &stream, size_t stream_size);
void handleRollback(AsyncWebServerRequest* request); void handleRollback(AsyncWebServerRequest* request);
void handleUpdateActions(AsyncWebServerRequest* request); void handleUpdateActions(AsyncWebServerRequest* request);

View File

@@ -32,6 +32,7 @@ class DynStorage {
void end(); void end();
void listFiles(); void listFiles();
size_t freeSpace(); size_t freeSpace();
void checkForUpdate();
#ifdef HAS_SDCARD #ifdef HAS_SDCARD
uint8_t cardType(); uint8_t cardType();
#endif #endif

View File

@@ -45,6 +45,7 @@ void timeTask(void* parameter) {
if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE || config.runStatus != RUNSTATUS_RUN) wsSendSysteminfo(); if (now % 5 == 0 || apInfo.state != AP_STATE_ONLINE || config.runStatus != RUNSTATUS_RUN) wsSendSysteminfo();
if (now % 5 == 0) Serial.printf("Free heap: %.2f KB\n", ESP.getFreeHeap() / 1024.0f); if (now % 5 == 0) Serial.printf("Free heap: %.2f KB\n", ESP.getFreeHeap() / 1024.0f);
if (now % 5 == 0) Storage.checkForUpdate();
if (now % 300 == 6 && config.runStatus != RUNSTATUS_STOP) saveDB("/current/tagDB.json"); if (now % 300 == 6 && config.runStatus != RUNSTATUS_STOP) saveDB("/current/tagDB.json");
if (apInfo.state == AP_STATE_ONLINE) contentRunner(); if (apInfo.state == AP_STATE_ONLINE) contentRunner();

View File

@@ -102,7 +102,7 @@ void handleGetExtUrl(AsyncWebServerRequest* request) {
} }
} else { } else {
request->send(httpResponseCode, "text/plain", "Failed to fetch URL"); request->send(httpResponseCode, "text/plain", "Failed to fetch URL");
wsSerial(http.errorToString(httpResponseCode)); wsLog(http.errorToString(httpResponseCode));
} }
http.end(); http.end();
} else { } else {
@@ -164,20 +164,74 @@ void firmwareUpdateTask(void* parameter) {
FirmwareUpdateParams* params = reinterpret_cast<FirmwareUpdateParams*>(parameter); FirmwareUpdateParams* params = reinterpret_cast<FirmwareUpdateParams*>(parameter);
if (ESP.getMaxAllocHeap() < 22000) { if (ESP.getMaxAllocHeap() < 22000) {
wsSerial("Error: Not enough memory left. Restart the esp32 and try updating again."); wsLog("Error: Not enough memory left. Restart the esp32 and try updating again.");
wsSerial("[reboot]"); wsLog("[reboot]");
} else { } else {
const char* url = params->url.c_str(); const char* url = params->url.c_str();
const char* md5 = params->md5.c_str(); const char* md5 = params->md5.c_str();
size_t size = params->size; size_t size = params->size;
updateFirmware(url, md5, size); updateFirmwareFromURL(url, md5, size);
} }
delete params; delete params;
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void updateFirmware(const char* url, const char* expectedMd5, size_t size) { bool executeUpdate(const char* expectedMd5, size_t size, Stream &stream, size_t stream_size) {
if (!Update.begin(size)) {
wsLog("Failed to begin firmware update");
wsLog(Update.errorString());
return false;
}
if (expectedMd5) {
Serial.println("Setting update md5: " + String(expectedMd5));
if (!Update.setMD5(expectedMd5)) {
Serial.println("Failed to set firmware md5");
wsErr("Failed to set firmware md5");
return false;
}
}
unsigned long progressTimer = millis();
Update.onProgress([&progressTimer](size_t progress, size_t total) {
if (millis() - progressTimer > 500 || progress == total) {
char buffer[50];
sprintf(buffer, "Progress: %u%% %d %d", progress * 100 / total, progress, total);
wsLog(String(buffer));
Serial.println(String(buffer));
progressTimer = millis();
vTaskDelay(1 / portTICK_PERIOD_MS);
}
});
size_t written = Update.writeStream(stream);
if (written != stream_size) {
Serial.println("Error writing firmware:");
wsLog("Error writing firmware:");
Serial.println(Update.errorString());
wsLog(Update.errorString());
return false;
}
if (!Update.end(true)) {
Serial.println("Error updating firmware:");
wsLog("Error updating firmware:");
Serial.println(Update.errorString());
wsLog(Update.errorString());
Update.abort();
return false;
}
wsLog("Firmware update successful");
wsLog("Reboot system now");
wsLog("[reboot]");
vTaskDelay(1000 / portTICK_PERIOD_MS);
return true;
}
void updateFirmwareFromURL(const char* url, const char* expectedMd5, size_t size) {
uint32_t freeStack = uxTaskGetStackHighWaterMark(NULL); uint32_t freeStack = uxTaskGetStackHighWaterMark(NULL);
Serial.printf("Free heap: %d allocatable: %d stack: %d\n", ESP.getFreeHeap(), ESP.getMaxAllocHeap(), freeStack); Serial.printf("Free heap: %d allocatable: %d stack: %d\n", ESP.getFreeHeap(), ESP.getMaxAllocHeap(), freeStack);
@@ -189,8 +243,8 @@ void updateFirmware(const char* url, const char* expectedMd5, size_t size) {
HTTPClient httpClient; HTTPClient httpClient;
wsSerial("start downloading"); wsLog("start downloading");
wsSerial(url); wsLog(url);
httpClient.begin(url); httpClient.begin(url);
httpClient.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS); httpClient.setFollowRedirects(HTTPC_FORCE_FOLLOW_REDIRECTS);
@@ -201,43 +255,10 @@ void updateFirmware(const char* url, const char* expectedMd5, size_t size) {
Serial.printf("Free heap: %d allocatable: %d stack: %d\n", ESP.getFreeHeap(), ESP.getMaxAllocHeap(), freeStack); Serial.printf("Free heap: %d allocatable: %d stack: %d\n", ESP.getFreeHeap(), ESP.getMaxAllocHeap(), freeStack);
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
if (Update.begin(size)) { executeUpdate(expectedMd5, size, httpClient.getStream(), httpClient.getSize());
Update.setMD5(expectedMd5);
unsigned long progressTimer = millis();
Update.onProgress([&progressTimer](size_t progress, size_t total) {
if (millis() - progressTimer > 500 || progress == total) {
char buffer[50];
sprintf(buffer, "Progress: %u%% %d %d", progress * 100 / total, progress, total);
wsSerial(String(buffer));
progressTimer = millis();
vTaskDelay(1 / portTICK_PERIOD_MS);
}
});
size_t written = Update.writeStream(httpClient.getStream());
if (written == httpClient.getSize()) {
if (Update.end(true)) {
wsSerial("Firmware update successful");
wsSerial("Reboot system now");
wsSerial("[reboot]");
vTaskDelay(1000 / portTICK_PERIOD_MS);
// ESP.restart();
} else {
wsSerial("Error updating firmware:");
wsSerial(Update.errorString());
}
} else {
wsSerial("Error writing firmware data:");
wsSerial(Update.errorString());
}
} else {
wsSerial("Failed to begin firmware update");
wsSerial(Update.errorString());
}
} else { } else {
wsSerial("Failed to download firmware file (HTTP code " + String(httpCode) + ")"); wsLog("Failed to download firmware file (HTTP code " + String(httpCode) + ")");
wsSerial(httpClient.errorToString(httpCode)); wsLog(httpClient.errorToString(httpCode));
} }
httpClient.end(); httpClient.end();
@@ -251,26 +272,26 @@ void handleRollback(AsyncWebServerRequest* request) {
bool rollbackSuccess = Update.rollBack(); bool rollbackSuccess = Update.rollBack();
if (rollbackSuccess) { if (rollbackSuccess) {
request->send(200, "Rollback successful"); request->send(200, "Rollback successful");
wsSerial("Rollback successful"); wsLog("Rollback successful");
wsSerial("Reboot system now"); wsLog("Reboot system now");
wsSerial("[reboot]"); wsLog("[reboot]");
vTaskDelay(1000 / portTICK_PERIOD_MS); vTaskDelay(1000 / portTICK_PERIOD_MS);
// ESP.restart(); // ESP.restart();
} else { } else {
wsSerial("Rollback failed"); wsLog("Rollback failed");
request->send(400, "Rollback failed"); request->send(400, "Rollback failed");
} }
} else { } else {
wsSerial("Rollback not allowed"); wsLog("Rollback not allowed");
request->send(400, "Rollback not allowed"); request->send(400, "Rollback not allowed");
} }
} }
void handleUpdateActions(AsyncWebServerRequest* request) { void handleUpdateActions(AsyncWebServerRequest* request) {
wsSerial("Performing cleanup"); wsLog("Performing cleanup");
File file = contentFS->open("/update_actions.json", "r"); File file = contentFS->open("/update_actions.json", "r");
if (!file) { if (!file) {
wsSerial("No update_actions.json present"); wsLog("No update_actions.json present");
request->send(200, "No update actions needed"); request->send(200, "No update actions needed");
return; return;
} }
@@ -279,11 +300,11 @@ void handleUpdateActions(AsyncWebServerRequest* request) {
JsonArray deleteFiles = doc["deletefile"].as<JsonArray>(); JsonArray deleteFiles = doc["deletefile"].as<JsonArray>();
for (const auto& filePath : deleteFiles) { for (const auto& filePath : deleteFiles) {
if (contentFS->remove(filePath.as<const char*>())) { if (contentFS->remove(filePath.as<const char*>())) {
wsSerial("deleted file: " + filePath.as<String>()); wsLog("deleted file: " + filePath.as<String>());
} }
} }
file.close(); file.close();
wsSerial("Cleanup finished"); wsLog("Cleanup finished");
request->send(200, "Clean up finished"); request->send(200, "Clean up finished");
contentFS->remove("/update_actions.json"); contentFS->remove("/update_actions.json");
} }

View File

@@ -18,6 +18,8 @@ static SPIClass* spi;
#endif #endif
#include "LittleFS.h" #include "LittleFS.h"
#include "web.h"
#include "ota.h"
DynStorage::DynStorage() : isInited(0) {} DynStorage::DynStorage() : isInited(0) {}