Skip to content

Commit 023ff29

Browse files
committed
Add single-click auto-update functionality
1 parent d00c216 commit 023ff29

File tree

6 files changed

+72
-53
lines changed

6 files changed

+72
-53
lines changed

data

Submodule data updated from 1c2d8dc to 6c40b54

src/lib/ota.cpp

+53-24
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ TaskHandle_t taskOtaHandle = NULL;
44
bool isOtaUpdating = false;
55
QueueHandle_t otaQueue;
66

7+
8+
79
void setupOTA()
810
{
911
if (preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED))
@@ -65,7 +67,7 @@ void onOTAStart()
6567
vTaskSuspend(workerTaskHandle);
6668
vTaskSuspend(taskScreenRotateTaskHandle);
6769

68-
vTaskSuspend(ledTaskHandle);
70+
// vTaskSuspend(ledTaskHandle);
6971
vTaskSuspend(buttonTaskHandle);
7072

7173
// stopWebServer();
@@ -81,15 +83,26 @@ void handleOTATask(void *parameter)
8183
{
8284
if (xQueueReceive(otaQueue, &msg, 0) == pdTRUE)
8385
{
84-
int result = downloadUpdateHandler(msg.updateType);
86+
if (msg.updateType == UPDATE_ALL) {
87+
int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI);
88+
int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE);
89+
90+
if (resultWebUi == 0 && resultFw == 0) {
91+
ESP.restart();
92+
} else {
93+
queueLedEffect(LED_FLASH_ERROR);
94+
vTaskDelay(pdMS_TO_TICKS(3000));
95+
ESP.restart();
96+
}
97+
}
8598
}
8699

87100
ArduinoOTA.handle(); // Allow OTA updates to occur
88101
vTaskDelay(pdMS_TO_TICKS(2000));
89102
}
90103
}
91104

92-
String getLatestRelease(const String &fileToDownload)
105+
ReleaseInfo getLatestRelease(const String &fileToDownload)
93106
{
94107
String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest";
95108
WiFiClientSecure client;
@@ -100,7 +113,7 @@ String getLatestRelease(const String &fileToDownload)
100113

101114
int httpCode = http.GET();
102115

103-
String downloadUrl = "";
116+
ReleaseInfo info = {"", ""};
104117

105118
if (httpCode > 0)
106119
{
@@ -113,15 +126,26 @@ String getLatestRelease(const String &fileToDownload)
113126

114127
for (JsonObject asset : assets)
115128
{
116-
if (asset["name"] == fileToDownload)
129+
String assetName = asset["name"].as<String>();
130+
if (assetName == fileToDownload)
131+
{
132+
info.fileUrl = asset["browser_download_url"].as<String>();
133+
}
134+
else if (assetName == fileToDownload + ".sha256")
135+
{
136+
info.checksumUrl = asset["browser_download_url"].as<String>();
137+
}
138+
139+
if (!info.fileUrl.isEmpty() && !info.checksumUrl.isEmpty())
117140
{
118-
downloadUrl = asset["browser_download_url"].as<String>();
119141
break;
120142
}
121143
}
122-
Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str());
144+
Serial.printf("Latest release URL: %s\r\n", info.fileUrl.c_str());
145+
Serial.printf("Checksum URL: %s\r\n", info.checksumUrl.c_str());
123146
}
124-
return downloadUrl;
147+
http.end();
148+
return info;
125149
}
126150

127151
int downloadUpdateHandler(char updateType)
@@ -131,7 +155,7 @@ int downloadUpdateHandler(char updateType)
131155
HTTPClient http;
132156
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
133157

134-
String latestRelease = "";
158+
ReleaseInfo latestRelease;
135159

136160
switch (updateType)
137161
{
@@ -143,25 +167,22 @@ int downloadUpdateHandler(char updateType)
143167
case UPDATE_WEBUI:
144168
{
145169
latestRelease = getLatestRelease("littlefs.bin");
146-
updateWebUi(latestRelease, U_SPIFFS);
147-
return 0;
170+
// updateWebUi(latestRelease.fileUrl, U_SPIFFS);
171+
// return 0;
148172
}
149173
break;
150174
}
151175

152-
if (latestRelease.isEmpty())
153-
{
154-
return 503;
155-
}
176+
156177
// First, download the expected SHA256
157-
String expectedSHA256 = downloadSHA256(getFirmwareFilename());
178+
String expectedSHA256 = downloadSHA256(latestRelease.checksumUrl);
158179
if (expectedSHA256.isEmpty())
159180
{
160181
Serial.println("Failed to get SHA256 checksum. Aborting update.");
161182
return false;
162183
}
163184

164-
http.begin(client, latestRelease);
185+
http.begin(client, latestRelease.fileUrl);
165186
http.setUserAgent(USER_AGENT);
166187

167188
int httpCode = http.GET();
@@ -215,19 +236,21 @@ int downloadUpdateHandler(char updateType)
215236

216237
Update.onProgress(onOTAProgress);
217238

218-
int updateType = (updateType == UPDATE_WEBUI) ? U_SPIFFS : U_FLASH;
219-
220239
if (Update.begin(contentLength, updateType))
221240
{
222-
size_t written = Update.writeStream(*stream);
241+
onOTAStart();
242+
size_t written = Update.write(firmware, contentLength);
223243

224244
if (written == contentLength)
225245
{
226246
Serial.println("Written : " + String(written) + " successfully");
247+
free(firmware);
227248
}
228249
else
229250
{
230251
Serial.println("Written only : " + String(written) + "/" + String(contentLength) + ". Retry?");
252+
free(firmware);
253+
return 503;
231254
}
232255

233256
if (Update.end())
@@ -236,26 +259,33 @@ int downloadUpdateHandler(char updateType)
236259
if (Update.isFinished())
237260
{
238261
Serial.println("Update successfully completed. Rebooting.");
239-
ESP.restart();
262+
// ESP.restart();
240263
}
241264
else
242265
{
243266
Serial.println("Update not finished? Something went wrong!");
267+
free(firmware);
268+
return 503;
244269
}
245270
}
246271
else
247272
{
248273
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
274+
free(firmware);
275+
return 503;
249276
}
250277
}
251278
else
252279
{
253280
Serial.println("Not enough space to begin OTA");
281+
free(firmware);
282+
return 503;
254283
}
255284
}
256285
else
257286
{
258287
Serial.println("Invalid content length");
288+
return 503;
259289
}
260290
}
261291
else
@@ -265,7 +295,7 @@ int downloadUpdateHandler(char updateType)
265295
}
266296
http.end();
267297

268-
return 200;
298+
return 0;
269299
}
270300

271301
void updateWebUi(String latestRelease, int command)
@@ -380,9 +410,8 @@ bool getIsOTAUpdating()
380410
return isOtaUpdating;
381411
}
382412

383-
String downloadSHA256(const String &filename)
413+
String downloadSHA256(const String &sha256Url)
384414
{
385-
String sha256Url = getLatestRelease(filename + ".sha256");
386415
if (sha256Url.isEmpty())
387416
{
388417
Serial.println("Failed to get SHA256 file URL");

src/lib/ota.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ typedef struct {
1515

1616
extern QueueHandle_t otaQueue;
1717

18+
struct ReleaseInfo {
19+
String fileUrl;
20+
String checksumUrl;
21+
};
22+
1823
void setupOTA();
1924
void onOTAStart();
2025
void handleOTATask(void *parameter);
@@ -23,9 +28,10 @@ void onOTAProgress(unsigned int progress, unsigned int total);
2328
void onOTAError(ota_error_t error);
2429
void onOTAComplete();
2530
int downloadUpdateHandler(char updateType);
26-
String getLatestRelease(const String& fileToDownload);
31+
ReleaseInfo getLatestRelease(const String& fileToDownload);
2732

2833
bool getIsOTAUpdating();
2934

3035
void updateWebUi(String latestRelease, int command);
31-
String downloadSHA256(const String& filename);
36+
String downloadSHA256(const String& filename);
37+

src/lib/shared.hpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <GxEPD2.h>
1010
#include <GxEPD2_BW.h>
1111
#include <mbedtls/md.h>
12+
#include <Update.h>
1213

1314
#include <mutex>
1415
#include <utils.hpp>
@@ -69,9 +70,9 @@ const int usPerMinute = 60 * usPerSecond;
6970

7071
extern const char *github_root_ca;
7172

72-
const PROGMEM char UPDATE_FIRMWARE = 0;
73-
const PROGMEM char UPDATE_WEBUI = 1;
74-
73+
const PROGMEM char UPDATE_FIRMWARE = U_FLASH;
74+
const PROGMEM char UPDATE_WEBUI = U_SPIFFS;
75+
const PROGMEM char UPDATE_ALL = 99;
7576

7677
struct ScreenMapping {
7778
int value;

src/lib/webserver.cpp

+5-19
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@ void setupWebserver()
8686
{
8787
server.on("/upload/firmware", HTTP_POST, onFirmwareUpdate, asyncFirmwareUpdateHandler);
8888
server.on("/upload/webui", HTTP_POST, onFirmwareUpdate, asyncWebuiUpdateHandler);
89-
// server.on("/update/webui", HTTP_GET, onUpdateWebUi);
90-
// server.on("/update/firmware", HTTP_GET, onUpdateFirmware);
89+
server.on("/api/firmware/auto_update", HTTP_GET, onAutoUpdateFirmware);
9190
}
9291

9392
server.on("/api/restart", HTTP_GET, onApiRestart);
@@ -142,29 +141,16 @@ void onFirmwareUpdate(AsyncWebServerRequest *request)
142141
request->send(response);
143142
}
144143

145-
void onUpdateWebUi(AsyncWebServerRequest *request)
144+
void onAutoUpdateFirmware(AsyncWebServerRequest *request)
146145
{
147-
UpdateMessage msg = {UPDATE_WEBUI};
146+
UpdateMessage msg = {UPDATE_ALL};
148147
if (xQueueSend(otaQueue, &msg, 0) == pdTRUE)
149148
{
150-
request->send(200, "text/plain", "WebUI update triggered");
149+
request->send(200, "application/json", "{\"msg\":\"Firmware update triggered\"}");
151150
}
152151
else
153152
{
154-
request->send(503, "text/plain", "Update already in progress");
155-
}
156-
}
157-
158-
void onUpdateFirmware(AsyncWebServerRequest *request)
159-
{
160-
UpdateMessage msg = {UPDATE_FIRMWARE};
161-
if (xQueueSend(otaQueue, &msg, 0) == pdTRUE)
162-
{
163-
request->send(200, "text/plain", "Firmware update triggered");
164-
}
165-
else
166-
{
167-
request->send(503, "text/plain", "Update already in progress");
153+
request->send(503,"application/json", "{\"msg\":\"Update already in progress\"}");
168154
}
169155
}
170156

src/lib/webserver.hpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request);
2626
void onApiStatus(AsyncWebServerRequest *request);
2727
void onApiSystemStatus(AsyncWebServerRequest *request);
2828
void onApiSetWifiTxPower(AsyncWebServerRequest *request);
29-
void onUpdateWebUi(AsyncWebServerRequest *request);
30-
void onUpdateFirmware(AsyncWebServerRequest *request);
31-
32-
3329

3430
void onApiScreenNext(AsyncWebServerRequest *request);
3531
void onApiScreenPrevious(AsyncWebServerRequest *request);
@@ -58,6 +54,7 @@ void onFirmwareUpdate(AsyncWebServerRequest *request);
5854
void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
5955
void asyncFileUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final, int command);
6056
void asyncWebuiUpdateHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
57+
void onAutoUpdateFirmware(AsyncWebServerRequest *request);
6158

6259
void onIndex(AsyncWebServerRequest *request);
6360
void onNotFound(AsyncWebServerRequest *request);

0 commit comments

Comments
 (0)