Compare commits
1 commit
main
...
feature/ep
Author | SHA1 | Date | |
---|---|---|---|
8906bbee10 |
24 changed files with 509 additions and 562 deletions
2
data
2
data
|
@ -1 +1 @@
|
|||
Subproject commit 0116cd68cdfdf383823f74e0f9665a1700cf0500
|
||||
Subproject commit 033fe098295ab6da6568d6298b4380e51bec0b98
|
|
@ -4,6 +4,6 @@ dependencies:
|
|||
source:
|
||||
type: idf
|
||||
version: 4.4.7
|
||||
manifest_hash: 1d4ef353a86901733b106a1897b186dbf9fc091a4981f0560ea2f6899b7a3d44
|
||||
manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff
|
||||
target: esp32s3
|
||||
version: 1.0.0
|
||||
|
|
|
@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd,
|
|||
[env]
|
||||
|
||||
[btclock_base]
|
||||
platform = espressif32 @ ^6.10.0
|
||||
platform = espressif32 @ ^6.9.0
|
||||
framework = arduino, espidf
|
||||
monitor_speed = 115200
|
||||
monitor_filters = esp32_exception_decoder, colorize
|
||||
|
@ -30,17 +30,17 @@ build_flags =
|
|||
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||
-DARDUINO_USB_CDC_ON_BOOT
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-D CONFIG_ASYNC_TCP_STACK_SIZE=16384
|
||||
-D DEFAULT_BOOT_TEXT=\"BTCLOCK\"
|
||||
-fexceptions
|
||||
build_unflags =
|
||||
-Werror=all
|
||||
-fno-exceptions
|
||||
lib_deps =
|
||||
https://github.com/joltwallet/esp_littlefs.git#v1.16.4
|
||||
bblanchon/ArduinoJson@^7.3.0
|
||||
esp32async/ESPAsyncWebServer @ 3.7.0
|
||||
robtillaart/MCP23017@^0.9.0
|
||||
adafruit/Adafruit NeoPixel@^1.12.4
|
||||
https://github.com/joltwallet/esp_littlefs.git
|
||||
bblanchon/ArduinoJson@^7.2.1
|
||||
mathieucarbou/ESPAsyncWebServer @ 3.3.23
|
||||
robtillaart/MCP23017@^0.8.0
|
||||
adafruit/Adafruit NeoPixel@^1.12.3
|
||||
https://github.com/dsbaars/universal_pin#feature/mcp23017_rt
|
||||
https://github.com/dsbaars/GxEPD2#universal_pin
|
||||
https://github.com/tzapu/WiFiManager.git#v2.0.17
|
||||
|
@ -79,10 +79,9 @@ build_flags =
|
|||
-D I2C_SDA_PIN=35
|
||||
-D I2C_SCK_PIN=36
|
||||
-D HAS_FRONTLIGHT
|
||||
-D PCA_OE_PIN=48
|
||||
-D PCA_OE_PIN=45
|
||||
-D PCA_I2C_ADDR=0x42
|
||||
-D IS_HW_REV_B
|
||||
|
||||
lib_deps =
|
||||
${btclock_base.lib_deps}
|
||||
robtillaart/PCA9685@^0.7.1
|
||||
|
@ -101,7 +100,6 @@ build_flags =
|
|||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
-D HW_REV=\"REV_A_EPD_2_13\"
|
||||
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
|
@ -114,7 +112,6 @@ build_flags =
|
|||
-D USE_QR
|
||||
-D VERSION_EPD_2_13
|
||||
-D HW_REV=\"REV_B_EPD_2_13\"
|
||||
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
|
||||
platform_packages =
|
||||
platformio/tool-mklittlefs@^1.203.210628
|
||||
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
#include "block_notify.hpp"
|
||||
#include "led_handler.hpp"
|
||||
|
||||
// Initialize static members
|
||||
esp_websocket_client_handle_t BlockNotify::wsClient = nullptr;
|
||||
uint32_t BlockNotify::currentBlockHeight = 878000;
|
||||
uint16_t BlockNotify::blockMedianFee = 1;
|
||||
bool BlockNotify::notifyInit = false;
|
||||
unsigned long int BlockNotify::lastBlockUpdate = 0;
|
||||
TaskHandle_t BlockNotify::taskHandle = nullptr;
|
||||
char *wsServer;
|
||||
esp_websocket_client_handle_t blockNotifyClient = NULL;
|
||||
uint32_t currentBlockHeight = 873400;
|
||||
uint16_t blockMedianFee = 1;
|
||||
bool blockNotifyInit = false;
|
||||
unsigned long int lastBlockUpdate;
|
||||
|
||||
const char* BlockNotify::mempoolWsCert = R"EOF(
|
||||
const char *mempoolWsCert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
|
@ -43,154 +43,145 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
|||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
BlockNotify& instance = BlockNotify::getInstance();
|
||||
void setupBlockNotify()
|
||||
{
|
||||
IPAddress result;
|
||||
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
{
|
||||
notifyInit = true;
|
||||
Serial.print(F("Connected to "));
|
||||
Serial.println(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE));
|
||||
int dnsErr = -1;
|
||||
String mempoolInstance =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
||||
JsonDocument doc;
|
||||
doc["action"] = "want";
|
||||
JsonArray dataArray = doc.createNestedArray("data");
|
||||
dataArray.add("blocks");
|
||||
dataArray.add("mempool-blocks");
|
||||
|
||||
String sub;
|
||||
serializeJson(doc, sub);
|
||||
esp_websocket_client_send_text(wsClient, sub.c_str(), sub.length(), portMAX_DELAY);
|
||||
break;
|
||||
}
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
instance.onWebsocketMessage(data);
|
||||
break;
|
||||
while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':'))
|
||||
{
|
||||
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
|
||||
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Mempool.space WS Connection Closed"));
|
||||
break;
|
||||
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Mempool.space WS Connection Error"));
|
||||
break;
|
||||
if (dnsErr != 1)
|
||||
{
|
||||
Serial.print(mempoolInstance);
|
||||
Serial.println(F("mempool DNS could not be resolved"));
|
||||
WiFi.reconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
// Get current block height through regular API
|
||||
int blockFetch = getBlockFetch();
|
||||
|
||||
if (blockFetch > currentBlockHeight)
|
||||
currentBlockHeight = blockFetch;
|
||||
|
||||
if (currentBlockHeight != -1)
|
||||
{
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
}
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
// std::strcpy(wsServer, String("wss://" + mempoolInstance +
|
||||
// "/api/v1/ws").c_str());
|
||||
|
||||
const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "wss" : "ws";
|
||||
|
||||
String mempoolUri = protocol + "://" + preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE) + "/api/v1/ws";
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
// .uri = "wss://mempool.space/api/v1/ws",
|
||||
.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);
|
||||
esp_websocket_client_start(blockNotifyClient);
|
||||
}
|
||||
|
||||
void BlockNotify::onWebsocketMessage(esp_websocket_event_data_t *data) {
|
||||
JsonDocument doc;
|
||||
JsonDocument filter;
|
||||
filter["block"]["height"] = true;
|
||||
filter["mempool-blocks"][0]["medianFee"] = true;
|
||||
void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
const String sub = "{\"action\": \"want\", \"data\":[\"blocks\", \"mempool-blocks\"]}";
|
||||
switch (event_id)
|
||||
{
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
blockNotifyInit = true;
|
||||
|
||||
deserializeJson(doc, (char*)data->data_ptr, DeserializationOption::Filter(filter));
|
||||
Serial.println(F("Connected to Mempool.space WebSocket"));
|
||||
|
||||
if (doc["block"].is<JsonObject>()) {
|
||||
JsonObject block = doc["block"];
|
||||
if (block["height"].as<uint>() != currentBlockHeight) {
|
||||
processNewBlock(block["height"].as<uint>());
|
||||
}
|
||||
}
|
||||
else if (doc["mempool-blocks"].is<JsonArray>()) {
|
||||
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
|
||||
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
|
||||
processNewBlockFee(medianFee);
|
||||
Serial.println(sub);
|
||||
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(),
|
||||
sub.length(), portMAX_DELAY) == -1)
|
||||
{
|
||||
Serial.println(F("Mempool.space WS Block Subscribe Error"));
|
||||
}
|
||||
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
onWebsocketBlockMessage(data);
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Mempool.space WS Connnection error"));
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Mempool.space WS Connnection Closed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void BlockNotify::setup() {
|
||||
IPAddress result;
|
||||
int dnsErr = -1;
|
||||
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data)
|
||||
{
|
||||
JsonDocument doc;
|
||||
|
||||
while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) {
|
||||
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
|
||||
JsonDocument filter;
|
||||
filter["block"]["height"] = true;
|
||||
filter["mempool-blocks"][0]["medianFee"] = true;
|
||||
|
||||
if (dnsErr != 1) {
|
||||
Serial.print(mempoolInstance);
|
||||
Serial.println(F("mempool DNS could not be resolved"));
|
||||
WiFi.reconnect();
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
deserializeJson(doc, (char *)event_data->data_ptr, DeserializationOption::Filter(filter));
|
||||
|
||||
// if (error) {
|
||||
// Serial.print("deserializeJson() failed: ");
|
||||
// Serial.println(error.c_str());
|
||||
// return;
|
||||
// }
|
||||
|
||||
if (doc.containsKey("block"))
|
||||
{
|
||||
JsonObject block = doc["block"];
|
||||
|
||||
if (block["height"].as<uint>() == currentBlockHeight) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get current block height through regular API
|
||||
int blockFetch = fetchLatestBlock();
|
||||
processNewBlock(block["height"].as<uint>());
|
||||
}
|
||||
else if (doc.containsKey("mempool-blocks"))
|
||||
{
|
||||
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
|
||||
|
||||
if (blockFetch > currentBlockHeight)
|
||||
currentBlockHeight = blockFetch;
|
||||
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
|
||||
|
||||
if (currentBlockHeight != -1) {
|
||||
lastBlockUpdate = esp_timer_get_time() / 1000000;
|
||||
}
|
||||
processNewBlockFee(medianFee);
|
||||
}
|
||||
|
||||
if (workQueue != nullptr) {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
const bool useSSL = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE);
|
||||
const String protocol = useSSL ? "wss" : "ws";
|
||||
String wsUri = protocol + "://" + mempoolInstance + "/api/v1/ws";
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.task_stack = (6*1024),
|
||||
.user_agent = USER_AGENT
|
||||
};
|
||||
|
||||
if (useSSL) {
|
||||
config.cert_pem = mempoolWsCert;
|
||||
}
|
||||
|
||||
config.uri = wsUri.c_str();
|
||||
|
||||
Serial.printf("Connecting to %s\r\n", mempoolInstance.c_str());
|
||||
|
||||
wsClient = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(wsClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, wsClient);
|
||||
esp_websocket_client_start(wsClient);
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
|
||||
if (newBlockHeight <= currentBlockHeight)
|
||||
void processNewBlock(uint32_t newBlockHeight) {
|
||||
if (currentBlockHeight <= newBlockHeight)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -229,69 +220,76 @@ void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
|
|||
}
|
||||
}
|
||||
|
||||
void BlockNotify::processNewBlockFee(uint16_t newBlockFee) {
|
||||
if (blockMedianFee == newBlockFee)
|
||||
void processNewBlockFee(uint16_t newBlockFee) {
|
||||
if (blockMedianFee == newBlockFee)
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
// Serial.printf("New median fee: %d\r\n", medianFee);
|
||||
blockMedianFee = newBlockFee;
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t BlockNotify::getBlockHeight() const {
|
||||
return currentBlockHeight;
|
||||
}
|
||||
uint32_t getBlockHeight() { return currentBlockHeight; }
|
||||
|
||||
void BlockNotify::setBlockHeight(uint32_t newBlockHeight)
|
||||
void setBlockHeight(uint32_t newBlockHeight)
|
||||
{
|
||||
currentBlockHeight = newBlockHeight;
|
||||
currentBlockHeight = newBlockHeight;
|
||||
}
|
||||
|
||||
uint16_t BlockNotify::getBlockMedianFee() const {
|
||||
return blockMedianFee;
|
||||
}
|
||||
uint16_t getBlockMedianFee() { return blockMedianFee; }
|
||||
|
||||
void BlockNotify::setBlockMedianFee(uint16_t newBlockMedianFee)
|
||||
void setBlockMedianFee(uint16_t newBlockMedianFee)
|
||||
{
|
||||
blockMedianFee = newBlockMedianFee;
|
||||
blockMedianFee = newBlockMedianFee;
|
||||
}
|
||||
|
||||
bool BlockNotify::isConnected() const
|
||||
bool isBlockNotifyConnected()
|
||||
{
|
||||
if (wsClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(wsClient);
|
||||
if (blockNotifyClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(blockNotifyClient);
|
||||
}
|
||||
|
||||
bool BlockNotify::isInitialized() const
|
||||
bool getBlockNotifyInit()
|
||||
{
|
||||
return notifyInit;
|
||||
return blockNotifyInit;
|
||||
}
|
||||
|
||||
void BlockNotify::stop()
|
||||
void stopBlockNotify()
|
||||
{
|
||||
if (wsClient == NULL)
|
||||
return;
|
||||
if (blockNotifyClient == NULL)
|
||||
return;
|
||||
|
||||
esp_websocket_client_close(wsClient, portMAX_DELAY);
|
||||
esp_websocket_client_stop(wsClient);
|
||||
esp_websocket_client_destroy(wsClient);
|
||||
wsClient = NULL;
|
||||
esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
|
||||
esp_websocket_client_stop(blockNotifyClient);
|
||||
esp_websocket_client_destroy(blockNotifyClient);
|
||||
|
||||
blockNotifyClient = NULL;
|
||||
}
|
||||
|
||||
void BlockNotify::restart()
|
||||
void restartBlockNotify()
|
||||
{
|
||||
stop();
|
||||
setup();
|
||||
stopBlockNotify();
|
||||
|
||||
if (blockNotifyClient == NULL) {
|
||||
setupBlockNotify();
|
||||
return;
|
||||
}
|
||||
|
||||
// esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
|
||||
// esp_websocket_client_stop(blockNotifyClient);
|
||||
// esp_websocket_client_start(blockNotifyClient);
|
||||
}
|
||||
|
||||
int BlockNotify::fetchLatestBlock() {
|
||||
|
||||
int getBlockFetch() {
|
||||
try {
|
||||
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http";
|
||||
|
@ -314,12 +312,12 @@ int BlockNotify::fetchLatestBlock() {
|
|||
return 2203; // B-T-C
|
||||
}
|
||||
|
||||
uint BlockNotify::getLastBlockUpdate() const
|
||||
uint getLastBlockUpdate()
|
||||
{
|
||||
return lastBlockUpdate;
|
||||
return lastBlockUpdate;
|
||||
}
|
||||
|
||||
void BlockNotify::setLastBlockUpdate(uint lastUpdate)
|
||||
void setLastBlockUpdate(uint lastUpdate)
|
||||
{
|
||||
lastBlockUpdate = lastUpdate;
|
||||
lastBlockUpdate = lastUpdate;
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
#include <HTTPClient.h>
|
||||
#include <esp_timer.h>
|
||||
#include <esp_websocket_client.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
|
@ -13,53 +14,28 @@
|
|||
#include "lib/timers.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
class BlockNotify {
|
||||
public:
|
||||
static BlockNotify& getInstance() {
|
||||
static BlockNotify instance;
|
||||
return instance;
|
||||
}
|
||||
// using namespace websockets;
|
||||
|
||||
// Delete copy constructor and assignment operator
|
||||
BlockNotify(const BlockNotify&) = delete;
|
||||
void operator=(const BlockNotify&) = delete;
|
||||
void setupBlockNotify();
|
||||
|
||||
// Block notification setup and control
|
||||
void setup();
|
||||
void stop();
|
||||
void restart();
|
||||
bool isConnected() const;
|
||||
bool isInitialized() const;
|
||||
void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base,
|
||||
int32_t event_id, void *event_data);
|
||||
void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
// Block height management
|
||||
void setBlockHeight(uint32_t newBlockHeight);
|
||||
uint32_t getBlockHeight() const;
|
||||
void setBlockHeight(uint32_t newBlockHeight);
|
||||
uint32_t getBlockHeight();
|
||||
|
||||
// Block fee management
|
||||
void setBlockMedianFee(uint16_t blockMedianFee);
|
||||
uint16_t getBlockMedianFee() const;
|
||||
void setBlockMedianFee(uint16_t blockMedianFee);
|
||||
uint16_t getBlockMedianFee();
|
||||
|
||||
// Block processing
|
||||
void processNewBlock(uint32_t newBlockHeight);
|
||||
void processNewBlockFee(uint16_t newBlockFee);
|
||||
bool isBlockNotifyConnected();
|
||||
void stopBlockNotify();
|
||||
void restartBlockNotify();
|
||||
|
||||
// Block fetch and update tracking
|
||||
int fetchLatestBlock();
|
||||
uint getLastBlockUpdate() const;
|
||||
void setLastBlockUpdate(uint lastUpdate);
|
||||
void processNewBlock(uint32_t newBlockHeight);
|
||||
void processNewBlockFee(uint16_t newBlockFee);
|
||||
|
||||
private:
|
||||
BlockNotify() = default; // Private constructor for singleton
|
||||
|
||||
void setupTask();
|
||||
static void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data);
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *data);
|
||||
|
||||
static const char* mempoolWsCert;
|
||||
static esp_websocket_client_handle_t wsClient;
|
||||
static uint32_t currentBlockHeight;
|
||||
static uint16_t blockMedianFee;
|
||||
static bool notifyInit;
|
||||
static unsigned long int lastBlockUpdate;
|
||||
static TaskHandle_t taskHandle;
|
||||
};
|
||||
bool getBlockNotifyInit();
|
||||
uint32_t getLastBlockUpdate();
|
||||
int getBlockFetch();
|
||||
void setLastBlockUpdate(uint32_t lastUpdate);
|
||||
|
|
|
@ -132,25 +132,9 @@ void setup()
|
|||
void setupWifi()
|
||||
{
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
// wifi_country_t country = {
|
||||
// .cc = "NL",
|
||||
// .schan = 1,
|
||||
// .nchan = 13,
|
||||
// .policy = WIFI_COUNTRY_POLICY_MANUAL
|
||||
// };
|
||||
|
||||
// esp_err_t err = esp_wifi_set_country(&country);
|
||||
// if (err != ESP_OK) {
|
||||
// Serial.printf("Failed to set country: %d\n", err);
|
||||
// }
|
||||
|
||||
WiFi.setAutoConnect(true);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.begin();
|
||||
|
||||
|
||||
|
||||
if (preferences.getInt("txPower", DEFAULT_TX_POWER))
|
||||
{
|
||||
if (WiFi.setTxPower(
|
||||
|
@ -188,7 +172,6 @@ void setupWifi()
|
|||
wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT));
|
||||
wm.setWiFiAutoReconnect(false);
|
||||
wm.setDebugOutput(false);
|
||||
wm.setCountry("NL");
|
||||
wm.setConfigPortalBlocking(true);
|
||||
|
||||
wm.setAPCallback([&](WiFiManager *wifiManager)
|
||||
|
@ -282,7 +265,7 @@ void setupPreferences()
|
|||
|
||||
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||
BlockNotify::getInstance().setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
|
||||
setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
|
||||
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
||||
|
||||
if (!preferences.isKey("enableDebugLog")) {
|
||||
|
@ -390,7 +373,7 @@ void setupWebsocketClients(void *pvParameters)
|
|||
}
|
||||
else if (dataSource == THIRD_PARTY_SOURCE)
|
||||
{
|
||||
BlockNotify::getInstance().setup();
|
||||
setupBlockNotify();
|
||||
setupPriceNotify();
|
||||
}
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@
|
|||
#define DEFAULT_LUX_LIGHT_TOGGLE 128
|
||||
#define DEFAULT_FL_OFF_WHEN_DARK true
|
||||
|
||||
#define DEFAULT_FL_ALWAYS_ON true
|
||||
#define DEFAULT_FL_FLASH_ON_UPDATE true
|
||||
#define DEFAULT_FL_ALWAYS_ON false
|
||||
#define DEFAULT_FL_FLASH_ON_UPDATE false
|
||||
|
||||
#define DEFAULT_LED_STATUS false
|
||||
#define DEFAULT_TIMER_ACTIVE true
|
||||
|
@ -60,7 +60,6 @@
|
|||
#define DEFAULT_MINING_POOL_STATS_ENABLED false
|
||||
#define DEFAULT_MINING_POOL_NAME "ocean"
|
||||
#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher
|
||||
#define DEFAULT_LOCAL_POOL_ENDPOINT "umbrel.local:2019"
|
||||
|
||||
#define DEFAULT_ZAP_NOTIFY_ENABLED false
|
||||
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"
|
||||
|
|
188
src/lib/epd.cpp
188
src/lib/epd.cpp
|
@ -69,26 +69,7 @@ EPDManager::EPDManager()
|
|||
, fontSatsymbol{nullptr}
|
||||
, bgColor{GxEPD_BLACK}
|
||||
, fgColor{GxEPD_WHITE}
|
||||
, displays{
|
||||
#ifdef IS_BTCLOCK_V8
|
||||
EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]),
|
||||
EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]),
|
||||
EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]),
|
||||
EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]),
|
||||
EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]),
|
||||
EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]),
|
||||
EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6]),
|
||||
EPD_CLASS(&EPD_CS[7], &EPD_DC, &EPD_RESET[7], &EPD_BUSY[7])
|
||||
#else
|
||||
EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0]),
|
||||
EPD_CLASS(&EPD_CS[1], &EPD_DC, &EPD_RESET[1], &EPD_BUSY[1]),
|
||||
EPD_CLASS(&EPD_CS[2], &EPD_DC, &EPD_RESET[2], &EPD_BUSY[2]),
|
||||
EPD_CLASS(&EPD_CS[3], &EPD_DC, &EPD_RESET[3], &EPD_BUSY[3]),
|
||||
EPD_CLASS(&EPD_CS[4], &EPD_DC, &EPD_RESET[4], &EPD_BUSY[4]),
|
||||
EPD_CLASS(&EPD_CS[5], &EPD_DC, &EPD_RESET[5], &EPD_BUSY[5]),
|
||||
EPD_CLASS(&EPD_CS[6], &EPD_DC, &EPD_RESET[6], &EPD_BUSY[6])
|
||||
#endif
|
||||
}
|
||||
, display{EPD_CLASS(&EPD_CS[0], &EPD_DC, &EPD_RESET[0], &EPD_BUSY[0])}
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -119,11 +100,10 @@ void EPDManager::initialize() {
|
|||
String fontName = preferences.getString("fontName", DEFAULT_FONT_NAME);
|
||||
loadFonts(fontName);
|
||||
|
||||
// Initialize displays
|
||||
// Initialize first display
|
||||
switchToDisplay(0);
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
for (auto& display : displays) {
|
||||
display.init(0, true, 30);
|
||||
}
|
||||
display.init(0, true, 30);
|
||||
|
||||
// Create update queue and task
|
||||
updateQueue = xQueueCreate(UPDATE_QUEUE_SIZE, sizeof(UpdateDisplayTaskItem));
|
||||
|
@ -228,46 +208,48 @@ void EPDManager::waitUntilNoneBusy() {
|
|||
}
|
||||
|
||||
void EPDManager::setupDisplay(uint dispNum, const GFXfont* font) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setFont(font);
|
||||
display.setTextColor(fgColor);
|
||||
display.fillScreen(bgColor);
|
||||
}
|
||||
|
||||
void EPDManager::splitText(uint dispNum, const String& top, const String& bottom, bool partial) {
|
||||
switchToDisplay(dispNum);
|
||||
if (preferences.getBool("verticalDesc", DEFAULT_VERTICAL_DESC) && dispNum == 0) {
|
||||
displays[dispNum].setRotation(1);
|
||||
display.setRotation(1);
|
||||
} else {
|
||||
displays[dispNum].setRotation(2);
|
||||
display.setRotation(2);
|
||||
}
|
||||
displays[dispNum].setFont(fontSmall);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
display.setFont(fontSmall);
|
||||
display.setTextColor(fgColor);
|
||||
|
||||
// Top text
|
||||
int16_t ttbx, ttby;
|
||||
uint16_t ttbw, ttbh;
|
||||
displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh);
|
||||
uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx;
|
||||
uint16_t ty = ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12;
|
||||
display.getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh);
|
||||
uint16_t tx = ((display.width() - ttbw) / 2) - ttbx;
|
||||
uint16_t ty = ((display.height() - ttbh) / 2) - ttby - ttbh / 2 - 12;
|
||||
|
||||
// Bottom text
|
||||
int16_t tbbx, tbby;
|
||||
uint16_t tbbw, tbbh;
|
||||
displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh);
|
||||
uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx;
|
||||
uint16_t by = ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
|
||||
display.getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh);
|
||||
uint16_t bx = ((display.width() - tbbw) / 2) - tbbx;
|
||||
uint16_t by = ((display.height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
|
||||
|
||||
// Make separator as wide as the shortest text
|
||||
uint16_t lineWidth = (tbbw < ttbh) ? tbbw : ttbw;
|
||||
uint16_t lineX = round((displays[dispNum].width() - lineWidth) / 2);
|
||||
uint16_t lineX = round((display.width() - lineWidth) / 2);
|
||||
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
displays[dispNum].setCursor(tx, ty);
|
||||
displays[dispNum].print(top);
|
||||
displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3,
|
||||
lineWidth, 6, 3, fgColor);
|
||||
displays[dispNum].setCursor(bx, by);
|
||||
displays[dispNum].print(bottom);
|
||||
display.fillScreen(bgColor);
|
||||
display.setCursor(tx, ty);
|
||||
display.print(top);
|
||||
display.fillRoundRect(lineX, display.height() / 2 - 3,
|
||||
lineWidth, 6, 3, fgColor);
|
||||
display.setCursor(bx, by);
|
||||
display.print(bottom);
|
||||
}
|
||||
|
||||
void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont* font) {
|
||||
|
@ -280,17 +262,17 @@ void EPDManager::showDigit(uint dispNum, char chr, bool partial, const GFXfont*
|
|||
|
||||
int16_t tbx, tby;
|
||||
uint16_t tbw, tbh;
|
||||
displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
display.getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
|
||||
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
|
||||
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||
|
||||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(str);
|
||||
display.setCursor(x, y);
|
||||
display.print(str);
|
||||
|
||||
if (chr == '.') {
|
||||
displays[dispNum].fillRect(0, 0, displays[dispNum].width(),
|
||||
round(displays[dispNum].height() * 0.67), bgColor);
|
||||
display.fillRect(0, 0, display.width(),
|
||||
round(display.height() * 0.67), bgColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -299,11 +281,11 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
|
||||
int16_t tbx, tby;
|
||||
uint16_t tbw, tbh;
|
||||
displays[dispNum].getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
display.getTextBounds(chars, 0, 0, &tbx, &tby, &tbw, &tbh);
|
||||
|
||||
// Center the bounding box by transposition of the origin
|
||||
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
|
||||
uint16_t x = ((display.width() - tbw) / 2) - tbx;
|
||||
uint16_t y = ((display.height() - tbh) / 2) - tby;
|
||||
|
||||
for (size_t i = 0; i < chars.length(); i++) {
|
||||
char c = chars[i];
|
||||
|
@ -313,12 +295,12 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
int16_t dotDescent = dotGlyph->yOffset;
|
||||
|
||||
// Draw the dot with adjusted y-position
|
||||
displays[dispNum].setCursor(x, y + dotDescent + dotGlyph->height + 8);
|
||||
displays[dispNum].print(c);
|
||||
display.setCursor(x, y + dotDescent + dotGlyph->height + 8);
|
||||
display.print(c);
|
||||
} else {
|
||||
// For other characters, use the original y-position
|
||||
displays[dispNum].setCursor(x, y);
|
||||
displays[dispNum].print(c);
|
||||
display.setCursor(x, y);
|
||||
display.print(c);
|
||||
}
|
||||
|
||||
// Move x-position for the next character
|
||||
|
@ -327,11 +309,12 @@ void EPDManager::showChars(uint dispNum, const String& chars, bool partial, cons
|
|||
}
|
||||
|
||||
bool EPDManager::renderIcon(uint dispNum, const String& text, bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(bgColor);
|
||||
displays[dispNum].setTextColor(fgColor);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(bgColor);
|
||||
display.setTextColor(fgColor);
|
||||
|
||||
uint iconIndex = 0;
|
||||
uint width = 122;
|
||||
|
@ -352,27 +335,28 @@ bool EPDManager::renderIcon(uint dispNum, const String& text, bool partial) {
|
|||
return false;
|
||||
}
|
||||
|
||||
int x_offset = (displays[dispNum].width() - logo.width) / 2;
|
||||
int y_offset = (displays[dispNum].height() - logo.height) / 2;
|
||||
displays[dispNum].drawInvertedBitmap(x_offset, y_offset, logo.data,
|
||||
logo.width, logo.height, fgColor);
|
||||
int x_offset = (display.width() - logo.width) / 2;
|
||||
int y_offset = (display.height() - logo.height) / 2;
|
||||
display.drawInvertedBitmap(x_offset, y_offset, logo.data,
|
||||
logo.width, logo.height, fgColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
int x_offset = (displays[dispNum].width() - width) / 2;
|
||||
int y_offset = (displays[dispNum].height() - height) / 2;
|
||||
displays[dispNum].drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex],
|
||||
width, height, fgColor);
|
||||
int x_offset = (display.width() - width) / 2;
|
||||
int y_offset = (display.height() - height) / 2;
|
||||
display.drawInvertedBitmap(x_offset, y_offset, epd_icons_allArray[iconIndex],
|
||||
width, height, fgColor);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EPDManager::renderText(uint dispNum, const String& text, bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
displays[dispNum].setTextColor(GxEPD_BLACK);
|
||||
displays[dispNum].setCursor(0, 50);
|
||||
switchToDisplay(dispNum);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
display.setCursor(0, 50);
|
||||
|
||||
std::stringstream ss;
|
||||
ss.str(text.c_str());
|
||||
|
@ -381,16 +365,17 @@ void EPDManager::renderText(uint dispNum, const String& text, bool partial) {
|
|||
while (std::getline(ss, line, '\n')) {
|
||||
if (line.rfind("*", 0) == 0) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '*'), line.end());
|
||||
displays[dispNum].setFont(&FreeSansBold9pt7b);
|
||||
display.setFont(&FreeSansBold9pt7b);
|
||||
} else {
|
||||
displays[dispNum].setFont(&FreeSans9pt7b);
|
||||
display.setFont(&FreeSans9pt7b);
|
||||
}
|
||||
displays[dispNum].println(line.c_str());
|
||||
display.println(line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void EPDManager::renderQr(uint dispNum, const String& text, bool partial) {
|
||||
#ifdef USE_QR
|
||||
switchToDisplay(dispNum);
|
||||
// Dynamically allocate QR buffer
|
||||
uint8_t* qrcode = (uint8_t*)malloc(qrcodegen_BUFFER_LEN_MAX);
|
||||
if (!qrcode) {
|
||||
|
@ -405,17 +390,17 @@ void EPDManager::renderQr(uint dispNum, const String& text, bool partial) {
|
|||
|
||||
if (ok) {
|
||||
const int size = qrcodegen_getSize(qrcode);
|
||||
const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2);
|
||||
const int paddingY = floor(float(displays[dispNum].height() - (size * 4)) / 2);
|
||||
const int padding = floor(float(display.width() - (size * 4)) / 2);
|
||||
const int paddingY = floor(float(display.height() - (size * 4)) / 2);
|
||||
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
display.setRotation(2);
|
||||
display.setPartialWindow(0, 0, display.width(),
|
||||
display.height());
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
|
||||
for (int y = 0; y < size * 4; y++) {
|
||||
for (int x = 0; x < size * 4; x++) {
|
||||
displays[dispNum].drawPixel(
|
||||
display.drawPixel(
|
||||
padding + x, paddingY + y,
|
||||
qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4))
|
||||
? GxEPD_BLACK
|
||||
|
@ -449,10 +434,10 @@ void EPDManager::updateDisplayTask(void* pvParameters) noexcept {
|
|||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
std::lock_guard<std::mutex> lock(instance.displayMutexes[epdIndex]);
|
||||
{
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
instance.displays[epdIndex].init(0, false, 40);
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
instance.initializeDisplay(epdIndex);
|
||||
|
||||
|
||||
uint32_t count = 0;
|
||||
while (instance.EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) {
|
||||
|
@ -469,8 +454,8 @@ void EPDManager::updateDisplayTask(void* pvParameters) noexcept {
|
|||
|
||||
char tries = 0;
|
||||
while (tries < 3) {
|
||||
if (instance.displays[epdIndex].displayWithReturn(updatePartial)) {
|
||||
instance.displays[epdIndex].powerOff();
|
||||
if (instance.display.displayWithReturn(updatePartial)) {
|
||||
instance.display.powerOff();
|
||||
instance.currentContent[epdIndex] = instance.content[epdIndex];
|
||||
if (!updatePartial) {
|
||||
instance.lastFullRefresh[epdIndex] = millis();
|
||||
|
@ -534,4 +519,15 @@ void EPDManager::prepareDisplayUpdateTask(void* pvParameters) {
|
|||
xTaskNotifyGive(instance.tasks[epdIndex]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EPDManager::switchToDisplay(uint dispNum) {
|
||||
display.setCSPin(&EPD_CS[dispNum]);
|
||||
display.setRSTPin(&EPD_RESET[dispNum]);
|
||||
display.setBusyPin(&EPD_BUSY[dispNum]);
|
||||
}
|
||||
|
||||
void EPDManager::initializeDisplay(uint dispNum) {
|
||||
switchToDisplay(dispNum);
|
||||
display.init(0, false, 40);
|
||||
}
|
||||
|
|
|
@ -80,6 +80,8 @@ private:
|
|||
|
||||
static void updateDisplayTask(void* pvParameters) noexcept;
|
||||
static void prepareDisplayUpdateTask(void* pvParameters);
|
||||
void switchToDisplay(uint dispNum);
|
||||
void initializeDisplay(uint dispNum);
|
||||
|
||||
// Member variables
|
||||
std::array<String, NUM_SCREENS> currentContent;
|
||||
|
@ -119,8 +121,8 @@ private:
|
|||
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
|
||||
#endif
|
||||
|
||||
// Display array
|
||||
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, NUM_SCREENS> displays;
|
||||
// Single display instance
|
||||
GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT> display;
|
||||
|
||||
static constexpr size_t UPDATE_QUEUE_SIZE = 14;
|
||||
static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200;
|
||||
|
|
|
@ -535,7 +535,7 @@ void LedHandler::frontlightSetBrightness(uint brightness) {
|
|||
}
|
||||
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, brightness);
|
||||
flArray.setPWM(ledPin, 0, brightness);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -543,7 +543,7 @@ std::vector<uint16_t> LedHandler::frontlightGetStatus() {
|
|||
std::vector<uint16_t> statuses;
|
||||
for (int ledPin = 1; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
uint16_t a = 0, b = 0;
|
||||
flArray.getPWM(ledPin + 1, &a, &b);
|
||||
flArray.getPWM(ledPin, &a, &b);
|
||||
statuses.push_back(round(b - a / 4096));
|
||||
}
|
||||
return statuses;
|
||||
|
@ -576,7 +576,7 @@ void LedHandler::frontlightFadeInAll(int flDelayTime, bool staggered) {
|
|||
} else {
|
||||
for (int dutyCycle = 0; dutyCycle <= maxBrightness; dutyCycle += FL_FADE_STEP) {
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, dutyCycle);
|
||||
flArray.setPWM(ledPin, 0, dutyCycle);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ void LedHandler::frontlightFadeOutAll(int flDelayTime, bool staggered) {
|
|||
} else {
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= FL_FADE_STEP) {
|
||||
for (int ledPin = 0; ledPin <= NUM_SCREENS; ledPin++) {
|
||||
flArray.setPWM(ledPin + 1, 0, dutyCycle);
|
||||
flArray.setPWM(ledPin, 0, dutyCycle);
|
||||
}
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
|
@ -628,7 +628,7 @@ void LedHandler::frontlightFadeIn(uint num, int flDelayTime) {
|
|||
}
|
||||
|
||||
for (int dutyCycle = 0; dutyCycle <= preferences.getUInt("flMaxBrightness"); dutyCycle += 5) {
|
||||
flArray.setPWM(num + 1, 0, dutyCycle);
|
||||
flArray.setPWM(num, 0, dutyCycle);
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
|
@ -639,7 +639,7 @@ void LedHandler::frontlightFadeOut(uint num, int flDelayTime) {
|
|||
}
|
||||
|
||||
for (int dutyCycle = preferences.getUInt("flMaxBrightness"); dutyCycle >= 0; dutyCycle -= 5) {
|
||||
flArray.setPWM(num + 1, 0, dutyCycle);
|
||||
flArray.setPWM(num, 0, dutyCycle);
|
||||
vTaskDelay(pdMS_TO_TICKS(flDelayTime));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ const char* PoolFactory::MINING_POOL_NAME_NODERUNNERS = "noderunners";
|
|||
const char* PoolFactory::MINING_POOL_NAME_BRAIINS = "braiins";
|
||||
const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio";
|
||||
const char* PoolFactory::MINING_POOL_NAME_PUBLIC_POOL = "public_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_LOCAL_PUBLIC_POOL = "local_public_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_GOBRRR_POOL = "gobrrr_pool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool";
|
||||
const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_ckpool";
|
||||
|
@ -18,7 +17,6 @@ std::unique_ptr<MiningPoolInterface> PoolFactory::createPool(const std::string&
|
|||
{MINING_POOL_NAME_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }},
|
||||
{MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }},
|
||||
{MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique<PublicPool>(); }},
|
||||
{MINING_POOL_NAME_LOCAL_PUBLIC_POOL, []() { return std::make_unique<LocalPublicPool>(); }},
|
||||
{MINING_POOL_NAME_GOBRRR_POOL, []() { return std::make_unique<GoBrrrPool>(); }},
|
||||
{MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }},
|
||||
{MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "ocean/ocean_pool.hpp"
|
||||
#include "satoshi_radio/satoshi_radio_pool.hpp"
|
||||
#include "public_pool/public_pool.hpp"
|
||||
#include "public_pool/local_public_pool.hpp"
|
||||
#include "gobrrr_pool/gobrrr_pool.hpp"
|
||||
#include "ckpool/ckpool.hpp"
|
||||
#include "ckpool/eu_ckpool.hpp"
|
||||
|
@ -29,7 +28,6 @@ class PoolFactory {
|
|||
MINING_POOL_NAME_SATOSHI_RADIO,
|
||||
MINING_POOL_NAME_BRAIINS,
|
||||
MINING_POOL_NAME_PUBLIC_POOL,
|
||||
MINING_POOL_NAME_LOCAL_PUBLIC_POOL,
|
||||
MINING_POOL_NAME_GOBRRR_POOL,
|
||||
MINING_POOL_NAME_CKPOOL,
|
||||
MINING_POOL_NAME_EU_CKPOOL
|
||||
|
@ -57,7 +55,6 @@ class PoolFactory {
|
|||
static const char* MINING_POOL_NAME_BRAIINS;
|
||||
static const char* MINING_POOL_NAME_SATOSHI_RADIO;
|
||||
static const char* MINING_POOL_NAME_PUBLIC_POOL;
|
||||
static const char* MINING_POOL_NAME_LOCAL_PUBLIC_POOL;
|
||||
static const char* MINING_POOL_NAME_GOBRRR_POOL;
|
||||
static const char* MINING_POOL_NAME_CKPOOL;
|
||||
static const char* MINING_POOL_NAME_EU_CKPOOL;
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
#include "local_public_pool.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/defaults.hpp"
|
||||
|
||||
std::string LocalPublicPool::getEndpoint() const {
|
||||
return preferences.getString("localPoolEndpoint", DEFAULT_LOCAL_POOL_ENDPOINT).c_str();
|
||||
}
|
||||
|
||||
std::string LocalPublicPool::getApiUrl() const {
|
||||
return "http://" + getEndpoint() + "/api/client/" + poolUser;
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "public_pool.hpp"
|
||||
|
||||
class LocalPublicPool : public PublicPool {
|
||||
public:
|
||||
std::string getApiUrl() const override;
|
||||
std::string getDisplayLabel() const override { return "LOCAL/POOL"; }
|
||||
private:
|
||||
std::string getEndpoint() const;
|
||||
};
|
|
@ -41,7 +41,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify)
|
|||
{relay},
|
||||
{// First filter
|
||||
{
|
||||
{"kinds", {"12203"}},
|
||||
{"kinds", {"1"}},
|
||||
{"since", {String(getMinutesAgo(60))}},
|
||||
{"authors", {pubKey}},
|
||||
}},
|
||||
|
@ -79,9 +79,8 @@ void nostrTask(void *pvParameters)
|
|||
{
|
||||
DataSourceType dataSource = getDataSource();
|
||||
if(dataSource == NOSTR_SOURCE) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
int blockFetch = blockNotify.fetchLatestBlock();
|
||||
blockNotify.processNewBlock(blockFetch);
|
||||
int blockFetch = getBlockFetch();
|
||||
processNewBlock(blockFetch);
|
||||
}
|
||||
|
||||
while (1)
|
||||
|
@ -146,7 +145,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
|
|||
// Use direct value access instead of multiple comparisons
|
||||
String typeValue;
|
||||
uint medianFee = 0;
|
||||
uint blockHeight = 0;
|
||||
|
||||
for (JsonArray tag : tags) {
|
||||
if (tag.size() != 2) continue;
|
||||
|
@ -167,11 +165,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
|
|||
medianFee = tag[1].as<uint>();
|
||||
}
|
||||
break;
|
||||
case 'b': // blockHeight
|
||||
if (strcmp(key, "block") == 0) {
|
||||
blockHeight = tag[1].as<uint>();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,19 +172,13 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
|
|||
if (!typeValue.isEmpty()) {
|
||||
if (typeValue == "priceUsd") {
|
||||
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
|
||||
if (blockHeight != 0) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlock(blockHeight);
|
||||
}
|
||||
}
|
||||
else if (typeValue == "blockHeight") {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlock(obj["content"].as<uint>());
|
||||
processNewBlock(obj["content"].as<uint>());
|
||||
}
|
||||
|
||||
if (medianFee != 0) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.processNewBlockFee(medianFee);
|
||||
processNewBlockFee(medianFee);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ void onOTAStart()
|
|||
ButtonHandler::suspendTask();
|
||||
|
||||
// stopWebServer();
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.stop();
|
||||
stopBlockNotify();
|
||||
stopPriceNotify();
|
||||
}
|
||||
|
||||
void handleOTATask(void *parameter)
|
||||
|
|
|
@ -2,64 +2,103 @@
|
|||
|
||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
||||
|
||||
WebSocketsClient webSocket;
|
||||
// WebsocketsClient client;
|
||||
esp_websocket_client_handle_t clientPrice = NULL;
|
||||
esp_websocket_client_config_t config;
|
||||
uint currentPrice = 90000;
|
||||
unsigned long int lastPriceUpdate;
|
||||
bool priceNotifyInit = false;
|
||||
std::map<char, std::uint64_t> currencyMap;
|
||||
std::map<char, unsigned long int> lastUpdateMap;
|
||||
TaskHandle_t priceNotifyTaskHandle;
|
||||
|
||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
WebSocketsClient priceNotifyWs;
|
||||
|
||||
void setupPriceNotify()
|
||||
{
|
||||
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin");
|
||||
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) {
|
||||
onWebsocketPriceEvent(type, payload, length);
|
||||
});
|
||||
webSocket.setReconnectInterval(5000);
|
||||
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||
config = {.uri = wsServerPrice,
|
||||
.user_agent = USER_AGENT};
|
||||
config.cert_pem = isrg_root_x1cert;
|
||||
|
||||
setupPriceNotifyTask();
|
||||
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.println(F("Price WS Connection Closed"));
|
||||
break;
|
||||
case WStype_CONNECTED:
|
||||
{
|
||||
Serial.println("Connected to " + String(wsServerPrice));
|
||||
priceNotifyInit = true;
|
||||
break;
|
||||
}
|
||||
case WStype_TEXT:
|
||||
{
|
||||
JsonDocument doc;
|
||||
deserializeJson(doc, (char *)payload);
|
||||
|
||||
if (doc["bitcoin"].is<JsonObject>())
|
||||
{
|
||||
if (currentPrice != doc["bitcoin"].as<long>())
|
||||
{
|
||||
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD);
|
||||
}
|
||||
}
|
||||
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(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)
|
||||
{
|
||||
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
|
||||
|
||||
switch (event_id)
|
||||
{
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
Serial.println("Connected to " + String(config.uri) + " WebSocket");
|
||||
priceNotifyInit = true;
|
||||
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DATA:
|
||||
onWebsocketPriceMessage(data);
|
||||
break;
|
||||
case WEBSOCKET_EVENT_ERROR:
|
||||
Serial.println(F("Price WS Connnection error"));
|
||||
break;
|
||||
case WEBSOCKET_EVENT_DISCONNECTED:
|
||||
Serial.println(F("Price WS Connnection Closed"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data)
|
||||
{
|
||||
JsonDocument doc;
|
||||
|
||||
deserializeJson(doc, (char *)event_data->data_ptr);
|
||||
|
||||
if (doc.containsKey("bitcoin"))
|
||||
{
|
||||
if (currentPrice != doc["bitcoin"].as<long>())
|
||||
{
|
||||
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void processNewPrice(uint newPrice, char currency)
|
||||
|
@ -136,7 +175,9 @@ void setPrice(uint newPrice, char currency)
|
|||
|
||||
bool isPriceNotifyConnected()
|
||||
{
|
||||
return webSocket.isConnected();
|
||||
if (clientPrice == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(clientPrice);
|
||||
}
|
||||
|
||||
bool getPriceNotifyInit()
|
||||
|
@ -146,30 +187,24 @@ bool getPriceNotifyInit()
|
|||
|
||||
void stopPriceNotify()
|
||||
{
|
||||
webSocket.disconnect();
|
||||
if (priceNotifyTaskHandle != NULL) {
|
||||
vTaskDelete(priceNotifyTaskHandle);
|
||||
priceNotifyTaskHandle = NULL;
|
||||
}
|
||||
if (clientPrice == NULL)
|
||||
return;
|
||||
esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
|
||||
esp_websocket_client_stop(clientPrice);
|
||||
esp_websocket_client_destroy(clientPrice);
|
||||
|
||||
clientPrice = NULL;
|
||||
}
|
||||
|
||||
void restartPriceNotify()
|
||||
{
|
||||
stopPriceNotify();
|
||||
setupPriceNotify();
|
||||
}
|
||||
|
||||
void taskPriceNotify(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
if (clientPrice == NULL)
|
||||
{
|
||||
webSocket.loop();
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
setupPriceNotify();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void setupPriceNotifyTask()
|
||||
{
|
||||
xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&priceNotifyTaskHandle);
|
||||
// esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
|
||||
// esp_websocket_client_stop(clientPrice);
|
||||
// esp_websocket_client_start(clientPrice);
|
||||
}
|
|
@ -2,22 +2,24 @@
|
|||
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <WebSocketsClient.h>
|
||||
#include <esp_websocket_client.h>
|
||||
#include "block_notify.hpp"
|
||||
#include <string>
|
||||
|
||||
#include "lib/screen_handler.hpp"
|
||||
|
||||
extern TaskHandle_t priceNotifyTaskHandle;
|
||||
|
||||
void setupPriceNotify();
|
||||
void setupPriceNotifyTask();
|
||||
void taskPriceNotify(void *pvParameters);
|
||||
|
||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
||||
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);
|
||||
void setPrice(uint newPrice, char currency);
|
||||
|
||||
//void processNewPrice(uint newPrice);
|
||||
void processNewPrice(uint newPrice, char currency);
|
||||
|
||||
bool isPriceNotifyConnected();
|
||||
|
|
|
@ -251,8 +251,9 @@ void workerTask(void *pvParameters) {
|
|||
} else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) {
|
||||
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
||||
} else {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseMarketCap(blockNotify.getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||
taskEpdContent =
|
||||
parseMarketCap(getBlockHeight(), price, currency,
|
||||
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||
}
|
||||
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
|
@ -260,19 +261,16 @@ void workerTask(void *pvParameters) {
|
|||
}
|
||||
case TASK_FEE_UPDATE: {
|
||||
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(blockNotify.getBlockMedianFee()));
|
||||
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
|
||||
EPDManager::getInstance().setContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_BLOCK_UPDATE: {
|
||||
if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseBlockHeight(blockNotify.getBlockHeight());
|
||||
taskEpdContent = parseBlockHeight(getBlockHeight());
|
||||
} else {
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
taskEpdContent = parseHalvingCountdown(blockNotify.getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
|
||||
taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
|
||||
}
|
||||
|
||||
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
|
||||
|
|
|
@ -40,39 +40,39 @@
|
|||
// "MrY=\n"
|
||||
// "-----END CERTIFICATE-----\n";
|
||||
|
||||
// const char* isrg_root_x1cert = 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";
|
||||
const char* isrg_root_x1cert = R"EOF(
|
||||
-----BEGIN CERTIFICATE-----
|
||||
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
|
||||
-----END CERTIFICATE-----
|
||||
)EOF";
|
||||
|
||||
|
||||
#ifdef TEST_SCREENS
|
||||
|
|
|
@ -68,7 +68,7 @@ const int usPerSecond = 1000000;
|
|||
const int usPerMinute = 60 * usPerSecond;
|
||||
|
||||
// extern const char *github_root_ca;
|
||||
// extern const char *isrg_root_x1cert;
|
||||
extern const char *isrg_root_x1cert;
|
||||
|
||||
extern const uint8_t rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start");
|
||||
// extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start");
|
||||
|
|
|
@ -127,33 +127,24 @@ namespace V2Notify
|
|||
|
||||
void handleV2Message(JsonDocument doc)
|
||||
{
|
||||
if (doc["blockheight"].is<uint>())
|
||||
if (doc.containsKey("blockheight"))
|
||||
{
|
||||
uint newBlockHeight = doc["blockheight"].as<uint>();
|
||||
|
||||
if (newBlockHeight == BlockNotify::getInstance().getBlockHeight())
|
||||
if (newBlockHeight == getBlockHeight())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.print(F("processNewBlock "));
|
||||
Serial.println(newBlockHeight);
|
||||
}
|
||||
BlockNotify::getInstance().processNewBlock(newBlockHeight);
|
||||
processNewBlock(newBlockHeight);
|
||||
}
|
||||
else if (doc["blockfee"].is<uint>())
|
||||
else if (doc.containsKey("blockfee"))
|
||||
{
|
||||
uint medianFee = doc["blockfee"].as<uint>();
|
||||
|
||||
if (debugLogEnabled()) {
|
||||
Serial.print(F("processNewBlockFee "));
|
||||
Serial.println(medianFee);
|
||||
}
|
||||
|
||||
BlockNotify::getInstance().processNewBlockFee(medianFee);
|
||||
processNewBlockFee(medianFee);
|
||||
}
|
||||
else if (doc["price"].is<JsonObject>())
|
||||
else if (doc.containsKey("price"))
|
||||
{
|
||||
|
||||
// Iterate through the key-value pairs of the "price" object
|
||||
|
@ -172,7 +163,7 @@ namespace V2Notify
|
|||
for (;;)
|
||||
{
|
||||
webSocket.loop();
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
static const char* JSON_CONTENT = "application/json";
|
||||
|
||||
static const char *const PROGMEM strSettings[] = {
|
||||
"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName", "localPoolEndpoint"};
|
||||
"hostnamePrefix", "mempoolInstance", "nostrPubKey", "nostrRelay", "bitaxeHostname", "miningPoolName", "miningPoolUser", "nostrZapPubkey", "httpAuthUser", "httpAuthPass", "gitReleaseUrl", "poolLogosUrl", "ceEndpoint", "fontName"};
|
||||
|
||||
static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"};
|
||||
|
||||
|
@ -30,8 +30,7 @@ TaskHandle_t eventSourceTaskHandle;
|
|||
void setupWebserver()
|
||||
{
|
||||
events.onConnect([](AsyncEventSourceClient *client)
|
||||
{ client->send("welcome", NULL, millis(), 1000);
|
||||
});
|
||||
{ client->send("welcome", NULL, millis(), 1000); });
|
||||
server.addHandler(&events);
|
||||
|
||||
AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
|
||||
|
@ -248,8 +247,7 @@ JsonDocument getStatusObject()
|
|||
JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
|
||||
|
||||
conStatus["price"] = isPriceNotifyConnected();
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
conStatus["blocks"] = blockNotify.isConnected();
|
||||
conStatus["blocks"] = isBlockNotifyConnected();
|
||||
conStatus["V2"] = V2Notify::isV2NotifyConnected();
|
||||
conStatus["nostr"] = nostrConnected();
|
||||
|
||||
|
@ -307,18 +305,14 @@ JsonDocument getLedStatusObject()
|
|||
void eventSourceUpdate() {
|
||||
if (!events.count()) return;
|
||||
|
||||
static JsonDocument doc;
|
||||
doc.clear();
|
||||
|
||||
JsonDocument root = getStatusObject();
|
||||
|
||||
root["leds"] = getLedStatusObject()["data"];
|
||||
JsonDocument doc = getStatusObject();
|
||||
doc["leds"] = getLedStatusObject()["data"];
|
||||
|
||||
// Get current EPD content directly as array
|
||||
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent();
|
||||
|
||||
// Add EPD content arrays
|
||||
JsonArray data = root["data"].to<JsonArray>();
|
||||
JsonArray data = doc["data"].to<JsonArray>();
|
||||
|
||||
// Copy array elements directly
|
||||
for(const auto& content : epdContent) {
|
||||
|
@ -326,7 +320,7 @@ void eventSourceUpdate() {
|
|||
}
|
||||
|
||||
String buffer;
|
||||
serializeJson(root, buffer);
|
||||
serializeJson(doc, buffer);
|
||||
events.send(buffer.c_str(), "status");
|
||||
}
|
||||
|
||||
|
@ -618,15 +612,15 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
|||
}
|
||||
|
||||
// Handle DND settings
|
||||
if (settings["dnd"].is<JsonObject>()) {
|
||||
if (settings.containsKey("dnd")) {
|
||||
JsonObject dndObj = settings["dnd"];
|
||||
auto& ledHandler = getLedHandler();
|
||||
|
||||
if (dndObj["timeBasedEnabled"].is<bool>()) {
|
||||
if (dndObj.containsKey("timeBasedEnabled")) {
|
||||
ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as<bool>());
|
||||
}
|
||||
if (dndObj["startHour"].is<uint8_t>() && dndObj["startMinute"].is<uint8_t>() &&
|
||||
dndObj["endHour"].is<uint8_t>() && dndObj["endMinute"].is<uint8_t>()) {
|
||||
if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") &&
|
||||
dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) {
|
||||
ledHandler.setDNDTimeRange(
|
||||
dndObj["startHour"].as<uint8_t>(),
|
||||
dndObj["startMinute"].as<uint8_t>(),
|
||||
|
@ -701,9 +695,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
|||
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
root["mempoolSecure"] = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE);
|
||||
|
||||
// Local pool settings
|
||||
root["localPoolEndpoint"] = preferences.getString("localPoolEndpoint", DEFAULT_LOCAL_POOL_ENDPOINT);
|
||||
|
||||
// Nostr settings (used for NOSTR_SOURCE or when zapNotify is enabled)
|
||||
root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB);
|
||||
root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY);
|
||||
|
@ -915,7 +906,7 @@ void onApiStopDataSources(AsyncWebServerRequest *request)
|
|||
request->beginResponseStream(JSON_CONTENT);
|
||||
|
||||
stopPriceNotify();
|
||||
BlockNotify::getInstance().stop();
|
||||
stopBlockNotify();
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -926,7 +917,9 @@ void onApiRestartDataSources(AsyncWebServerRequest *request)
|
|||
request->beginResponseStream(JSON_CONTENT);
|
||||
|
||||
restartPriceNotify();
|
||||
BlockNotify::getInstance().restart();
|
||||
restartBlockNotify();
|
||||
// setupPriceNotify();
|
||||
// setupBlockNotify();
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
@ -1258,4 +1251,25 @@ void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len,
|
|||
pixels.show();
|
||||
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiSettings(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
{
|
||||
JsonObject settings = json.as<JsonObject>();
|
||||
auto& ledHandler = getLedHandler();
|
||||
|
||||
if (settings.containsKey("dnd")) {
|
||||
JsonObject dndObj = settings["dnd"];
|
||||
if (dndObj.containsKey("timeBasedEnabled")) {
|
||||
ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as<bool>());
|
||||
}
|
||||
if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") &&
|
||||
dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) {
|
||||
ledHandler.setDNDTimeRange(
|
||||
dndObj["startHour"].as<uint8_t>(),
|
||||
dndObj["startMinute"].as<uint8_t>(),
|
||||
dndObj["endHour"].as<uint8_t>(),
|
||||
dndObj["endMinute"].as<uint8_t>());
|
||||
}
|
||||
}
|
||||
}
|
20
src/main.cpp
20
src/main.cpp
|
@ -19,7 +19,6 @@
|
|||
#include "ESPAsyncWebServer.h"
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/block_notify.hpp"
|
||||
|
||||
uint wifiLostConnection;
|
||||
uint priceNotifyLostConnection = 0;
|
||||
|
@ -50,8 +49,7 @@ void handleBlockNotifyDisconnection() {
|
|||
|
||||
if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout
|
||||
Serial.println(F("Block notification connection lost for 5 minutes, restarting handler..."));
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
blockNotify.restart();
|
||||
restartBlockNotify();
|
||||
blockNotifyLostConnection = 0;
|
||||
}
|
||||
}
|
||||
|
@ -94,14 +92,13 @@ void checkWiFiConnection() {
|
|||
|
||||
void checkMissedBlocks() {
|
||||
Serial.println(F("Long time (45 min) since last block, checking if I missed anything..."));
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
int currentBlock = blockNotify.fetchLatestBlock();
|
||||
int currentBlock = getBlockFetch();
|
||||
if (currentBlock != -1) {
|
||||
if (currentBlock != blockNotify.getBlockHeight()) {
|
||||
if (currentBlock != getBlockHeight()) {
|
||||
Serial.println(F("Detected stuck block height... restarting block handler."));
|
||||
blockNotify.restart();
|
||||
restartBlockNotify();
|
||||
}
|
||||
blockNotify.setLastBlockUpdate(getUptime());
|
||||
setLastBlockUpdate(getUptime());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,10 +111,9 @@ void monitorDataConnections() {
|
|||
}
|
||||
|
||||
// Block notification monitoring
|
||||
auto& blockNotify = BlockNotify::getInstance();
|
||||
if (blockNotify.isInitialized() && !blockNotify.isConnected()) {
|
||||
if (getBlockNotifyInit() && !isBlockNotifyConnected()) {
|
||||
handleBlockNotifyDisconnection();
|
||||
} else if (blockNotifyLostConnection > 0 && blockNotify.isConnected()) {
|
||||
} else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) {
|
||||
blockNotifyLostConnection = 0;
|
||||
}
|
||||
|
||||
|
@ -129,7 +125,7 @@ void monitorDataConnections() {
|
|||
}
|
||||
|
||||
// Check for missed blocks
|
||||
if ((blockNotify.getLastBlockUpdate() - getUptime()) > 45 * 60) {
|
||||
if ((getLastBlockUpdate() - getUptime()) > 45 * 60) {
|
||||
checkMissedBlocks();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue