Add single-click auto-update functionality
This commit is contained in:
parent
d00c216126
commit
023ff29131
6 changed files with 72 additions and 53 deletions
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 1c2d8dcdd0efd846f39b0f24977c982a96f16392
|
||||
Subproject commit 6c40b54273b7f7c7d6c2624d3c2a066435f27756
|
|
@ -4,6 +4,8 @@ TaskHandle_t taskOtaHandle = NULL;
|
|||
bool isOtaUpdating = false;
|
||||
QueueHandle_t otaQueue;
|
||||
|
||||
|
||||
|
||||
void setupOTA()
|
||||
{
|
||||
if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED))
|
||||
|
@ -65,7 +67,7 @@ void onOTAStart()
|
|||
vTaskSuspend(workerTaskHandle);
|
||||
vTaskSuspend(taskScreenRotateTaskHandle);
|
||||
|
||||
vTaskSuspend(ledTaskHandle);
|
||||
// vTaskSuspend(ledTaskHandle);
|
||||
vTaskSuspend(buttonTaskHandle);
|
||||
|
||||
// stopWebServer();
|
||||
|
@ -81,7 +83,18 @@ void handleOTATask(void *parameter)
|
|||
{
|
||||
if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE)
|
||||
{
|
||||
int result = downloadUpdateHandler(msg.updateType);
|
||||
if (msg.updateType == UPDATE_ALL) {
|
||||
int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI);
|
||||
int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE);
|
||||
|
||||
if (resultWebUi == 0 && resultFw == 0) {
|
||||
ESP.restart();
|
||||
} else {
|
||||
queueLedEffect(LED_FLASH_ERROR);
|
||||
vTaskDelay(pdMS_TO_TICKS(3000));
|
||||
ESP.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ArduinoOTA.handle(); // Allow OTA updates to occur
|
||||
|
@ -89,7 +102,7 @@ void handleOTATask(void *parameter)
|
|||
}
|
||||
}
|
||||
|
||||
String getLatestRelease(const String &fileToDownload)
|
||||
ReleaseInfo getLatestRelease(const String &fileToDownload)
|
||||
{
|
||||
String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest";
|
||||
WiFiClientSecure client;
|
||||
|
@ -100,7 +113,7 @@ String getLatestRelease(const String &fileToDownload)
|
|||
|
||||
int httpCode = http.GET();
|
||||
|
||||
String downloadUrl = "";
|
||||
ReleaseInfo info = {"", ""};
|
||||
|
||||
if (httpCode > 0)
|
||||
{
|
||||
|
@ -113,15 +126,26 @@ String getLatestRelease(const String &fileToDownload)
|
|||
|
||||
for (JsonObject asset : assets)
|
||||
{
|
||||
if (asset["name"] == fileToDownload)
|
||||
String assetName = asset["name"].as<String>();
|
||||
if (assetName == fileToDownload)
|
||||
{
|
||||
info.fileUrl = asset["browser_download_url"].as<String>();
|
||||
}
|
||||
else if (assetName == fileToDownload + ".sha256")
|
||||
{
|
||||
info.checksumUrl = asset["browser_download_url"].as<String>();
|
||||
}
|
||||
|
||||
if (!info.fileUrl.isEmpty() && !info.checksumUrl.isEmpty())
|
||||
{
|
||||
downloadUrl = asset["browser_download_url"].as<String>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str());
|
||||
Serial.printf("Latest release URL: %s\r\n", info.fileUrl.c_str());
|
||||
Serial.printf("Checksum URL: %s\r\n", info.checksumUrl.c_str());
|
||||
}
|
||||
return downloadUrl;
|
||||
http.end();
|
||||
return info;
|
||||
}
|
||||
|
||||
int downloadUpdateHandler(char updateType)
|
||||
|
@ -131,7 +155,7 @@ int downloadUpdateHandler(char updateType)
|
|||
HTTPClient http;
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
|
||||
String latestRelease = "";
|
||||
ReleaseInfo latestRelease;
|
||||
|
||||
switch (updateType)
|
||||
{
|
||||
|
@ -143,25 +167,22 @@ int downloadUpdateHandler(char updateType)
|
|||
case UPDATE_WEBUI:
|
||||
{
|
||||
latestRelease = getLatestRelease("littlefs.bin");
|
||||
updateWebUi(latestRelease, U_SPIFFS);
|
||||
return 0;
|
||||
// updateWebUi(latestRelease.fileUrl, U_SPIFFS);
|
||||
// return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (latestRelease.isEmpty())
|
||||
{
|
||||
return 503;
|
||||
}
|
||||
|
||||
// First, download the expected SHA256
|
||||
String expectedSHA256 = downloadSHA256(getFirmwareFilename());
|
||||
String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl);
|
||||
if (expectedSHA256.isEmpty())
|
||||
{
|
||||
Serial.println("Failed to get SHA256 checksum. Aborting update.");
|
||||
return false;
|
||||
}
|
||||
|
||||
http.begin(client, latestRelease);
|
||||
http.begin(client, latestRelease.fileUrl);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
|
@ -215,19 +236,21 @@ int downloadUpdateHandler(char updateType)
|
|||
|
||||
Update.onProgress(onOTAProgress);
|
||||
|
||||
int updateType = (updateType == UPDATE_WEBUI) ? U_SPIFFS : U_FLASH;
|
||||
|
||||
if (Update.begin(contentLength, updateType))
|
||||
{
|
||||
size_t written = Update.writeStream(*stream);
|
||||
onOTAStart();
|
||||
size_t written = Update.write(firmware, contentLength);
|
||||
|
||||
if (written == contentLength)
|
||||
{
|
||||
Serial.println("Written : " + String(written) + " successfully");
|
||||
free(firmware);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
|
||||
if (Update.end())
|
||||
|
@ -236,26 +259,33 @@ int downloadUpdateHandler(char updateType)
|
|||
if (Update.isFinished())
|
||||
{
|
||||
Serial.println("Update successfully completed. Rebooting.");
|
||||
ESP.restart();
|
||||
// ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Update not finished? Something went wrong!");
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Not enough space to begin OTA");
|
||||
free(firmware);
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Invalid content length");
|
||||
return 503;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -265,7 +295,7 @@ int downloadUpdateHandler(char updateType)
|
|||
}
|
||||
http.end();
|
||||
|
||||
return 200;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void updateWebUi(String latestRelease, int command)
|
||||
|
@ -380,9 +410,8 @@ bool getIsOTAUpdating()
|
|||
return isOtaUpdating;
|
||||
}
|
||||
|
||||
String downloadSHA256(const String &filename)
|
||||
String downloadSHA256(const String &sha256Url)
|
||||
{
|
||||
String sha256Url = getLatestRelease(filename + ".sha256");
|
||||
if (sha256Url.isEmpty())
|
||||
{
|
||||
Serial.println("Failed to get SHA256 file URL");
|
||||
|
|
|
@ -15,6 +15,11 @@ typedef struct {
|
|||
|
||||
extern QueueHandle_t otaQueue;
|
||||
|
||||
struct ReleaseInfo {
|
||||
String fileUrl;
|
||||
String checksumUrl;
|
||||
};
|
||||
|
||||
void setupOTA();
|
||||
void onOTAStart();
|
||||
void handleOTATask(void *parameter);
|
||||
|
@ -23,9 +28,10 @@ void onOTAProgress(unsigned int progress, unsigned int total);
|
|||
void onOTAError(ota_error_t error);
|
||||
void onOTAComplete();
|
||||
int downloadUpdateHandler(char updateType);
|
||||
String getLatestRelease(const String& fileToDownload);
|
||||
ReleaseInfo getLatestRelease(const String& fileToDownload);
|
||||
|
||||
bool getIsOTAUpdating();
|
||||
|
||||
void updateWebUi(String latestRelease, int command);
|
||||
String downloadSHA256(const String& filename);
|
||||
String downloadSHA256(const String& filename);
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <GxEPD2.h>
|
||||
#include <GxEPD2_BW.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <Update.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <utils.hpp>
|
||||
|
@ -69,9 +70,9 @@ const int usPerMinute = 60 * usPerSecond;
|
|||
|
||||
extern const char *github_root_ca;
|
||||
|
||||
const PROGMEM char UPDATE_FIRMWARE = 0;
|
||||
const PROGMEM char UPDATE_WEBUI = 1;
|
||||
|
||||
const PROGMEM char UPDATE_FIRMWARE = U_FLASH;
|
||||
const PROGMEM char UPDATE_WEBUI = U_SPIFFS;
|
||||
const PROGMEM char UPDATE_ALL = 99;
|
||||
|
||||
struct ScreenMapping {
|
||||
int value;
|
||||
|
|
|
@ -86,8 +86,7 @@ void setupWebserver()
|
|||
{
|
||||
server.on("/upload/firmware", HTTP_POST, onFirmwareUpdate, asyncFirmwareUpdateHandler);
|
||||
server.on("/upload/webui", HTTP_POST, onFirmwareUpdate, asyncWebuiUpdateHandler);
|
||||
// server.on("/update/webui", HTTP_GET, onUpdateWebUi);
|
||||
// server.on("/update/firmware", HTTP_GET, onUpdateFirmware);
|
||||
server.on("/api/firmware/auto_update", HTTP_GET, onAutoUpdateFirmware);
|
||||
}
|
||||
|
||||
server.on("/api/restart", HTTP_GET, onApiRestart);
|
||||
|
@ -142,29 +141,16 @@ void onFirmwareUpdate(AsyncWebServerRequest *request)
|
|||
request->send(response);
|
||||
}
|
||||
|
||||
void onUpdateWebUi(AsyncWebServerRequest *request)
|
||||
void onAutoUpdateFirmware(AsyncWebServerRequest *request)
|
||||
{
|
||||
UpdateMessage msg = {UPDATE_WEBUI};
|
||||
UpdateMessage msg = {UPDATE_ALL};
|
||||
if (xQueueSend(otaQueue, &msg, 0) == pdTRUE)
|
||||
{
|
||||
request->send(200, "text/plain", "WebUI update triggered");
|
||||
request->send(200, "application/json", "{\"msg\":\"Firmware update triggered\"}");
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(503, "text/plain", "Update already in progress");
|
||||
}
|
||||
}
|
||||
|
||||
void onUpdateFirmware(AsyncWebServerRequest *request)
|
||||
{
|
||||
UpdateMessage msg = {UPDATE_FIRMWARE};
|
||||
if (xQueueSend(otaQueue, &msg, 0) == pdTRUE)
|
||||
{
|
||||
request->send(200, "text/plain", "Firmware update triggered");
|
||||
}
|
||||
else
|
||||
{
|
||||
request->send(503, "text/plain", "Update already in progress");
|
||||
request->send(503,"application/json", "{\"msg\":\"Update already in progress\"}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,10 +26,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request);
|
|||
void onApiStatus(AsyncWebServerRequest *request);
|
||||
void onApiSystemStatus(AsyncWebServerRequest *request);
|
||||
void onApiSetWifiTxPower(AsyncWebServerRequest *request);
|
||||
void onUpdateWebUi(AsyncWebServerRequest *request);
|
||||
void onUpdateFirmware(AsyncWebServerRequest *request);
|
||||
|
||||
|
||||
|
||||
void onApiScreenNext(AsyncWebServerRequest *request);
|
||||
void onApiScreenPrevious(AsyncWebServerRequest *request);
|
||||
|
@ -58,6 +54,7 @@ void onFirmwareUpdate(AsyncWebServerRequest *request);
|
|||
void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
void asyncFileUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final, int command);
|
||||
void asyncWebuiUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
|
||||
void onAutoUpdateFirmware(AsyncWebServerRequest *request);
|
||||
|
||||
void onIndex(AsyncWebServerRequest *request);
|
||||
void onNotFound(AsyncWebServerRequest *request);
|
||||
|
|
Loading…
Reference in a new issue