Make zap notify more lightning like, verify SSL certificates, remove price fetch code
This commit is contained in:
parent
5425ea7fbf
commit
1f2110fc5a
21 changed files with 494 additions and 190 deletions
|
@ -7,49 +7,42 @@ uint blockMedianFee = 1;
|
|||
bool blockNotifyInit = false;
|
||||
unsigned long int lastBlockUpdate;
|
||||
|
||||
// const char *mempoolWsCert = R"(-----BEGIN CERTIFICATE-----
|
||||
// MIIHfTCCBmWgAwIBAgIRANFX3mhqRYDt1NFuENoSyaAwDQYJKoZIhvcNAQELBQAw
|
||||
// gZUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
// BgNVBAcTB1NhbGZvcmQxGDAWBgNVBAoTD1NlY3RpZ28gTGltaXRlZDE9MDsGA1UE
|
||||
// AxM0U2VjdGlnbyBSU0EgT3JnYW5pemF0aW9uIFZhbGlkYXRpb24gU2VjdXJlIFNl
|
||||
// cnZlciBDQTAeFw0yMzA3MjQwMDAwMDBaFw0yNDA4MjIyMzU5NTlaMFcxCzAJBgNV
|
||||
// BAYTAkpQMQ4wDAYDVQQIEwVUb2t5bzEgMB4GA1UEChMXTUVNUE9PTCBTUEFDRSBD
|
||||
// Ty4sIExURC4xFjAUBgNVBAMTDW1lbXBvb2wuc3BhY2UwggEiMA0GCSqGSIb3DQEB
|
||||
// AQUAA4IBDwAwggEKAoIBAQCqmiPRWgo58d25R0biQjAksXMq5ciH7z7ZQo2w2AbB
|
||||
// rHxpnlIry74b9S4wRY5UJeYmd6ZwA76NdSioDvxTJc29bLplY+Ftmfc4ET0zYb2k
|
||||
// Fi86z7GOWb6Ezor/qez9uMM9cxd021Bvcs0/2OrL6Sgp66u9keDZv9NyvFPpXfuR
|
||||
// tdV2r4HF57VJqZn105PN4k80kNWgDbae8aw+BuUNvQYKEe71yfB7Bh6zSh9pCSfM
|
||||
// I6pIJdQzoada2uY1dQMoJeIq8qKNKqAPKGsH5McemUT5ZIKU/tjk3nfX0pz/sQa4
|
||||
// CN7tLH6UeUlctei92GFd6Xtn7RbKLhDUbc4Sq02Cc9iXAgMBAAGjggQDMIID/zAf
|
||||
// BgNVHSMEGDAWgBQX2dYlJ2f5McJJQ9kwNkSMbKlP6zAdBgNVHQ4EFgQUXkxoddJ6
|
||||
// rKobsbmDdtuCK1ywXuIwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYD
|
||||
// VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEoGA1UdIARDMEEwNQYMKwYBBAGy
|
||||
// MQECAQMEMCUwIwYIKwYBBQUHAgEWF2h0dHBzOi8vc2VjdGlnby5jb20vQ1BTMAgG
|
||||
// BmeBDAECAjBaBgNVHR8EUzBRME+gTaBLhklodHRwOi8vY3JsLnNlY3RpZ28uY29t
|
||||
// L1NlY3RpZ29SU0FPcmdhbml6YXRpb25WYWxpZGF0aW9uU2VjdXJlU2VydmVyQ0Eu
|
||||
// Y3JsMIGKBggrBgEFBQcBAQR+MHwwVQYIKwYBBQUHMAKGSWh0dHA6Ly9jcnQuc2Vj
|
||||
// dGlnby5jb20vU2VjdGlnb1JTQU9yZ2FuaXphdGlvblZhbGlkYXRpb25TZWN1cmVT
|
||||
// ZXJ2ZXJDQS5jcnQwIwYIKwYBBQUHMAGGF2h0dHA6Ly9vY3NwLnNlY3RpZ28uY29t
|
||||
// MIIBgAYKKwYBBAHWeQIEAgSCAXAEggFsAWoAdwB2/4g/Crb7lVHCYcz1h7o0tKTN
|
||||
// uyncaEIKn+ZnTFo6dAAAAYmc9m/gAAAEAwBIMEYCIQD8XOozx411S/bnZambGjTB
|
||||
// yTcr2fCmggUfQLSmqksD5gIhAIjiEMg0o1VSuQW31gWzfzL6idCkIZeSKN104cdp
|
||||
// xa4SAHcA2ra/az+1tiKfm8K7XGvocJFxbLtRhIU0vaQ9MEjX+6sAAAGJnPZwPwAA
|
||||
// BAMASDBGAiEA2sPTZTzvxewzQ8vk36+BWAKuJS7AvJ5W3clvfwCa8OUCIQC74ekT
|
||||
// Ged2fqQE4sVy74aS6HRA2ihC9VLtNrASJx1YjQB2AO7N0GTV2xrOxVy3nbTNE6Iy
|
||||
// h0Z8vOzew1FIWUZxH7WbAAABiZz2cA8AAAQDAEcwRQIgEklH7wYCFuuJIFUHX5PY
|
||||
// /vZ3bDoxOp+061PT3caa+rICIQC0abgfGlBKiHxp47JZxnW3wcVqWdiYX4ViLm9H
|
||||
// xfx4ljCBxgYDVR0RBIG+MIG7gg1tZW1wb29sLnNwYWNlghMqLmZtdC5tZW1wb29s
|
||||
// LnNwYWNlghMqLmZyYS5tZW1wb29sLnNwYWNlgg8qLm1lbXBvb2wuc3BhY2WCEyou
|
||||
// dGs3Lm1lbXBvb2wuc3BhY2WCEyoudmExLm1lbXBvb2wuc3BhY2WCDGJpc3EubWFy
|
||||
// a2V0c4IKYmlzcS5uaW5qYYIObGlxdWlkLm5ldHdvcmuCDGxpcXVpZC5wbGFjZYIN
|
||||
// bWVtcG9vbC5uaW5qYTANBgkqhkiG9w0BAQsFAAOCAQEAFvOSRnlHDfq9C8acjZEG
|
||||
// 5XIqjNYigyWyjOvx83of6Z3PBKkAZB5D/UHBPp+jBDJiEb/QXC7Z7Y7kpuvnoVib
|
||||
// b4jDc0RjGEsxL+3F7cSw26m3wILJhhHooGZRmFY4GOAeCZtYCOTzJsiZvFpDoQjU
|
||||
// hTBxtaps05z0Ly9/eYvkXnjnBNROZJVR+KYHlq4TIoGNc4q4KvpfHv2I/vhS2M1e
|
||||
// bECNNPEyRxHGKdXXO3huocE7aVKpy+JDR6cWwDu6hpdc1j/SCDqdTDFQ7McHOrqA
|
||||
// fpPh4FcfePMh7Mqxtg2pSs5pXPtiP0ZjLgxd7HbAXct8Y+/jGk+k3sx3SeYXVimr
|
||||
// ew==
|
||||
// -----END CERTIFICATE-----)";
|
||||
const char *mempoolWsCert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
void setupBlockNotify()
|
||||
{
|
||||
|
@ -103,13 +96,18 @@ void setupBlockNotify()
|
|||
|
||||
esp_websocket_client_config_t config = {
|
||||
// .uri = "wss://mempool.space/api/v1/ws",
|
||||
// .task_stack = (6*1024),
|
||||
// .cert_pem = mempoolWsCert,
|
||||
.user_agent = USER_AGENT,
|
||||
.task_stack = (6*1024),
|
||||
.user_agent = USER_AGENT
|
||||
};
|
||||
|
||||
if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) {
|
||||
config.cert_pem = mempoolWsCert;
|
||||
}
|
||||
|
||||
config.uri = mempoolUri.c_str();
|
||||
|
||||
Serial.printf("Connecting to %s\r\n", preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE));
|
||||
|
||||
blockNotifyClient = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY,
|
||||
onWebsocketBlockEvent, blockNotifyClient);
|
||||
|
@ -302,7 +300,10 @@ int getBlockFetch()
|
|||
{
|
||||
try {
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure();
|
||||
|
||||
if (preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE)) {
|
||||
client.setCACert(mempoolWsCert);
|
||||
}
|
||||
|
||||
String mempoolInstance =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
|
|
@ -753,4 +753,16 @@ bool isActiveCurrency(std::string ¤cy)
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* getFirmwareFilename() {
|
||||
if (HW_REV == "REV_B_EPD_2_13") {
|
||||
return "btclock_rev_b_213epd_firmware.bin";
|
||||
} else if (HW_REV == "REV_A_EPD_2_13") {
|
||||
return "lolin_s3_mini_213epd_firmware.bin";
|
||||
} else if (HW_REV == "REV_A_EPD_2_9") {
|
||||
return "lolin_s3_mini_29epd_firmware.bin";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -82,4 +82,5 @@ void addScreenMapping(int value, const char* name);
|
|||
// void addScreenMapping(int value, const std::string& name);
|
||||
|
||||
int findScreenIndexByValue(int value);
|
||||
String replaceAmbiguousChars(String input);
|
||||
String replaceAmbiguousChars(String input);
|
||||
const char* getFirmwareFilename();
|
|
@ -298,9 +298,14 @@ void ledTask(void *parameter)
|
|||
}
|
||||
}
|
||||
#endif
|
||||
blinkDelayColor(250, 3, 142, 48, 235);
|
||||
// blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235),
|
||||
// pixels.Color(169, 21, 255));
|
||||
for (int flash = 0; flash < random(7, 10); flash++)
|
||||
{
|
||||
lightningStrike();
|
||||
delay(random(50, 150));
|
||||
}
|
||||
// blinkDelayColor(250, 3, 142, 48, 235);
|
||||
// blinkDelayTwoColor(250, 3, pixels.Color(142, 48, 235),
|
||||
// pixels.Color(169, 21, 255));
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
if (preferences.getBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE))
|
||||
{
|
||||
|
@ -668,4 +673,29 @@ void ledTheaterChaseRainbow(int wait)
|
|||
}
|
||||
}
|
||||
|
||||
void lightningStrike()
|
||||
{
|
||||
uint32_t PURPLE = pixels.Color(128, 0, 128);
|
||||
uint32_t YELLOW = pixels.Color(255, 226, 41);
|
||||
|
||||
// Randomly choose which LEDs to light up
|
||||
for (int i = 0; i < pixels.numPixels(); i++)
|
||||
{
|
||||
if (random(2) == 0)
|
||||
{ // 50% chance for each LED
|
||||
pixels.setPixelColor(i, YELLOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixels.setPixelColor(i, PURPLE);
|
||||
}
|
||||
}
|
||||
pixels.show();
|
||||
|
||||
delay(random(10, 50)); // Flash duration
|
||||
|
||||
// Return to purple background
|
||||
// setAllPixels(PURPLE);
|
||||
}
|
||||
|
||||
Adafruit_NeoPixel getPixels() { return pixels; }
|
||||
|
|
|
@ -61,6 +61,7 @@ void ledRainbow(int wait);
|
|||
void ledTheaterChaseRainbow(int wait);
|
||||
void ledTheaterChase(uint32_t color, int wait);
|
||||
Adafruit_NeoPixel getPixels();
|
||||
void lightningStrike();
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
void frontlightFlash(int flDelayTime);
|
||||
|
|
|
@ -70,62 +70,62 @@ void handleOTATask(void *parameter) {
|
|||
}
|
||||
}
|
||||
|
||||
void downloadUpdate() {
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure();
|
||||
HTTPClient http;
|
||||
http.setUserAgent(USER_AGENT);
|
||||
// void downloadUpdate() {
|
||||
// WiFiClientSecure client;
|
||||
// client.setInsecure();
|
||||
// HTTPClient http;
|
||||
// http.setUserAgent(USER_AGENT);
|
||||
|
||||
// Send HTTP request to CoinGecko API
|
||||
http.useHTTP10(true);
|
||||
// // Send HTTP request to CoinGecko API
|
||||
// http.useHTTP10(true);
|
||||
|
||||
http.begin(client,
|
||||
"https://api.github.com/repos/btclock/btclock_v3/releases/latest");
|
||||
int httpCode = http.GET();
|
||||
// http.begin(client,
|
||||
// "https://api.github.com/repos/btclock/btclock_v3/releases/latest");
|
||||
// int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200) {
|
||||
// WiFiClient * stream = http->getStreamPtr();
|
||||
// if (httpCode == 200) {
|
||||
// // WiFiClient * stream = http->getStreamPtr();
|
||||
|
||||
JsonDocument filter;
|
||||
// JsonDocument filter;
|
||||
|
||||
JsonObject filter_assets_0 = filter["assets"].add<JsonObject>();
|
||||
filter_assets_0["name"] = true;
|
||||
filter_assets_0["browser_download_url"] = true;
|
||||
// JsonObject filter_assets_0 = filter["assets"].add<JsonObject>();
|
||||
// filter_assets_0["name"] = true;
|
||||
// filter_assets_0["browser_download_url"] = true;
|
||||
|
||||
JsonDocument doc;
|
||||
// JsonDocument doc;
|
||||
|
||||
DeserializationError error = deserializeJson(
|
||||
doc, http.getStream(), DeserializationOption::Filter(filter));
|
||||
// DeserializationError error = deserializeJson(
|
||||
// doc, http.getStream(), DeserializationOption::Filter(filter));
|
||||
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
// if (error) {
|
||||
// Serial.print("deserializeJson() failed: ");
|
||||
// Serial.println(error.c_str());
|
||||
// return;
|
||||
// }
|
||||
|
||||
String downloadUrl;
|
||||
for (JsonObject asset : doc["assets"].as<JsonArray>()) {
|
||||
if (asset["name"].as<String>().compareTo("firmware.bin") == 0) {
|
||||
downloadUrl = asset["browser_download_url"].as<String>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// String downloadUrl;
|
||||
// for (JsonObject asset : doc["assets"].as<JsonArray>()) {
|
||||
// if (asset["name"].as<String>().compareTo("firmware.bin") == 0) {
|
||||
// downloadUrl = asset["browser_download_url"].as<String>();
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
Serial.printf("Download update from %s", downloadUrl);
|
||||
// Serial.printf("Download update from %s", downloadUrl);
|
||||
|
||||
// esp_http_client_config_t config = {
|
||||
// .url = CONFIG_FIRMWARE_UPGRADE_URL,
|
||||
// };
|
||||
// esp_https_ota_config_t ota_config = {
|
||||
// .http_config = &config,
|
||||
// };
|
||||
// esp_err_t ret = esp_https_ota(&ota_config);
|
||||
// if (ret == ESP_OK)
|
||||
// {
|
||||
// esp_restart();
|
||||
// }
|
||||
}
|
||||
}
|
||||
// // esp_http_client_config_t config = {
|
||||
// // .url = CONFIG_FIRMWARE_UPGRADE_URL,
|
||||
// // };
|
||||
// // esp_https_ota_config_t ota_config = {
|
||||
// // .http_config = &config,
|
||||
// // };
|
||||
// // esp_err_t ret = esp_https_ota(&ota_config);
|
||||
// // if (ret == ESP_OK)
|
||||
// // {
|
||||
// // esp_restart();
|
||||
// // }
|
||||
// }
|
||||
// }
|
||||
|
||||
void onOTAError(ota_error_t error) {
|
||||
Serial.println(F("\nOTA update error, restarting"));
|
||||
|
|
|
@ -8,7 +8,7 @@ void setupOTA();
|
|||
void onOTAStart();
|
||||
void handleOTATask(void *parameter);
|
||||
void onOTAProgress(unsigned int progress, unsigned int total);
|
||||
void downloadUpdate();
|
||||
// void downloadUpdate();
|
||||
void onOTAError(ota_error_t error);
|
||||
void onOTAComplete();
|
||||
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
#include "price_fetch.hpp"
|
||||
|
||||
const PROGMEM char *cgApiUrl =
|
||||
"https://api.coingecko.com/api/v3/simple/"
|
||||
"price?ids=bitcoin&vs_currencies=usd%2Ceur";
|
||||
|
||||
TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
void taskPriceFetch(void *pvParameters) {
|
||||
WiFiClientSecure *client = new WiFiClientSecure;
|
||||
client->setInsecure();
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
HTTPClient *http = new HTTPClient();
|
||||
http->setUserAgent(USER_AGENT);
|
||||
|
||||
// Send HTTP request to CoinGecko API
|
||||
http->begin(*client, cgApiUrl);
|
||||
|
||||
int httpCode = http->GET();
|
||||
|
||||
// Parse JSON response and extract average price
|
||||
uint usdPrice, eurPrice;
|
||||
if (httpCode == 200) {
|
||||
String payload = http->getString();
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
// usdPrice = doc["bitcoin"]["usd"];
|
||||
eurPrice = doc["bitcoin"]["eur"].as<uint>();
|
||||
|
||||
setPrice(eurPrice, CURRENCY_EUR);
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
preferences.putUInt("lastPrice", eurPrice);
|
||||
} else {
|
||||
Serial.print(
|
||||
F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
||||
Serial.println(httpCode);
|
||||
if (httpCode == -1) {
|
||||
WiFi.reconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupPriceFetchTask() {
|
||||
xTaskCreate(taskPriceFetch, "priceFetch", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&priceFetchTaskHandle);
|
||||
|
||||
xTaskNotifyGive(priceFetchTaskHandle);
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
extern TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
void setupPriceFetchTask();
|
||||
void taskPriceFetch(void *pvParameters);
|
|
@ -5,6 +5,39 @@ const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws";
|
|||
|
||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
||||
|
||||
const char* coincapWsCert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
// WebsocketsClient client;
|
||||
esp_websocket_client_handle_t clientPrice = NULL;
|
||||
|
@ -14,6 +47,7 @@ unsigned long int lastPriceUpdate;
|
|||
bool priceNotifyInit = false;
|
||||
std::map<char, std::uint64_t> currencyMap;
|
||||
std::map<char, unsigned long int> lastUpdateMap;
|
||||
WebSocketsClient priceNotifyWs;
|
||||
|
||||
void setupPriceNotify()
|
||||
{
|
||||
|
@ -26,14 +60,51 @@ void setupPriceNotify()
|
|||
{
|
||||
config = {.uri = wsServerPrice,
|
||||
.user_agent = USER_AGENT};
|
||||
config.cert_pem = coincapWsCert;
|
||||
config.task_stack = (6*1024);
|
||||
}
|
||||
|
||||
clientPrice = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY,
|
||||
onWebsocketPriceEvent, clientPrice);
|
||||
esp_websocket_client_start(clientPrice);
|
||||
|
||||
// priceNotifyWs.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin");
|
||||
// priceNotifyWs.onEvent(onWebsocketPriceEvent);
|
||||
// priceNotifyWs.setReconnectInterval(5000);
|
||||
// priceNotifyWs.enableHeartbeat(15000, 3000, 2);
|
||||
}
|
||||
|
||||
|
||||
// void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) {
|
||||
// switch(type) {
|
||||
// case WStype_DISCONNECTED:
|
||||
// Serial.printf("[WSc] Disconnected!\n");
|
||||
// break;
|
||||
// case WStype_CONNECTED:
|
||||
// {
|
||||
// Serial.printf("[WSc] Connected to url: %s\n", payload);
|
||||
|
||||
|
||||
// break;
|
||||
// }
|
||||
// case WStype_TEXT:
|
||||
// String message = String((char*)payload);
|
||||
// onWebsocketPriceMessage(message);
|
||||
// break;
|
||||
// case WStype_BIN:
|
||||
// break;
|
||||
// case WStype_ERROR:
|
||||
// case WStype_FRAGMENT_TEXT_START:
|
||||
// case WStype_FRAGMENT_BIN_START:
|
||||
// case WStype_FRAGMENT:
|
||||
// case WStype_PING:
|
||||
// case WStype_PONG:
|
||||
// case WStype_FRAGMENT_FIN:
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
|
@ -83,7 +154,7 @@ void processNewPrice(uint newPrice, char currency)
|
|||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
uint currentTime = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end()||
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
|
||||
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
||||
{
|
||||
// const unsigned long oldPrice = currentPrice;
|
||||
|
@ -108,22 +179,26 @@ void processNewPrice(uint newPrice, char currency)
|
|||
|
||||
uint getLastPriceUpdate(char currency)
|
||||
{
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end()) {
|
||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return lastUpdateMap[currency];
|
||||
}
|
||||
|
||||
uint getPrice(char currency) {
|
||||
if (currencyMap.find(currency) == currencyMap.end()) {
|
||||
uint getPrice(char currency)
|
||||
{
|
||||
if (currencyMap.find(currency) == currencyMap.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return currencyMap[currency];
|
||||
return currencyMap[currency];
|
||||
}
|
||||
|
||||
void setPrice(uint newPrice, char currency) {
|
||||
currencyMap[currency] = newPrice;
|
||||
void setPrice(uint newPrice, char currency)
|
||||
{
|
||||
currencyMap[currency] = newPrice;
|
||||
}
|
||||
|
||||
bool isPriceNotifyConnected()
|
||||
|
|
|
@ -12,6 +12,8 @@ void setupPriceNotify();
|
|||
|
||||
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data);
|
||||
//void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
uint getPrice(char currency);
|
||||
|
|
|
@ -126,9 +126,6 @@ void IRAM_ATTR minuteTimerISR(void *arg) {
|
|||
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
|
||||
if (priceFetchTaskHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(priceFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
|
||||
if (bitaxeFetchTaskHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <bitaxe_handler.hpp>
|
||||
|
||||
#include "lib/epd.hpp"
|
||||
#include "lib/price_fetch.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
// extern TaskHandle_t priceUpdateTaskHandle;
|
||||
|
|
|
@ -1,10 +1,74 @@
|
|||
#include "shared.hpp"
|
||||
|
||||
const char *github_root_ca =
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL\n"
|
||||
"MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl\n"
|
||||
"eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT\n"
|
||||
"JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx\n"
|
||||
"MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT\n"
|
||||
"Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg\n"
|
||||
"VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm\n"
|
||||
"aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo\n"
|
||||
"I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng\n"
|
||||
"o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G\n"
|
||||
"A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD\n"
|
||||
"VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB\n"
|
||||
"zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW\n"
|
||||
"RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=\n"
|
||||
"-----END CERTIFICATE-----\n"
|
||||
"-----BEGIN CERTIFICATE-----\n"
|
||||
"MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh\n"
|
||||
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
|
||||
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
|
||||
"MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT\n"
|
||||
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
|
||||
"b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG\n"
|
||||
"9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI\n"
|
||||
"2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx\n"
|
||||
"1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ\n"
|
||||
"q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz\n"
|
||||
"tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ\n"
|
||||
"vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP\n"
|
||||
"BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV\n"
|
||||
"5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY\n"
|
||||
"1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4\n"
|
||||
"NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG\n"
|
||||
"Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91\n"
|
||||
"8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe\n"
|
||||
"pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl\n"
|
||||
"MrY=\n"
|
||||
"-----END CERTIFICATE-----\n";
|
||||
|
||||
#ifdef TEST_SCREENS
|
||||
uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24
|
||||
uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits
|
||||
uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits
|
||||
uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w
|
||||
uint8_t input_buffer[3 * input_buffer_pixels]; // up to depth 24
|
||||
uint8_t output_row_mono_buffer[max_row_width / 8]; // buffer for at least one row of b/w bits
|
||||
uint8_t output_row_color_buffer[max_row_width / 8]; // buffer for at least one row of color bits
|
||||
uint8_t mono_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 b/w
|
||||
uint8_t color_palette_buffer[max_palette_pixels / 8]; // palette buffer for depth <= 8 c/w
|
||||
uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display
|
||||
#endif
|
||||
uint16_t rgb_palette_buffer[max_palette_pixels]; // palette buffer for depth <= 8 for buffered graphics, needed for 7-color display
|
||||
#endif
|
||||
|
||||
// Function to calculate SHA-256 hash
|
||||
String calculateSHA256(uint8_t *data, size_t len)
|
||||
{
|
||||
byte shaResult[32];
|
||||
mbedtls_md_context_t ctx;
|
||||
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||
|
||||
mbedtls_md_init(&ctx);
|
||||
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
|
||||
mbedtls_md_starts(&ctx);
|
||||
mbedtls_md_update(&ctx, data, len);
|
||||
mbedtls_md_finish(&ctx, shaResult);
|
||||
mbedtls_md_free(&ctx);
|
||||
|
||||
char sha256_str[65];
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
sprintf(sha256_str + (i * 2), "%02x", shaResult[i]);
|
||||
}
|
||||
sha256_str[64] = 0;
|
||||
|
||||
return String(sha256_str);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <freertos/task.h>
|
||||
#include <GxEPD2.h>
|
||||
#include <GxEPD2_BW.h>
|
||||
#include <mbedtls/md.h>
|
||||
|
||||
#include <mutex>
|
||||
#include <utils.hpp>
|
||||
|
@ -65,7 +66,16 @@ const PROGMEM int screens[SCREEN_COUNT] = {
|
|||
const int usPerSecond = 1000000;
|
||||
const int usPerMinute = 60 * usPerSecond;
|
||||
|
||||
extern const char *github_root_ca;
|
||||
|
||||
const PROGMEM char UPDATE_FIRMWARE = 0;
|
||||
const PROGMEM char UPDATE_WEBUI = 1;
|
||||
|
||||
|
||||
struct ScreenMapping {
|
||||
int value;
|
||||
const char* name;
|
||||
};
|
||||
};
|
||||
|
||||
String calculateSHA256(uint8_t* data, size_t len);
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ void setupV2Notify()
|
|||
if ( preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) {
|
||||
Serial.println(F("Connecting to V2 staging source"));
|
||||
hostname = "ws-staging.btclock.dev";
|
||||
}
|
||||
} else {
|
||||
Serial.println(F("Connecting to V2 source"));
|
||||
}
|
||||
|
||||
webSocket.beginSSL(hostname, 443, "/api/v2/ws");
|
||||
webSocket.onEvent(onWebsocketV2Event);
|
||||
|
@ -120,7 +122,7 @@ void handleV2Message(JsonDocument doc) {
|
|||
processNewPrice(newPrice, getCurrencyChar(currency));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taskV2Notify(void *pvParameters) {
|
||||
|
|
|
@ -86,6 +86,8 @@ 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/restart", HTTP_GET, onApiRestart);
|
||||
|
@ -662,7 +664,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
|||
root["mcapBigChar"] = preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR);
|
||||
root["mdnsEnabled"] = preferences.getBool("mdnsEnabled", DEFAULT_MDNS_ENABLED);
|
||||
root["otaEnabled"] = preferences.getBool("otaEnabled", DEFAULT_OTA_ENABLED);
|
||||
root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE);
|
||||
// root["fetchEurPrice"] = preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE);
|
||||
root["useSatsSymbol"] = preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL);
|
||||
root["useBlkCountdown"] = preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN);
|
||||
root["suffixPrice"] = preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE);
|
||||
|
@ -1043,6 +1045,167 @@ void onApiShowCurrency(AsyncWebServerRequest *request)
|
|||
request->send(404);
|
||||
}
|
||||
|
||||
String getLatestRelease(const String &fileToDownload)
|
||||
{
|
||||
|
||||
// const char *fileToDownload = "littlefs.bin";
|
||||
|
||||
String releaseUrl = "https://api.github.com/repos/btclock/btclock_v3/releases/latest";
|
||||
WiFiClientSecure client;
|
||||
client.setCACert(github_root_ca);
|
||||
HTTPClient http;
|
||||
http.begin(client, releaseUrl);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
|
||||
String downloadUrl = "";
|
||||
|
||||
if (httpCode > 0)
|
||||
{
|
||||
String payload = http.getString();
|
||||
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, payload);
|
||||
|
||||
JsonArray assets = doc["assets"];
|
||||
|
||||
for (JsonObject asset : assets)
|
||||
{
|
||||
if (asset["name"] == fileToDownload)
|
||||
{
|
||||
downloadUrl = asset["browser_download_url"].as<String>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
Serial.printf("Latest release URL: %s\r\n", downloadUrl.c_str());
|
||||
}
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
void onUpdateWebUi(AsyncWebServerRequest *request)
|
||||
{
|
||||
request->send(downloadUpdateHandler(UPDATE_WEBUI));
|
||||
}
|
||||
|
||||
void onUpdateFirmware(AsyncWebServerRequest *request)
|
||||
{
|
||||
request->send(downloadUpdateHandler(UPDATE_FIRMWARE));
|
||||
}
|
||||
|
||||
int downloadUpdateHandler(char updateType)
|
||||
{
|
||||
WiFiClientSecure client;
|
||||
client.setCACert(github_root_ca);
|
||||
HTTPClient http;
|
||||
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||
|
||||
String latestRelease = "";
|
||||
|
||||
switch (updateType)
|
||||
{
|
||||
case UPDATE_FIRMWARE:
|
||||
latestRelease = getLatestRelease(getFirmwareFilename());
|
||||
break;
|
||||
case UPDATE_WEBUI:
|
||||
latestRelease = getLatestRelease("littlefs.bin");
|
||||
break;
|
||||
}
|
||||
|
||||
if (latestRelease.equals(""))
|
||||
{
|
||||
return 503;
|
||||
}
|
||||
|
||||
http.begin(client, latestRelease);
|
||||
http.setUserAgent(USER_AGENT);
|
||||
|
||||
int httpCode = http.GET();
|
||||
if (httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
int contentLength = http.getSize();
|
||||
if (contentLength > 0)
|
||||
{
|
||||
uint8_t *buffer = (uint8_t *)malloc(contentLength);
|
||||
if (buffer)
|
||||
{
|
||||
WiFiClient *stream = http.getStreamPtr();
|
||||
size_t written = stream->readBytes(buffer, contentLength);
|
||||
|
||||
if (written == contentLength)
|
||||
{
|
||||
String calculated_sha256 = calculateSHA256(buffer, contentLength);
|
||||
Serial.print("Checksum is ");
|
||||
Serial.println(calculated_sha256);
|
||||
if (true)
|
||||
{
|
||||
Serial.println("Checksum verified. Proceeding with update.");
|
||||
|
||||
Update.onProgress(onOTAProgress);
|
||||
|
||||
int updateType = U_FLASH;
|
||||
|
||||
switch (updateType)
|
||||
{
|
||||
case UPDATE_WEBUI:
|
||||
updateType = U_SPIFFS;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
updateType = U_FLASH;
|
||||
}
|
||||
}
|
||||
|
||||
if (Update.begin(contentLength, updateType))
|
||||
{
|
||||
Update.write(buffer, contentLength);
|
||||
if (Update.end())
|
||||
{
|
||||
Serial.println("Update complete. Rebooting.");
|
||||
ESP.restart();
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Error in update process.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Not enough space to begin OTA");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Checksum mismatch. Aborting update.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Error downloading firmware");
|
||||
}
|
||||
free(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Not enough memory to allocate buffer");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Invalid content length");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(httpCode);
|
||||
Serial.println("Error on HTTP request");
|
||||
return 503;
|
||||
}
|
||||
http.end();
|
||||
|
||||
return 200;
|
||||
}
|
||||
|
||||
#ifdef HAS_FRONTLIGHT
|
||||
void onApiFrontlightOn(AsyncWebServerRequest *request)
|
||||
{
|
||||
|
|
|
@ -21,10 +21,17 @@ void stopWebServer();
|
|||
void setupWebserver();
|
||||
bool processEpdColorSettings(AsyncWebServerRequest *request);
|
||||
|
||||
|
||||
|
||||
void onApiStatus(AsyncWebServerRequest *request);
|
||||
void onApiSystemStatus(AsyncWebServerRequest *request);
|
||||
void onApiSetWifiTxPower(AsyncWebServerRequest *request);
|
||||
void onUpdateWebUi(AsyncWebServerRequest *request);
|
||||
void onUpdateFirmware(AsyncWebServerRequest *request);
|
||||
|
||||
int downloadUpdateHandler(char updateType);
|
||||
|
||||
String getLatestRelease(const String& fileToDownload);
|
||||
|
||||
void onApiScreenNext(AsyncWebServerRequest *request);
|
||||
void onApiScreenPrevious(AsyncWebServerRequest *request);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue