From e77de7dbdbe22e62f18af6d4e6830135feb6009c Mon Sep 17 00:00:00 2001 From: Rune Harlyk Date: Fri, 8 Nov 2024 17:20:22 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=20Update=20firmware=20service?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../update/GithubFirmwareManager.svelte | 266 +++++++++--------- .../system/update/UploadFirmware.svelte | 83 +++--- .../ESP32-sveltekit/DownloadFirmwareService.h | 42 --- esp32/lib/ESP32-sveltekit/ESP32SvelteKit.cpp | 24 +- esp32/lib/ESP32-sveltekit/ESP32SvelteKit.h | 13 +- .../ESP32-sveltekit/UploadFirmwareService.h | 46 --- ...vice.cpp => firmware_download_service.cpp} | 11 +- .../firmware_download_service.h | 24 ++ ...ervice.cpp => firmware_upload_service.cpp} | 80 +++--- .../ESP32-sveltekit/firmware_upload_service.h | 32 +++ esp32/src/main.cpp | 2 +- 11 files changed, 302 insertions(+), 321 deletions(-) delete mode 100644 esp32/lib/ESP32-sveltekit/DownloadFirmwareService.h delete mode 100644 esp32/lib/ESP32-sveltekit/UploadFirmwareService.h rename esp32/lib/ESP32-sveltekit/{DownloadFirmwareService.cpp => firmware_download_service.cpp} (89%) create mode 100644 esp32/lib/ESP32-sveltekit/firmware_download_service.h rename esp32/lib/ESP32-sveltekit/{UploadFirmwareService.cpp => firmware_upload_service.cpp} (67%) create mode 100644 esp32/lib/ESP32-sveltekit/firmware_upload_service.h diff --git a/app/src/routes/system/update/GithubFirmwareManager.svelte b/app/src/routes/system/update/GithubFirmwareManager.svelte index 2424afc..5f6c879 100644 --- a/app/src/routes/system/update/GithubFirmwareManager.svelte +++ b/app/src/routes/system/update/GithubFirmwareManager.svelte @@ -1,149 +1,161 @@ - - Github Firmware Manager - {#await getGithubAPI()} - - {:then githubReleases} -
-
- - - - - - - - - - - {#each githubReleases as release} - - - - - - - {/each} - -
ReleaseExperimentalInstall
- {release.name} - {#if release.prerelease} - - {/if} - - {#if compareVersions($features.firmware_version, release.tag_name) != 0} - - {/if} -
-
-
- {:catch error} -
- - Please connect to a network with internet access to perform a firmware update. -
- {/await} + + Github Firmware Manager + {#await getGithubAPI()} + + {:then githubReleases} +
+
+ + + + + + + + + + + {#each githubReleases as release} + + + + + + + {/each} + +
ReleaseExperimentalInstall
+ {release.name} + {#if release.prerelease} + + {/if} + + {#if compareVersions($features.firmware_version, release.tag_name) != 0} + + {/if} +
+
+
+ {:catch error} +
+ + Please connect to a network with internet access to perform a firmware update. +
+ {/await}
diff --git a/app/src/routes/system/update/UploadFirmware.svelte b/app/src/routes/system/update/UploadFirmware.svelte index 5c59b86..8734fca 100644 --- a/app/src/routes/system/update/UploadFirmware.svelte +++ b/app/src/routes/system/update/UploadFirmware.svelte @@ -1,54 +1,53 @@ - - Upload Firmware -
- - Uploading a new firmware (.bin) file will replace the existing firmware. You may upload a - (.md5) file first to verify the uploaded firmware. -
+ + Upload Firmware +
+ + Uploading a new firmware (.bin) file will replace the existing firmware. You may upload + a (.md5) file first to verify the uploaded firmware. +
- +
diff --git a/esp32/lib/ESP32-sveltekit/DownloadFirmwareService.h b/esp32/lib/ESP32-sveltekit/DownloadFirmwareService.h deleted file mode 100644 index e5665ef..0000000 --- a/esp32/lib/ESP32-sveltekit/DownloadFirmwareService.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once - -/** - * ESP32 SvelteKit - * - * A simple, secure and extensible framework for IoT projects for ESP32 platforms - * with responsive Sveltekit front-end built with TailwindCSS and DaisyUI. - * https://github.com/theelims/ESP32-sveltekit - * - * Copyright (C) 2018 - 2023 rjwats - * Copyright (C) 2023 theelims - * - * All Rights Reserved. This software may be modified and distributed under - * the terms of the LGPL v3 license. See the LICENSE file for details. - **/ - -#include - -#include -#include -#include -#include - -#include -#include -#include -// #include - -#define GITHUB_FIRMWARE_PATH "/api/downloadUpdate" -#define EVENT_DOWNLOAD_OTA "otastatus" -#define OTA_TASK_STACK_SIZE 9216 - -class DownloadFirmwareService { - public: - DownloadFirmwareService(PsychicHttpServer *server); - - void begin(); - - private: - PsychicHttpServer *_server; - esp_err_t downloadUpdate(PsychicRequest *request, JsonVariant &json); -}; diff --git a/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.cpp b/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.cpp index 4ea2e14..28db866 100644 --- a/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.cpp +++ b/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.cpp @@ -15,11 +15,8 @@ #include -ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server, unsigned int numberEndpoints) - : _numberEndpoints(numberEndpoints), -#if FT_ENABLED(USE_UPLOAD_FIRMWARE) - _uploadFirmwareService(server), -#endif +ESP32SvelteKit::ESP32SvelteKit(PsychicHttpServer *server) + : #if FT_ENABLED(USE_DOWNLOAD_FIRMWARE) _downloadFirmwareService(server), #endif @@ -43,9 +40,6 @@ void ESP32SvelteKit::begin() { g_taskManager.begin(); _wifiService.begin(); - _server->config.max_uri_handlers = _numberEndpoints; - _server->listen(80); - setupServer(); startServices(); @@ -57,6 +51,10 @@ void ESP32SvelteKit::begin() { } void ESP32SvelteKit::setupServer() { + _server->config.max_uri_handlers = _numberEndpoints; + _server->maxUploadSize = _maxFileUpload; + _server->listen(_port); + // wifi _server->on("/api/wifi/scan", HTTP_GET, _wifiService.handleScan); _server->on("/api/wifi/networks", HTTP_GET, @@ -132,6 +130,16 @@ void ESP32SvelteKit::setupServer() { _server->on("/api/ws/events", socket.getHandler()); _server->on("/api/features", feature_service::getFeatures); +#if FT_ENABLED(USE_UPLOAD_FIRMWARE) + _server->on("/api/firmware", HTTP_POST, _uploadFirmwareService.getHandler()); +#endif + +#if FT_ENABLED(USE_DOWNLOAD_FIRMWARE) + _server->on("/api/firmware/download", HTTP_POST, [this](PsychicRequest *r, JsonVariant &json) { + return _downloadFirmwareService.handleDownloadUpdate(r, json); + }); +#endif + #ifdef EMBED_WWW ESP_LOGV("ESP32SvelteKit", "Registering routes from PROGMEM static resources"); WWWData::registerRoutes([&](const String &uri, const String &contentType, const uint8_t *content, size_t len) { diff --git a/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.h b/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.h index 0478a79..6e77f27 100644 --- a/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.h +++ b/esp32/lib/ESP32-sveltekit/ESP32SvelteKit.h @@ -21,7 +21,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -62,7 +62,7 @@ class ESP32SvelteKit { public: - ESP32SvelteKit(PsychicHttpServer *server, unsigned int numberEndpoints = 115); + ESP32SvelteKit(PsychicHttpServer *server); void begin(); @@ -99,7 +99,6 @@ class ESP32SvelteKit { private: PsychicHttpServer *_server; - unsigned int _numberEndpoints; WiFiService _wifiService; APService _apService; EventSocket _socket; @@ -107,7 +106,7 @@ class ESP32SvelteKit { NTPService _ntpService; #endif #if FT_ENABLED(USE_UPLOAD_FIRMWARE) - UploadFirmwareService _uploadFirmwareService; + FirmwareUploadService _uploadFirmwareService; #endif #if FT_ENABLED(USE_DOWNLOAD_FIRMWARE) DownloadFirmwareService _downloadFirmwareService; @@ -133,6 +132,10 @@ class ESP32SvelteKit { String _appName = APP_NAME; + const u_int16_t _numberEndpoints = 115; + const u_int32_t _maxFileUpload = 2300000; // 2.3 MB + const uint16_t _port = 80; + protected: static void _loopImpl(void *_this) { static_cast(_this)->loop(); } void setupServer(); diff --git a/esp32/lib/ESP32-sveltekit/UploadFirmwareService.h b/esp32/lib/ESP32-sveltekit/UploadFirmwareService.h deleted file mode 100644 index 0705b73..0000000 --- a/esp32/lib/ESP32-sveltekit/UploadFirmwareService.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef UploadFirmwareService_h -#define UploadFirmwareService_h - -/** - * ESP32 SvelteKit - * - * A simple, secure and extensible framework for IoT projects for ESP32 platforms - * with responsive Sveltekit front-end built with TailwindCSS and DaisyUI. - * https://github.com/theelims/ESP32-sveltekit - * - * Copyright (C) 2018 - 2023 rjwats - * Copyright (C) 2023 theelims - * - * All Rights Reserved. This software may be modified and distributed under - * the terms of the LGPL v3 license. See the LICENSE file for details. - **/ - -#include - -#include -#include - -#include -#include - -#define UPLOAD_FIRMWARE_PATH "/api/uploadFirmware" - -enum FileType { ft_none = 0, ft_firmware = 1, ft_md5 = 2 }; - -class UploadFirmwareService { - public: - UploadFirmwareService(PsychicHttpServer *server); - - void begin(); - - private: - PsychicHttpServer *_server; - - esp_err_t handleUpload(PsychicRequest *request, const String &filename, uint64_t index, uint8_t *data, size_t len, - bool final); - esp_err_t uploadComplete(PsychicRequest *request); - esp_err_t handleError(PsychicRequest *request, int code); - esp_err_t handleEarlyDisconnect(); -}; - -#endif // end UploadFirmwareService_h diff --git a/esp32/lib/ESP32-sveltekit/DownloadFirmwareService.cpp b/esp32/lib/ESP32-sveltekit/firmware_download_service.cpp similarity index 89% rename from esp32/lib/ESP32-sveltekit/DownloadFirmwareService.cpp rename to esp32/lib/ESP32-sveltekit/firmware_download_service.cpp index 6c85d7b..495af96 100644 --- a/esp32/lib/ESP32-sveltekit/DownloadFirmwareService.cpp +++ b/esp32/lib/ESP32-sveltekit/firmware_download_service.cpp @@ -11,7 +11,7 @@ * the terms of the LGPL v3 license. See the LICENSE file for details. **/ -#include +#include extern const uint8_t rootca_crt_bundle_start[] asm("_binary_src_certs_x509_crt_bundle_bin_start"); @@ -89,14 +89,7 @@ void updateTask(void *param) { vTaskDelete(NULL); } -DownloadFirmwareService::DownloadFirmwareService(PsychicHttpServer *server) : _server(server) {} - -void DownloadFirmwareService::begin() { - _server->on(GITHUB_FIRMWARE_PATH, HTTP_POST, - [this](PsychicRequest *request, JsonVariant &json) { return downloadUpdate(request, json); }); - - ESP_LOGV("DownloadFirmwareService", "Registered POST endpoint: %s", GITHUB_FIRMWARE_PATH); -} +DownloadFirmwareService::DownloadFirmwareService() {} esp_err_t DownloadFirmwareService::downloadUpdate(PsychicRequest *request, JsonVariant &json) { if (!json.is()) { diff --git a/esp32/lib/ESP32-sveltekit/firmware_download_service.h b/esp32/lib/ESP32-sveltekit/firmware_download_service.h new file mode 100644 index 0000000..3566791 --- /dev/null +++ b/esp32/lib/ESP32-sveltekit/firmware_download_service.h @@ -0,0 +1,24 @@ +#pragma once + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#define EVENT_DOWNLOAD_OTA "otastatus" +#define OTA_TASK_STACK_SIZE 9216 + +class DownloadFirmwareService { + public: + DownloadFirmwareService(); + + esp_err_t downloadUpdate(PsychicRequest *request, JsonVariant &json); + + private: +}; diff --git a/esp32/lib/ESP32-sveltekit/UploadFirmwareService.cpp b/esp32/lib/ESP32-sveltekit/firmware_upload_service.cpp similarity index 67% rename from esp32/lib/ESP32-sveltekit/UploadFirmwareService.cpp rename to esp32/lib/ESP32-sveltekit/firmware_upload_service.cpp index a201735..8e7a790 100644 --- a/esp32/lib/ESP32-sveltekit/UploadFirmwareService.cpp +++ b/esp32/lib/ESP32-sveltekit/firmware_upload_service.cpp @@ -1,45 +1,25 @@ -/** - * ESP32 SvelteKit - * - * A simple, secure and extensible framework for IoT projects for ESP32 platforms - * with responsive Sveltekit front-end built with TailwindCSS and DaisyUI. - * https://github.com/theelims/ESP32-sveltekit - * - * Copyright (C) 2018 - 2023 rjwats - * Copyright (C) 2023 theelims - * - * All Rights Reserved. This software may be modified and distributed under - * the terms of the LGPL v3 license. See the LICENSE file for details. - **/ - -#include -#include +#include #include +#include + +static const char *TAG = "FirmwareUploadService"; using namespace std::placeholders; static char md5[33] = "\0"; +static size_t fsize = 0; static FileType fileType = ft_none; -UploadFirmwareService::UploadFirmwareService(PsychicHttpServer *server) : _server(server) {} +FirmwareUploadService::FirmwareUploadService() {} -void UploadFirmwareService::begin() { - _server->maxUploadSize = 2300000; // 2.3 MB - - PsychicUploadHandler *uploadHandler = new PsychicUploadHandler(); - - uploadHandler->onUpload(std::bind(&UploadFirmwareService::handleUpload, this, _1, _2, _3, _4, _5, _6)); - uploadHandler->onRequest( - std::bind(&UploadFirmwareService::uploadComplete, this, _1)); // gets called after upload has been handled - uploadHandler->onClose( - std::bind(&UploadFirmwareService::handleEarlyDisconnect, this)); // gets called if client disconnects - _server->on(UPLOAD_FIRMWARE_PATH, HTTP_POST, uploadHandler); - - ESP_LOGV("UploadFirmwareService", "Registered POST endpoint: %s", UPLOAD_FIRMWARE_PATH); +void FirmwareUploadService::begin() { + uploadHandler.onUpload(std::bind(&FirmwareUploadService::handleUpload, this, _1, _2, _3, _4, _5, _6)); + uploadHandler.onRequest(std::bind(&FirmwareUploadService::uploadComplete, this, _1)); + uploadHandler.onClose(std::bind(&FirmwareUploadService::handleEarlyDisconnect, this)); } -esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const String &filename, uint64_t index, +esp_err_t FirmwareUploadService::handleUpload(PsychicRequest *request, const String &filename, uint64_t index, uint8_t *data, size_t len, bool final) { // at init if (!index) { @@ -47,7 +27,7 @@ esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const Str std::string fname(filename.c_str()); auto position = fname.find_last_of("."); std::string extension = fname.substr(position + 1); - size_t fsize = request->contentLength(); + fsize = request->contentLength(); fileType = ft_none; if ((extension == "bin") && (fsize > 1000000)) { @@ -61,11 +41,13 @@ esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const Str return ESP_OK; } else { md5[0] = '\0'; - return handleError(request, 406); // Not Acceptable - unsupported file type + return handleError(request, + 406); // Not Acceptable - unsupported file type } if (fileType == ft_firmware) { - // Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip offset 12: esp32:0, S2:2, C3:5 + // Check firmware header, 0xE9 magic offset 0 indicates esp bin, chip + // offset 12: esp32:0, S2:2, C3:5 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 if (len > 12 && (data[0] != 0xE9 || data[12] != 0)) { return handleError(request, 503); // service unavailable @@ -85,12 +67,15 @@ esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const Str #endif // it's firmware - initialize the ArduinoOTA updater if (Update.begin(fsize - sizeof(esp_image_header_t))) { + ESP_LOGI(TAG, "Starting update"); if (strlen(md5) == 32) { Update.setMD5(md5); md5[0] = '\0'; + ESP_LOGI(TAG, "Setting MD5 hash"); } } else { - return handleError(request, 507); // failed to begin, send an error response Insufficient Storage + return handleError(request, 507); // failed to begin, send an error + // response Insufficient Storage } } } @@ -99,10 +84,19 @@ esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const Str if (!request->_tempObject) { if (Update.write(data, len) != len) { handleError(request, 500); + } else { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "{\"status\":\"progress\",\"progress\":%.1f}", + (float)Update.progress() / (float)fsize * 100.f); + socket.emit("otastatus", buffer); + delay(20); } if (final) { if (!Update.end(true)) { handleError(request, 500); + } else { + socket.emit("otastatus", "{\"status\":\"finished\",\"progress\":100}"); + ESP_LOGI(TAG, "Finish writing update"); } } } @@ -110,7 +104,7 @@ esp_err_t UploadFirmwareService::handleUpload(PsychicRequest *request, const Str return ESP_OK; } -esp_err_t UploadFirmwareService::uploadComplete(PsychicRequest *request) { +esp_err_t FirmwareUploadService::uploadComplete(PsychicRequest *request) { // if we completed uploading a md5 file create a JSON response if (fileType == ft_md5) { if (strlen(md5) == 32) { @@ -124,7 +118,7 @@ esp_err_t UploadFirmwareService::uploadComplete(PsychicRequest *request) { // if no error, send the success response if (!request->_tempObject) { - request->reply(200); + ESP_LOGI(TAG, "Finish updating"); system_service::restart(); return ESP_OK; } @@ -139,18 +133,22 @@ esp_err_t UploadFirmwareService::uploadComplete(PsychicRequest *request) { return ESP_OK; } -esp_err_t UploadFirmwareService::handleError(PsychicRequest *request, int code) { +esp_err_t FirmwareUploadService::handleError(PsychicRequest *request, int code) { + char buffer[64]; + snprintf(buffer, sizeof(buffer), "{\"status\":\"error\",\"error\":\"%d\"}", Update.getError()); + socket.emit("otastatus", buffer); // if we have had an error already, do nothing if (request->_tempObject) { return ESP_OK; } - // send the error code to the client and record the error code in the temp object + // send the error code to the client and record the error code in the temp + // object request->_tempObject = new int(code); return request->reply(code); } -esp_err_t UploadFirmwareService::handleEarlyDisconnect() { +esp_err_t FirmwareUploadService::handleEarlyDisconnect() { // if updated has not ended on connection close, abort it if (!Update.end(true)) { Update.printError(Serial); @@ -158,4 +156,4 @@ esp_err_t UploadFirmwareService::handleEarlyDisconnect() { return ESP_OK; } return ESP_OK; -} +} \ No newline at end of file diff --git a/esp32/lib/ESP32-sveltekit/firmware_upload_service.h b/esp32/lib/ESP32-sveltekit/firmware_upload_service.h new file mode 100644 index 0000000..c0622b9 --- /dev/null +++ b/esp32/lib/ESP32-sveltekit/firmware_upload_service.h @@ -0,0 +1,32 @@ +#ifndef FirmwareUploadService_h +#define FirmwareUploadService_h + +#include + +#include +#include + +#include +#include +#include + +enum FileType { ft_none = 0, ft_firmware = 1, ft_md5 = 2 }; + +class FirmwareUploadService { + public: + FirmwareUploadService(); + + void begin(); + + PsychicUploadHandler *getHandler() { return &uploadHandler; } + + private: + PsychicUploadHandler uploadHandler; + esp_err_t handleUpload(PsychicRequest *request, const String &filename, uint64_t index, uint8_t *data, size_t len, + bool final); + esp_err_t uploadComplete(PsychicRequest *request); + esp_err_t handleError(PsychicRequest *request, int code); + esp_err_t handleEarlyDisconnect(); +}; + +#endif // end FirmwareUploadService_h diff --git a/esp32/src/main.cpp b/esp32/src/main.cpp index eb0bbb5..79e6a1f 100644 --- a/esp32/src/main.cpp +++ b/esp32/src/main.cpp @@ -5,7 +5,7 @@ DRAM_ATTR PsychicHttpServer server; -DRAM_ATTR ESP32SvelteKit spot(&server, 130); +DRAM_ATTR ESP32SvelteKit spot(&server); void setup() { Serial.begin(SERIAL_BAUD_RATE);