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
|
@ -12,11 +12,16 @@ Biggest differences with v2 are:
|
|||
- Added market capitalization screen
|
||||
- LED flash on new block (and focus to block height screen on new block)
|
||||
|
||||
New features:
|
||||
- BitAxe integration
|
||||
- Zap notifier
|
||||
-
|
||||
|
||||
"Steal focus on new block" means that when a new block is mined, the display will switch to the block height screen if it's not on it already.
|
||||
|
||||
Most [information](https://github.com/btclock/btclock_v2/wiki) about BTClock v2 is still valid for this version.
|
||||
|
||||
**NOTE**: The software assumes that the hardware is run in a controlled private network. The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.
|
||||
**NOTE**: The software assumes that the hardware is run in a controlled private network. ~~The Web UI and the OTA update mechanism are not password protected and accessible to anyone in the network. Also, since the device only fetches numbers through WebSockets it will skip server certificate verification to save resources.~~ Since 3.2.0 the WebUI is password protectable and all certificates are verified. OTA update mechanism is not password-protected.
|
||||
|
||||
## Building
|
||||
|
||||
|
|
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 1fa62ca88dc9cf85109712082e2b0d3916d03323
|
||||
Subproject commit 1c2d8dcdd0efd846f39b0f24977c982a96f16392
|
|
@ -7,8 +7,8 @@ CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
|||
#CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||
#CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||
#CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=n
|
||||
CONFIG_ESP_TLS_INSECURE=y
|
||||
CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
#CONFIG_ESP_TLS_INSECURE=y
|
||||
#CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y
|
||||
|
||||
CONFIG_HEAP_CORRUPTION_DETECTION=CONFIG_HEAP_POISONING_LIGHT
|
||||
CONFIG_HEAP_POISONING_LIGHT=y
|
||||
|
@ -50,4 +50,6 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
|
|||
CONFIG_ESP_SYSTEM_MEMPROT_FEATURE=n
|
||||
CONFIG_SPIRAM_CACHE_WORKAROUND=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
|
||||
CONFIG_MBEDTLS_SSL_SERVER_VERIFY=n
|
||||
CONFIG_MBEDTLS_SSL_VERIFY_CLIENT_CERTIFICATE=n
|
|
@ -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-----
|
||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
||||
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
||||
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
||||
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
||||
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
||||
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
||||
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
||||
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
||||
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
||||
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
||||
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
||||
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
||||
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
||||
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
||||
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
||||
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
||||
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
||||
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
||||
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
||||
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
||||
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
||||
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
||||
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
||||
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
||||
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
||||
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
||||
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
||||
-----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…
Reference in a new issue