📦 Update firmware service
This commit is contained in:
@@ -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 <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <event_socket.h>
|
||||
#include <PsychicHttp.h>
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include <HTTPUpdate.h>
|
||||
#include <task_manager.h>
|
||||
// #include <SSLCertBundle.h>
|
||||
|
||||
#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);
|
||||
};
|
||||
@@ -15,11 +15,8 @@
|
||||
|
||||
#include <ESP32SvelteKit.h>
|
||||
|
||||
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) {
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
#include <analytics_service.h>
|
||||
#include <BatteryService.h>
|
||||
#include <filesystem.h>
|
||||
#include <DownloadFirmwareService.h>
|
||||
#include <firmware_download_service.h>
|
||||
#include <firmware_upload_service.h>
|
||||
#include <Peripherals.h>
|
||||
#include <ServoController.h>
|
||||
#include <ESPmDNS.h>
|
||||
@@ -34,7 +35,6 @@
|
||||
#include <CameraSettingsService.h>
|
||||
#include <PsychicHttp.h>
|
||||
#include <task_manager.h>
|
||||
#include <UploadFirmwareService.h>
|
||||
#include <WiFi.h>
|
||||
#include <wifi_service.h>
|
||||
#include <ap_service.h>
|
||||
@@ -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<ESP32SvelteKit *>(_this)->loop(); }
|
||||
void setupServer();
|
||||
|
||||
@@ -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 <Arduino.h>
|
||||
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <system_service.h>
|
||||
|
||||
#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
|
||||
+2
-9
@@ -11,7 +11,7 @@
|
||||
* the terms of the LGPL v3 license. See the LICENSE file for details.
|
||||
**/
|
||||
|
||||
#include <DownloadFirmwareService.h>
|
||||
#include <firmware_download_service.h>
|
||||
|
||||
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<JsonObject>()) {
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <event_socket.h>
|
||||
#include <PsychicHttp.h>
|
||||
|
||||
#include <HTTPClient.h>
|
||||
#include <HTTPUpdate.h>
|
||||
#include <task_manager.h>
|
||||
|
||||
#define EVENT_DOWNLOAD_OTA "otastatus"
|
||||
#define OTA_TASK_STACK_SIZE 9216
|
||||
|
||||
class DownloadFirmwareService {
|
||||
public:
|
||||
DownloadFirmwareService();
|
||||
|
||||
esp_err_t downloadUpdate(PsychicRequest *request, JsonVariant &json);
|
||||
|
||||
private:
|
||||
};
|
||||
+39
-41
@@ -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 <UploadFirmwareService.h>
|
||||
#include <esp_ota_ops.h>
|
||||
#include <firmware_upload_service.h>
|
||||
#include <esp_app_format.h>
|
||||
#include <esp_ota_ops.h>
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef FirmwareUploadService_h
|
||||
#define FirmwareUploadService_h
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#include <Update.h>
|
||||
#include <WiFi.h>
|
||||
|
||||
#include <PsychicHttp.h>
|
||||
#include <system_service.h>
|
||||
#include <event_socket.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user