Compare commits

..

1 commit

Author SHA1 Message Date
a5cab3d4ac
Use compressed icons 2025-01-05 20:07:24 +01:00
36 changed files with 2446 additions and 2814 deletions

2
data

@ -1 +1 @@
Subproject commit 0116cd68cdfdf383823f74e0f9665a1700cf0500 Subproject commit 033fe098295ab6da6568d6298b4380e51bec0b98

View file

@ -4,6 +4,6 @@ dependencies:
source: source:
type: idf type: idf
version: 4.4.7 version: 4.4.7
manifest_hash: 1d4ef353a86901733b106a1897b186dbf9fc091a4981f0560ea2f6899b7a3d44 manifest_hash: cd2f3ee15e776d949eb4ea4eddc8f39b30c2a7905050850eed01ab4928143cff
target: esp32s3 target: esp32s3
version: 1.0.0 version: 1.0.0

View file

@ -15,7 +15,7 @@ default_envs = lolin_s3_mini_213epd, lolin_s3_mini_29epd, btclock_rev_b_213epd,
[env] [env]
[btclock_base] [btclock_base]
platform = espressif32 @ ^6.10.0 platform = espressif32 @ ^6.9.0
framework = arduino, espidf framework = arduino, espidf
monitor_speed = 115200 monitor_speed = 115200
monitor_filters = esp32_exception_decoder, colorize monitor_filters = esp32_exception_decoder, colorize
@ -30,17 +30,17 @@ build_flags =
-DLAST_BUILD_TIME=$UNIX_TIME -DLAST_BUILD_TIME=$UNIX_TIME
-DARDUINO_USB_CDC_ON_BOOT -DARDUINO_USB_CDC_ON_BOOT
-DCORE_DEBUG_LEVEL=0 -DCORE_DEBUG_LEVEL=0
-D CONFIG_ASYNC_TCP_STACK_SIZE=16384 -D DEFAULT_BOOT_TEXT=\"BTCLOCK\"
-fexceptions -fexceptions
build_unflags = build_unflags =
-Werror=all -Werror=all
-fno-exceptions -fno-exceptions
lib_deps = lib_deps =
https://github.com/joltwallet/esp_littlefs.git#v1.16.4 https://github.com/joltwallet/esp_littlefs.git
bblanchon/ArduinoJson@^7.3.0 bblanchon/ArduinoJson@^7.2.1
esp32async/ESPAsyncWebServer @ 3.7.0 mathieucarbou/ESPAsyncWebServer @ 3.3.23
robtillaart/MCP23017@^0.9.0 robtillaart/MCP23017@^0.8.0
adafruit/Adafruit NeoPixel@^1.12.4 adafruit/Adafruit NeoPixel@^1.12.3
https://github.com/dsbaars/universal_pin#feature/mcp23017_rt https://github.com/dsbaars/universal_pin#feature/mcp23017_rt
https://github.com/dsbaars/GxEPD2#universal_pin https://github.com/dsbaars/GxEPD2#universal_pin
https://github.com/tzapu/WiFiManager.git#v2.0.17 https://github.com/tzapu/WiFiManager.git#v2.0.17
@ -79,10 +79,9 @@ build_flags =
-D I2C_SDA_PIN=35 -D I2C_SDA_PIN=35
-D I2C_SCK_PIN=36 -D I2C_SCK_PIN=36
-D HAS_FRONTLIGHT -D HAS_FRONTLIGHT
-D PCA_OE_PIN=48 -D PCA_OE_PIN=45
-D PCA_I2C_ADDR=0x42 -D PCA_I2C_ADDR=0x42
-D IS_HW_REV_B -D IS_HW_REV_B
lib_deps = lib_deps =
${btclock_base.lib_deps} ${btclock_base.lib_deps}
robtillaart/PCA9685@^0.7.1 robtillaart/PCA9685@^0.7.1
@ -101,7 +100,6 @@ build_flags =
-D USE_QR -D USE_QR
-D VERSION_EPD_2_13 -D VERSION_EPD_2_13
-D HW_REV=\"REV_A_EPD_2_13\" -D HW_REV=\"REV_A_EPD_2_13\"
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
platform_packages = platform_packages =
platformio/tool-mklittlefs@^1.203.210628 platformio/tool-mklittlefs@^1.203.210628
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216
@ -114,7 +112,6 @@ build_flags =
-D USE_QR -D USE_QR
-D VERSION_EPD_2_13 -D VERSION_EPD_2_13
-D HW_REV=\"REV_B_EPD_2_13\" -D HW_REV=\"REV_B_EPD_2_13\"
-D CONFIG_ARDUINO_MAIN_TASK_STACK_SIZE=16384
platform_packages = platform_packages =
platformio/tool-mklittlefs@^1.203.210628 platformio/tool-mklittlefs@^1.203.210628
earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216 earlephilhower/tool-mklittlefs-rp2040-earlephilhower@^5.100300.230216

View file

@ -1,235 +1,201 @@
#pragma once const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#include <Adafruit_GFX.h> 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
#include <Arduino.h> 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
#include "fonts.hpp" 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00,
const uint8_t Satoshi_Symbol90pt7bBitmaps_Gzip[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x63, 0x60, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x60, 0x60, 0xe0, 0xff, 0xc7, 0x00, 0x05, 0xcc, 0xff, 0x1b, 0x60, 0xcc, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0x0f, 0x60, 0x2c, 0xfb, 0x1f, 0x30, 0xd6, 0x60, 0x53, 0x38, 0x28, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
0x81, 0xfd, 0x7f, 0x3a, 0x83, 0x81, 0xf6, 0x30, 0x1a, 0xe0, 0xa7, 0xb7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00,
0xff, 0x0f, 0x0c, 0xb4, 0x8f, 0x51, 0x01, 0x33, 0xbd, 0xfd, 0xff, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00,
0xa0, 0x7d, 0x8c, 0x17, 0x0c, 0x8e, 0x92, 0x82, 0x44, 0x85, 0x54, 0x8f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
0x23, 0x88, 0xe1, 0xec, 0xff, 0xa1, 0x56, 0xf2, 0xff, 0xff, 0x03, 0x61, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc8, 0xff, 0x87, 0x3a, 0xc7, 0x1e, 0x16, 0x8d, 0xf5, 0x30, 0xa7, 0xc2, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x12, 0x36, 0xe3, 0x7f, 0xa8, 0xeb, 0x98, 0x47, 0x8d, 0x19, 0x35, 0x66, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
0x78, 0x1b, 0x43, 0x65, 0xf0, 0x00, 0x00, 0xc7, 0x63, 0x9f, 0x4b, 0xde, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
}; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// unsigned int satoshi_bin_gz_len = 123; 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// const uint8_t Satoshi_Symbol90pt7bBitmaps[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00,
// 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F,
// 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFE, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x0F, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x03, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF,
// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00,
// 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00,
// 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00,
// 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00,
// 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00,
// 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00,
// 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8,
// 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00,
// 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80,
// 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
// 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00,
// 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00,
// 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00,
// 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00,
// 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
// 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
// 0x00, 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
// 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
// 0x0F, 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
// 0x00, 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
// 0x00, 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
// 0xFF, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
// 0x00, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0xFF, 0xE0 };
// 0x00, 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x07, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// 0x7F, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
// 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x00, 0x3F, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F,
// 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xC0, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00,
// 0x00, 0x03, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF,
// 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xFF, 0xFC, 0x00, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x1F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
// 0xFF, 0xE0 };
const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = { const GFXglyph Satoshi_Symbol90pt7bGlyphs[] PROGMEM = {
{ 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S' { 0, 82, 127, 99, 8, -126 }, { 1302, 71, 109, 93, 0, -117 } }; // 0x53 'S'
// const GFXfont Satoshi_Symbol90pt7b PROGMEM = { const GFXfont Satoshi_Symbol90pt7b PROGMEM = {
// (uint8_t *)Satoshi_Symbol90pt7bBitmaps, (uint8_t *)Satoshi_Symbol90pt7bBitmaps,
// (GFXglyph *)Satoshi_Symbol90pt7bGlyphs, (GFXglyph *)Satoshi_Symbol90pt7bGlyphs,
// 0x53, 0x53, 192 }; 0x53, 0x53, 192 };
// Font properties
static constexpr FontData Satoshi_Symbol90pt7b_Properties = {
Satoshi_Symbol90pt7bBitmaps_Gzip,
Satoshi_Symbol90pt7bGlyphs,
sizeof(Satoshi_Symbol90pt7bBitmaps_Gzip),
2270, // Original size
0x53, // First char
0x53, // Last char
192 // yAdvance
};
// Approx. 2284 bytes // Approx. 2284 bytes

View file

@ -1,542 +1,65 @@
#include "icons.h" #include "icons.h"
// 'lightning-bolt', 122x122px const unsigned char epd_icons_lightning_bolt[] PROGMEM = {
const unsigned char epd_icons_lightning_bolt [] PROGMEM = { 0x1f,0x8b,0x08,0x00,0xa5,0xc7,0x7a,0x67,0x02,0xff,0xbd,0xd5,0xb1,0x0d,0xc3,0x20,0x10,0x40,0x51,0x23,0x17,0x2e,0x19,0x81,0x51,0x18,0x0d,0x6f,0x16,0x46,0x61,0x04,0x97,0x14,0x08,0x92,0x60,0x25,0x24,0xd6,0x1d,0xbf,0xf3,0x75,0x4f,0x3a,0x8a,0xdf,0x70,0xad,0xfd,0x4d,0x6c,0x37,0xf9,0x71,0xb1,0x9f,0xbb,0x82,0x0b,0x38,0x83,0x0f,0x70,0x02,0x47,0xf0,0x0e,0x5e,0xe6,0xae,0xe0,0x02,0xce,0xe0,0x03,0x9c,0xc0,0x11,0xbc,0x83,0x97,0xb9,0x2b,0xb8,0xb0,0x5f,0xe3,0xbe,0xce,0x17,0x1f,0xdd,0x5e,0x75,0xea,0x0e,0xaa,0x63,0x77,0x53,0xbd,0xbf,0x69,0x74,0xf7,0xf5,0x55,0x75,0xed,0xde,0x54,0x9f,0x79,0x56,0xf5,0xc8,0x95,0x3d,0x72,0x65,0x8f,0x5c,0xd9,0x23,0x57,0xf6,0xc8,0x95,0x3d,0x72,0x45,0xff,0xe4,0x8a,0x3e,0x9f,0x58,0xb0,0x03,0x7b,0x70,0x00,0xb7,0xb9,0x0d,0x78,0x05,0x6f,0x60,0x0b,0x76,0x60,0xfa,0x8f,0x02,0xb8,0xcd,0x6d,0xc0,0x2b,0x78,0x03,0x5b,0xb0,0x03,0x7b,0x70,0xb8,0xfb,0x3e,0x7e,0xfc,0x04,0x18,0x55,0x3a,0x4a,0xa0,0x07,0x00,0x00
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
};
// 'rocket-launch', 122x122px
const unsigned char epd_icons_rocket_launch [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x07, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0x80, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xfe, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xf1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xc1, 0xf0, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0x03, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xfc, 0x03, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf0, 0x07, 0xc0, 0x00, 0x00, 0x07, 0xfe, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x80, 0x0f, 0x80, 0x00, 0x00, 0x03, 0xfc, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfe, 0x00, 0x0f, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf8, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x80, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x80, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf8, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xc0, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xfc, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xe0, 0x7e, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xc0, 0xff, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x81, 0xff, 0x80, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x03, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfe, 0x07, 0xe7, 0xe0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfc, 0x0f, 0xc3, 0xf0, 0x00, 0x00, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf8, 0x1f, 0x81, 0xf8, 0x00, 0x03, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf0, 0x3f, 0x00, 0xfc, 0x00, 0x0f, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x7e, 0x00, 0x7e, 0x00, 0x3f, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xc0, 0xfc, 0x00, 0x3f, 0x80, 0xff, 0x81, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x81, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x03, 0xf0, 0x00, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x07, 0xe0, 0x01, 0xf3, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x0f, 0xc0, 0x03, 0xe0, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x1f, 0x80, 0x07, 0xc0, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x3f, 0x00, 0x0f, 0x81, 0xff, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x7e, 0x00, 0x1f, 0x03, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfc, 0x00, 0x3e, 0x07, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf8, 0x00, 0x7c, 0x0f, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf0, 0x00, 0xf8, 0x1f, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x01, 0xf0, 0x3f, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xc0, 0x03, 0xe0, 0x7f, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x80, 0x07, 0xc0, 0xff, 0xff, 0xe0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x00, 0x0f, 0x81, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x00, 0x1f, 0x03, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x00, 0x3e, 0x07, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x00, 0x7c, 0x0f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x00, 0xf8, 0x1f, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x01, 0xf0, 0x3f, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
};
// 'pickaxe', 122x122px
const unsigned char epd_icons_pickaxe [] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x31, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xc7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xe0, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x7f, 0xf8, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xfd, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xf8, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xfe, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe0, 0x0f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf0, 0x07, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xe0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xc0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x80, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfe, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf8, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x80, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0x80, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xc0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xe0, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0
}; };
const unsigned char epd_icons_bitaxe_logo [] PROGMEM = { const unsigned char epd_icons_rocket_launch[] PROGMEM = {
// 'bitaxe_dark copy', 88x220px 0x1f,0x8b,0x08,0x00,0xa5,0xc7,0x7a,0x67,0x02,0xff,0xed,0xd4,0xb1,0x6e,0xc4,0x20,0x0c,0x06,0x60,0x47,0x0c,0x8c,0x3c,0x02,0x2f,0x52,0x5d,0x5e,0xab,0xc3,0xe9,0xc2,0xbd,0x19,0x55,0x5f,0x84,0xad,0x2b,0x55,0x17,0x2a,0x51,0x5c,0x43,0x0e,0x0c,0x5e,0x3a,0xde,0xd2,0x6c,0x9f,0x94,0xf8,0xb7,0xc1,0x0a,0xe2,0xf2,0x78,0x7c,0x96,0xa3,0x59,0x9c,0x01,0x8e,0xd9,0x1e,0x60,0x9f,0x0d,0xab,0xb3,0x70,0x14,0xf6,0xc2,0x8e,0x6c,0xd9,0x05,0x56,0x67,0xe1,0x28,0x1c,0x84,0xbd,0xb0,0x13,0x86,0xd5,0x45,0x38,0x0b,0x27,0xd8,0xd2,0xdc,0x6f,0x04,0x5d,0x66,0x07,0x30,0x38,0xdb,0xd3,0xb7,0x6e,0xb2,0x13,0xae,0xef,0x7a,0x3e,0xcf,0xf2,0x87,0xf3,0xe9,0x7e,0x1f,0x25,0xad,0xfe,0x8c,0xcd,0x5b,0xf7,0x9b,0xb0,0x0a,0x75,0x16,0xd7,0x9d,0x15,0x9d,0x0e,0xf5,0xab,0x1e,0x8e,0x9a,0x4c,0xf3,0x74,0x3b,0x43,0xa7,0xa5,0x32,0xe8,0xd3,0x05,0x4c,0x3b,0x3d,0x78,0xec,0x43,0x02,0x0b,0xb3,0x43,0xb7,0x3d,0xed,0xe0,0x72,0x7a,0xef,0x7e,0x59,0x1c,0xe0,0x7a,0xfa,0xe8,0xf5,0x1e,0xee,0xfb,0x07,0xaf,0x8d,0x5b,0xb7,0x4f,0xab,0x63,0xbb,0xfc,0xb3,0xdd,0x36,0xdf,0x69,0x3d,0x1c,0xb8,0xbd,0xc9,0x56,0x78,0x17,0x3e,0x84,0x71,0xf5,0x86,0x6b,0x9e,0x1a,0xce,0x91,0xe3,0xaa,0x53,0xe2,0xb8,0xd6,0xef,0x95,0xe3,0xaa,0xc3,0x8d,0xcb,0xb7,0xf9,0x90,0xcb,0x57,0xdf,0xeb,0xb6,0x6a,0xb6,0x42,0x3f,0xca,0xd7,0xfb,0xd0,0x1f,0x61,0x94,0x23,0x67,0xf3,0x4e,0x0d,0xe0,0xd1,0x9d,0xec,0x3d,0x81,0x2a,0xc3,0x71,0x87,0x0c,0x26,0x8d,0xf7,0x29,0xfe,0x06,0x7b,0x18,0xf6,0x19,0x76,0x47,0xa1,0xdd,0xf4,0xf5,0x81,0x85,0xfb,0x51,0x91,0x7a,0x4d,0x6c,0x1d,0xb6,0x2f,0x0c,0x6a,0xd8,0x78,0x15,0xd0,0xb1,0xad,0xd3,0x34,0x11,0xf7,0xbf,0x83,0xb9,0xcf,0xbe,0x81,0x55,0xb4,0x63,0xdc,0x3f,0x5c,0xf4,0x6c,0xda,0x07,0x83,0xce,0x0e,0x47,0x48,0x16,0x3d,0x3b,0x6c,0x91,0x96,0x9b,0xe7,0xa7,0xf8,0x03,0x03,0xbb,0xc6,0xcf,0xae,0xf1,0x18,0x0f,0x36,0xc5,0x2f,0xa6,0x78,0x8c,0xfc,0xff,0xab,0xf1,0x98,0x26,0x53,0x3c,0x7e,0xb3,0x6b,0x3c,0xfe,0x3c,0xff,0xff,0xfc,0xef,0xa7,0xf8,0x17,0xa1,0x5d,0x0c,0xd4,0xa0,0x07,0x00,0x00
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, };
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, const unsigned char epd_icons_pickaxe[] PROGMEM = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3e, 0xff, 0xff, 0xfd, 0xff, 0xff, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xed, 0xd3,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xb1, 0x71, 0xc5, 0x30, 0x08, 0x06, 0x60, 0x7c, 0x2e, 0x5c, 0x7a, 0x04,
0x00, 0xff, 0xff, 0xfe, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0xff, 0x00, 0xcf, 0x90, 0x09, 0x3c, 0x9a, 0x35, 0x1a, 0xa9, 0xb2, 0x86, 0xba, 0x94,
0x07, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x3f, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x51, 0xa9, 0x5c, 0x14, 0x2b, 0x08, 0x64, 0x09, 0xe8, 0x53, 0x25, 0xaf,
0xf8, 0x00, 0x3f, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x1f, 0xff, 0xff, 0xfb, 0xce, 0x98, 0x1f, 0xfc, 0xa4, 0x5a, 0xcd, 0x0f, 0xeb, 0x6f, 0xf8,
0xf0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0xff, 0xff, 0xdd, 0xf9, 0xd5, 0x19, 0x4f, 0xe7, 0xdd, 0x3a, 0x6c, 0xce, 0x8b, 0x35,
0xff, 0xf0, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xc0, 0x65, 0x9f, 0xc3, 0x61, 0x1c, 0x61, 0x37, 0x4e, 0xb0, 0x1a, 0x17,
0xff, 0xfc, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x58, 0x8c, 0xa9, 0xe1, 0x97, 0x71, 0x80, 0x97, 0x0f, 0xed, 0x08, 0xf0,
0xff, 0xff, 0xe0, 0x07, 0xf8, 0x7f, 0xff, 0xfd, 0xfc, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xfe, 0xa6, 0x9d, 0xa0, 0x77, 0xec, 0xce, 0xd0, 0x3b, 0x76, 0xdf, 0x00, 0xa0,
0x3f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0x4d, 0x01, 0x32, 0xf2, 0xe3, 0xe0, 0x8c, 0xae, 0x3e, 0xd9, 0x7e, 0x6d,
0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xcf, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x0f, 0x80, 0xea, 0xea, 0xfd, 0xfb, 0xa7, 0xab, 0x37, 0xcf, 0x93, 0x7b, 0x3f,
0xff, 0xe7, 0xff, 0xff, 0xf8, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0, 0x3b, 0x17, 0x57, 0x7f, 0xbb, 0x7e, 0xd5, 0xbb, 0x7f, 0xf2, 0x61, 0x94,
0x01, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xf3, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x4f, 0xfe, 0xec, 0xff, 0xfc, 0x05, 0xdd, 0xe5, 0xca, 0xb0, 0x29, 0xe7,
0x1f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xf3, 0x3b, 0xac, 0xca, 0xe9, 0xa8, 0xa8, 0x1d, 0xf7, 0x1a, 0x17, 0x65,
0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xdc, 0x68, 0x03, 0x65, 0x3a, 0x20, 0x59, 0x9b, 0xc2, 0x32, 0x2f, 0x80,
0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x7d, 0xfa, 0x83, 0x36, 0x9a, 0x2e, 0x34, 0xfc, 0xcd, 0x0b, 0x60, 0xdf,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfe, 0x32, 0xe6, 0xde, 0xbc, 0x50, 0x3f, 0x3f, 0x2d, 0x3b, 0x4c, 0xf3,
0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x6c, 0x61, 0x1f, 0xe6, 0xf3, 0x89, 0xd3, 0xbc, 0x6b, 0x1c, 0xbe, 0xb9,
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0x55, 0xdc, 0x1e, 0x17, 0x8e, 0x4a, 0xc3, 0x32, 0x6a, 0x1e, 0xf5, 0xb2,
0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x5a, 0x1e, 0xf3, 0xc8, 0xea, 0x65, 0xec, 0x87, 0xcf, 0xe9, 0xed, 0x9e,
0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xd7, 0x43, 0x3c, 0x4e, 0xbb, 0xf8, 0x1e, 0xb7, 0x41, 0x2c, 0xf1, 0xd3,
0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79, 0xdc, 0x1e, 0xb1, 0xc4, 0x4f, 0xc7, 0xc5, 0x5a, 0xc5, 0xb3, 0x55,
0xff, 0xfc, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe, 0x3c, 0x5b, 0xc5, 0x37, 0xeb, 0xf8, 0x66, 0x1d, 0xdf, 0xac, 0xe3, 0x9b,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0x75, 0x7c, 0xb3, 0x8e, 0x6f, 0xd6, 0xf1, 0xcd, 0x3a, 0xbe, 0x59, 0xc7,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x93, 0x4d, 0x3c, 0xd9, 0xc4, 0x93, 0x4d, 0x3c, 0x39, 0xe9, 0x38, 0x72,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x5c, 0xad, 0x71, 0xb3, 0x0e, 0xbb, 0xf3, 0xe1, 0xea, 0x4f, 0xeb, 0x78,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfe, 0x7f, 0x59, 0xa7, 0x6a, 0xfd, 0xe9, 0x5c, 0xff, 0xfd, 0x97, 0xfd, 0x03, 0x1c,
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xb6, 0xaf, 0x78, 0xa0, 0x07, 0x00, 0x00
0xff, 0xfc, 0x00, 0x00, 0x7f, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e, };
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x0f, 0xff,
0xff, 0xff, 0xf0, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, const unsigned char epd_icons_bitaxe_logo[] PROGMEM = {
0x3c, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x1f,0x8b,0x08,0x00,0xa5,0xc7,0x7a,0x67,0x02,0xff,0xa5,0x96,0x4d,0x6a,0xdc,0x40,0x10,0x85,0x7b,0xd0,0x62,0x36,0x81,0xbe,0x40,0xa0,0x73,0x90,0xe0,0xbe,0x4a,0x8e,0x10,0xc8,0xde,0x52,0xf0,0x22,0xcb,0x1c,0x21,0x47,0x89,0x42,0x0e,0x90,0x2b,0x68,0xe7,0xa5,0x65,0x66,0xe1,0x16,0xb4,0x54,0xae,0xdf,0x2e,0x8d,0x70,0x88,0x4d,0x04,0xf6,0x7c,0x8c,0xa4,0x56,0xbf,0x7a,0xf5,0x4a,0x03,0xf0,0xcf,0xa3,0x3a,0x6e,0xbd,0xe3,0x0d,0xc0,0xaa,0x18,0xf0,0xa2,0x10,0x0d,0x37,0xc1,0x1a,0xf0,0xe2,0x70,0x16,0xcc,0x00,0x23,0x63,0x21,0x9c,0x14,0x13,0xc0,0xdc,0x11,0xce,0x74,0x4b,0x51,0xc4,0x93,0xe5,0x24,0xd8,0xd1,0xbd,0x84,0x53,0x08,0xba,0x22,0xde,0x5c,0x7a,0x58,0x6b,0x66,0xdc,0xf0,0xa3,0xe2,0x32,0x30,0x46,0xc0,0x8f,0x72,0x16,0xfc,0xa3,0x4b,0x0c,0x11,0xee,0x0d,0x13,0x5c,0x70,0x49,0xc2,0x51,0x90,0x1e,0x37,0x27,0x58,0x14,0x4b,0x26,0x3d,0xbc,0xb5,0xcd,0x11,0x02,0x1f,0x8c,0x03,0x63,0x3c,0xe0,0xc8,0x98,0x0e,0x38,0x1d,0x31,0x1f,0x70,0x3e,0x62,0xdf,0xaa,0x6d,0x55,0x5e,0xaf,0x0a,0x0e,0x19,0x5e,0x7d,0xac,0x7e,0x7b,0x35,0x0b,0x33,0xd4,0x9e,0xbd,0x08,0x7d,0x26,0xb1,0x64,0x40,0xb8,0xd5,0x4d,0x2a,0x46,0xd9,0xcd,0x8d,0x2a,0x46,0xfc,0x88,0x78,0x92,0x9d,0xbf,0x47,0xec,0x44,0xe5,0x3b,0xbd,0x40,0xca,0xc0,0xb7,0x8d,0x8e,0xa2,0x52,0xd6,0x4d,0xac,0x8e,0x9e,0x86,0x36,0x89,0xd9,0xbc,0x17,0x29,0x2e,0x1f,0x3b,0x1c,0x77,0x18,0x5f,0x42,0x34,0xd4,0xb4,0xa1,0xa1,0xa6,0x0d,0x1f,0x65,0xda,0x82,0x6b,0x0b,0xae,0x2d,0xb8,0xb6,0xa0,0x2a,0x08,0x3f,0x35,0x6d,0xe1,0x73,0xd3,0x16,0x66,0xd7,0x56,0x9a,0xb6,0x53,0x91,0xc5,0xa6,0x08,0x8f,0x45,0x04,0xa1,0xb6,0xa5,0x8a,0x6f,0x95,0xdb,0xc8,0xb4,0xad,0xf0,0xa6,0x83,0x2f,0xdf,0x3c,0x6a,0x68,0x1a,0x7e,0xc5,0x82,0xb0,0x11,0x0b,0x88,0xa0,0xcd,0x05,0x55,0x17,0x54,0xbd,0x3d,0x15,0x4f,0xae,0xb8,0x73,0x3c,0xbb,0xf8,0x5d,0x1d,0x92,0x63,0x76,0xdf,0x24,0x64,0xf0,0x84,0x4b,0x4a,0xc8,0x28,0x2d,0x16,0xb2,0x8b,0x87,0xec,0xe2,0x21,0x5b,0x34,0x59,0x83,0xc7,0x69,0x64,0x7b,0x2c,0x64,0x28,0x64,0xd2,0x90,0xdd,0x26,0x0b,0x59,0x85,0x4e,0x1d,0xc7,0x74,0x0f,0x96,0xac,0x13,0x95,0x5b,0xb0,0xa3,0x2d,0x45,0x6d,0x81,0xc9,0xe2,0xc4,0x2d,0x25,0x98,0xa1,0x18,0xf6,0x50,0x2c,0x4e,0x3b,0x94,0x7e,0x3f,0x20,0x17,0x7a,0x3f,0xca,0xde,0x1a,0xb2,0x9f,0x8e,0xdf,0xdd,0xc2,0x6f,0x6e,0xe1,0x1d,0x34,0x0b,0x11,0x0b,0x57,0x52,0x0d,0xe4,0xfd,0x6a,0x6e,0x48,0x9b,0x16,0x9d,0xa7,0x5e,0x68,0x16,0x56,0x47,0xbb,0xaf,0x6b,0xc3,0x88,0xdd,0xf4,0x15,0x6c,0xb5,0xe4,0x98,0xdb,0x83,0xc1,0xb7,0xc3,0xc7,0x6f,0xdf,0xfa,0x05,0xfe,0xe3,0x58,0xdb,0xbf,0x96,0x42,0x74,0x1e,0x27,0xf3,0x62,0x7b,0xcf,0x58,0xf2,0x16,0xbd,0xa9,0x6f,0x8d,0x38,0xe6,0xd9,0xb4,0x0d,0x69,0x87,0x93,0xc9,0x1c,0xf3,0x68,0xd7,0x4e,0xb9,0x4d,0x98,0xb9,0x6f,0x32,0x17,0x1b,0x36,0x59,0x9a,0xcb,0x64,0x62,0x20,0x4d,0xe6,0xf6,0xea,0x61,0xf9,0x97,0xb7,0x5b,0x6e,0xf5,0x21,0xd4,0x27,0x6c,0x49,0x4d,0x55,0xc4,0x33,0x0f,0x6c,0x50,0x57,0xc4,0x8a,0x2a,0x83,0x82,0x0c,0xba,0x46,0x1a,0x2a,0x66,0xf1,0x2c,0x66,0x16,0x19,0x40,0x86,0x1f,0xc4,0xed,0xd9,0xba,0xe4,0x0a,0xad,0x49,0xb0,0x7f,0x29,0x3b,0x43,0xe4,0x87,0x33,0x26,0xce,0xe6,0xa8,0x58,0x22,0x4f,0xcb,0x20,0xef,0x42,0xba,0x8e,0x8a,0x84,0x6f,0x56,0x3a,0x39,0x64,0x8e,0x29,0x26,0x13,0x6b,0xcc,0x38,0x27,0x8e,0x0b,0xc5,0x94,0x86,0x0c,0xda,0x47,0x31,0x25,0x5d,0x55,0x92,0xdf,0x9a,0xf6,0xdc,0x3a,0x2e,0xec,0xbe,0x8d,0xad,0x51,0xf7,0x98,0x5a,0x27,0x87,0xe4,0x2a,0xb2,0xab,0xc8,0x66,0x20,0x09,0x1a,0x02,0x27,0x79,0x23,0xe4,0x11,0xc1,0x3f,0x22,0x78,0x2e,0xac,0x82,0xb1,0xe1,0x94,0xa4,0xf8,0x54,0xa8,0xdc,0xb0,0xf4,0x0d,0xab,0xa3,0xba,0xb9,0x75,0x6e,0x6c,0xe7,0x01,0x27,0xfc,0xe1,0xf8,0x20,0xf8,0x15,0xff,0x9e,0x1c,0x17,0x89,0xfa,0x2f,0x69,0x13,0xc2,0x89,0x4e,0xc9,0x6a,0x54,0x37,0x5d,0xa2,0x64,0xfc,0x95,0x71,0x2f,0x73,0x9c,0x4a,0x5f,0xbf,0xc8,0x7b,0xab,0x7f,0xb9,0xe5,0x9e,0x01,0x52,0xde,0x2e,0xf4,0x74,0x09,0x00,0x00
0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, };
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xf8, const size_t epd_icons_compressed_sizes[epd_icons_allArray_LEN] = {
0x1f, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf0, 0x03, 0xff, 331,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 381,
0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x07, 183,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 733
0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, };
0x0f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xfc, 0xff, 0xff,
0xff, 0xff, 0xfc, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, const size_t epd_icons_original_sizes[epd_icons_allArray_LEN] = {
0x00, 0x3f, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 1952, // 122x122 pixels / 8 bits per byte + padding
0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 1952,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 1952,
0x01, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0xc0, 2420 // 88x220 pixels / 8 bits per byte + padding
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0xf8, 0x00,
0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff,
0xe0, 0x0f, 0xff, 0xf1, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xf9, 0xfc,
0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xf9, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0x3f, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff,
0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xfe, 0x3f,
0xff, 0xf8, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1f, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff,
0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff,
0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xf7, 0xff, 0xff, 0xfc, 0x3f, 0xff,
0xff, 0xff, 0xe0, 0x07, 0xff, 0xf3, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff,
0xf3, 0xff, 0xff, 0xf8, 0x07, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xf3, 0xff, 0xff, 0xf8, 0x01,
0xff, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xf9, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xff, 0xff, 0x80, 0x1f,
0xff, 0xf9, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xff, 0xff, 0xc0, 0x1f, 0xff, 0xfc, 0xff, 0xff, 0xf0,
0x03, 0xff, 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xfe, 0x3f, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xf8,
0x3f, 0xff, 0x7e, 0x1f, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xfc, 0xff, 0x03, 0xff,
0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0x80, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff,
0xff, 0x80, 0x01, 0xff, 0xc0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x80, 0x03, 0xff, 0xe0,
0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff,
0xff, 0xff, 0xe0, 0x1f, 0xff, 0xf0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xff,
0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff,
0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff,
0xff, 0xfc, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x7f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x8f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0x87, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xfc, 0x7f, 0xff, 0xff,
0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xff, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0f, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xf8, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xf9, 0xff, 0xff, 0xf8, 0x7f,
0xff, 0xf9, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xf0, 0xff, 0xf8, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x07, 0xff, 0xc0, 0x3f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xf0,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0x80, 0x1f, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0xff, 0xc0, 0x3f, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xe0, 0x3f,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xf0, 0x7f, 0x80, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0xff, 0xf9, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff,
0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xfd,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff,
0xff, 0xfc, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x1f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff,
0xef, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x03, 0xf8, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfc, 0x00,
0x00, 0x01, 0xf8, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x01, 0xf8, 0x00, 0x00,
0x00, 0x07, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0xf8,
0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x60, 0x00,
0x00, 0x00, 0x03, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0xff, 0xff,
0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
0xff, 0xe0, 0x07, 0xff, 0xff, 0x80, 0x0f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xe0, 0x07, 0xff, 0xff,
0x80, 0x1f, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xc0, 0x07, 0xff, 0xff, 0x80, 0x1f, 0xff, 0xff, 0xf8,
0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0x00, 0x1f, 0xff, 0xff, 0xf8, 0x07, 0xff, 0x80, 0x0f, 0xff,
0xff, 0x00, 0x3f, 0xff, 0xff, 0xf8, 0x03, 0xff, 0x80, 0x1f, 0xff, 0xff, 0x80, 0x3f, 0xff, 0xff,
0xf0, 0x01, 0xff, 0xc0, 0x1f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xff, 0xf0, 0x01, 0xff, 0xf0, 0x1f,
0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xf0, 0x03, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xf8, 0x7f, 0xff,
0xff, 0xe0, 0x03, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xfe,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x07, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff,
0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xe0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0xff, 0x80, 0x00, 0xff, 0xff, 0xff, 0xe0, 0x3f, 0xfe, 0x00, 0x7f, 0xff, 0x80, 0x03, 0xff,
0xff, 0xff, 0xf8, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe,
0x00, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xfe, 0x00, 0xff, 0xff, 0xe0, 0x1f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff,
0xfe, 0x01, 0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfc,
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x01, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff,
0xff, 0xfe, 0x03, 0xff, 0xff, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff,
0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0x9f, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0x03, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff,
0xff, 0xff, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x81, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff,
0xbf, 0xff, 0xff, 0xff, 0xc1, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xff, 0xe0,
0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x7f, 0xff, 0xff, 0xff, 0x9f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xfd, 0xff, 0xff, 0xff, 0xff,
0xfe, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x73, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x7f, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff
}; };
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 8032)
const int epd_icons_allArray_LEN = 4;
const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = { const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN] = {
epd_icons_pickaxe, epd_icons_pickaxe,
epd_icons_rocket_launch, epd_icons_rocket_launch,
epd_icons_lightning_bolt, epd_icons_lightning_bolt,
epd_icons_bitaxe_logo epd_icons_bitaxe_logo
}; };

View file

@ -1,10 +1,13 @@
#pragma once #pragma once
#ifndef ICONS_H
#define ICONS_H
#include <Arduino.h> #include <Arduino.h>
extern const unsigned char* epd_icons_allArray[]; extern const unsigned char epd_icons_pickaxe[] PROGMEM;
extern const unsigned char epd_icons_rocket_launch[] PROGMEM;
extern const unsigned char epd_icons_lightning_bolt[] PROGMEM;
extern const unsigned char epd_icons_bitaxe_logo[] PROGMEM;
#endif // ICONS_H constexpr int epd_icons_allArray_LEN = 4;
extern const unsigned char* epd_icons_allArray[epd_icons_allArray_LEN];
extern const size_t epd_icons_original_sizes[epd_icons_allArray_LEN];
extern const size_t epd_icons_compressed_sizes[epd_icons_allArray_LEN];

View file

@ -1,19 +1,24 @@
#include "bitaxe_fetch.hpp" #include "bitaxe_fetch.hpp"
void BitAxeFetch::taskWrapper(void* pvParameters) { TaskHandle_t bitaxeFetchTaskHandle;
BitAxeFetch::getInstance().task();
uint64_t bitaxeHashrate;
uint64_t bitaxeBestDiff;
uint64_t getBitAxeHashRate()
{
return bitaxeHashrate;
} }
uint64_t BitAxeFetch::getHashRate() const { uint64_t getBitaxeBestDiff()
return hashrate; {
return bitaxeBestDiff;
} }
uint64_t BitAxeFetch::getBestDiff() const { void taskBitaxeFetch(void *pvParameters)
return bestDiff; {
} for (;;)
{
void BitAxeFetch::task() {
for (;;) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
HTTPClient http; HTTPClient http;
@ -23,38 +28,46 @@ void BitAxeFetch::task() {
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode == 200) { if (httpCode == 200)
{
String payload = http.getString(); String payload = http.getString();
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, payload); deserializeJson(doc, payload);
// Convert GH/s to H/s (multiply by 10^9) // Convert GH/s to H/s (multiply by 10^9)
float hashRateGH = doc["hashRate"].as<float>(); float hashRateGH = doc["hashRate"].as<float>();
hashrate = static_cast<uint64_t>(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G')))); bitaxeHashrate = static_cast<uint64_t>(std::round(hashRateGH * std::pow(10, getHashrateMultiplier('G'))));
// Parse difficulty string and convert to uint64_t // Parse difficulty string and convert to uint64_t
std::string diffStr = doc["bestDiff"].as<std::string>(); std::string diffStr = doc["bestDiff"].as<std::string>();
char diffUnit = diffStr[diffStr.length() - 1]; char diffUnit = diffStr[diffStr.length() - 1];
if (std::isalpha(diffUnit)) { if (std::isalpha(diffUnit)) {
float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1)); float diffValue = std::stof(diffStr.substr(0, diffStr.length() - 1));
bestDiff = static_cast<uint64_t>(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit)))); bitaxeBestDiff = static_cast<uint64_t>(std::round(diffValue * std::pow(10, getDifficultyMultiplier(diffUnit))));
} else { } else {
bestDiff = std::stoull(diffStr); bitaxeBestDiff = std::stoull(diffStr);
} }
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF)) { if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_BITAXE_BESTDIFF))
{
WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0}; WorkItem priceUpdate = {TASK_BITAXE_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
} else { }
Serial.print(F("Error retrieving BitAxe data. HTTP status code: ")); else
{
Serial.print(
F("Error retrieving BitAxe data. HTTP status code: "));
Serial.println(httpCode); Serial.println(httpCode);
Serial.println(bitaxeApiUrl); Serial.println(bitaxeApiUrl);
} }
} }
} }
void BitAxeFetch::setup() { void setupBitaxeFetchTask()
xTaskCreate(taskWrapper, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY, &taskHandle); {
xTaskNotifyGive(taskHandle); xTaskCreate(taskBitaxeFetch, "bitaxeFetch", (3 * 1024), NULL, tskIDLE_PRIORITY,
&bitaxeFetchTaskHandle);
xTaskNotifyGive(bitaxeFetchTaskHandle);
} }

View file

@ -7,28 +7,10 @@
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
class BitAxeFetch { extern TaskHandle_t bitaxeFetchTaskHandle;
public:
static BitAxeFetch& getInstance() {
static BitAxeFetch instance;
return instance;
}
void setup(); void setupBitaxeFetchTask();
uint64_t getHashRate() const; void taskBitaxeFetch(void *pvParameters);
uint64_t getBestDiff() const;
static void taskWrapper(void* pvParameters);
TaskHandle_t getTaskHandle() const { return taskHandle; }
private: uint64_t getBitAxeHashRate();
BitAxeFetch() = default; uint64_t getBitaxeBestDiff();
~BitAxeFetch() = default;
BitAxeFetch(const BitAxeFetch&) = delete;
BitAxeFetch& operator=(const BitAxeFetch&) = delete;
void task();
TaskHandle_t taskHandle = nullptr;
uint64_t hashrate = 0;
uint64_t bestDiff = 0;
};

View file

@ -1,14 +1,13 @@
#include "block_notify.hpp" #include "block_notify.hpp"
// Initialize static members char *wsServer;
esp_websocket_client_handle_t BlockNotify::wsClient = nullptr; esp_websocket_client_handle_t blockNotifyClient = NULL;
uint32_t BlockNotify::currentBlockHeight = 878000; uint32_t currentBlockHeight = 873400;
uint16_t BlockNotify::blockMedianFee = 1; uint16_t blockMedianFee = 1;
bool BlockNotify::notifyInit = false; bool blockNotifyInit = false;
unsigned long int BlockNotify::lastBlockUpdate = 0; unsigned long int lastBlockUpdate;
TaskHandle_t BlockNotify::taskHandle = nullptr;
const char* BlockNotify::mempoolWsCert = R"EOF( const char *mempoolWsCert = R"EOF(
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
@ -43,255 +42,256 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9 jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----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"; )EOF";
void BlockNotify::onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { void setupBlockNotify()
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; {
BlockNotify& instance = BlockNotify::getInstance(); IPAddress result;
switch (event_id) { int dnsErr = -1;
case WEBSOCKET_EVENT_CONNECTED: String mempoolInstance =
{ preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
notifyInit = true;
Serial.print(F("Connected to "));
Serial.println(preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE));
JsonDocument doc; while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':'))
doc["action"] = "want"; {
JsonArray dataArray = doc.createNestedArray("data"); dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
dataArray.add("blocks");
dataArray.add("mempool-blocks");
String sub; if (dnsErr != 1)
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;
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;
}
}
void BlockNotify::onWebsocketMessage(esp_websocket_event_data_t *data) {
JsonDocument doc;
JsonDocument filter;
filter["block"]["height"] = true;
filter["mempool-blocks"][0]["medianFee"] = true;
deserializeJson(doc, (char*)data->data_ptr, DeserializationOption::Filter(filter));
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);
}
}
void BlockNotify::setup() {
IPAddress result;
int dnsErr = -1;
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
while (dnsErr != 1 && !strchr(mempoolInstance.c_str(), ':')) {
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
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 = fetchLatestBlock();
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);
}
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);
}
void BlockNotify::processNewBlock(uint32_t newBlockHeight) {
if (newBlockHeight <= currentBlockHeight)
{ {
return; 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 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;
Serial.println(F("Connected to Mempool.space WebSocket"));
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"));
} }
currentBlockHeight = newBlockHeight; 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 onWebsocketBlockMessage(esp_websocket_event_data_t *event_data)
{
JsonDocument doc;
JsonDocument filter;
filter["block"]["height"] = true;
filter["mempool-blocks"][0]["medianFee"] = true;
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;
}
processNewBlock(block["height"].as<uint>());
}
else if (doc.containsKey("mempool-blocks"))
{
JsonArray blockInfo = doc["mempool-blocks"].as<JsonArray>();
uint medianFee = (uint)round(blockInfo[0]["medianFee"].as<double>());
processNewBlockFee(medianFee);
}
doc.clear();
}
void processNewBlock(uint32_t newBlockHeight) {
if (newBlockHeight < currentBlockHeight)
return;
currentBlockHeight = newBlockHeight;
// Serial.printf("New block found: %d\r\n", block["height"].as<uint>());
preferences.putUInt("blockHeight", currentBlockHeight);
lastBlockUpdate = esp_timer_get_time() / 1000000; lastBlockUpdate = esp_timer_get_time() / 1000000;
if (workQueue != nullptr) if (workQueue != nullptr)
{ {
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0}; WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
} // xTaskNotifyGive(blockUpdateTaskHandle);
if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT && if (ScreenHandler::getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS)) preferences.getBool("stealFocus", DEFAULT_STEAL_FOCUS))
{ {
uint64_t timerPeriod = 0; uint64_t timerPeriod = 0;
if (isTimerActive()) if (isTimerActive())
{ {
timerPeriod = getTimerSeconds(); // store timer periode before making inactive to prevent artifacts
esp_timer_stop(screenRotateTimer); timerPeriod = getTimerSeconds();
esp_timer_stop(screenRotateTimer);
} }
ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT); ScreenHandler::setCurrentScreen(SCREEN_BLOCK_HEIGHT);
if (timerPeriod > 0) if (timerPeriod > 0)
{ {
esp_timer_start_periodic(screenRotateTimer, esp_timer_start_periodic(screenRotateTimer,
timerPeriod * usPerSecond); timerPeriod * usPerSecond);
} }
vTaskDelay(pdMS_TO_TICKS(315*NUM_SCREENS)); // Extra delay because of screen switching vTaskDelay(pdMS_TO_TICKS(315*NUM_SCREENS)); // Extra delay because of screen switching
} }
if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD))
{ {
vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY); queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
}
} }
} }
void BlockNotify::processNewBlockFee(uint16_t newBlockFee) { void processNewBlockFee(uint16_t newBlockFee) {
if (blockMedianFee == newBlockFee) if (blockMedianFee == newBlockFee)
{ {
return; return;
} }
// Serial.printf("New median fee: %d\r\n", medianFee);
blockMedianFee = newBlockFee; blockMedianFee = newBlockFee;
if (workQueue != nullptr) if (workQueue != nullptr)
{ {
WorkItem blockUpdate = {TASK_FEE_UPDATE, 0}; WorkItem blockUpdate = {TASK_FEE_UPDATE, 0};
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY); xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
} }
} }
uint32_t BlockNotify::getBlockHeight() const { uint32_t getBlockHeight() { return currentBlockHeight; }
return currentBlockHeight;
}
void BlockNotify::setBlockHeight(uint32_t newBlockHeight) void setBlockHeight(uint32_t newBlockHeight)
{ {
currentBlockHeight = newBlockHeight; currentBlockHeight = newBlockHeight;
} }
uint16_t BlockNotify::getBlockMedianFee() const { uint16_t getBlockMedianFee() { return blockMedianFee; }
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) if (blockNotifyClient == NULL)
return false; return false;
return esp_websocket_client_is_connected(wsClient); 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) if (blockNotifyClient == NULL)
return; return;
esp_websocket_client_close(wsClient, portMAX_DELAY); esp_websocket_client_close(blockNotifyClient, pdMS_TO_TICKS(5000));
esp_websocket_client_stop(wsClient); esp_websocket_client_stop(blockNotifyClient);
esp_websocket_client_destroy(wsClient); esp_websocket_client_destroy(blockNotifyClient);
wsClient = NULL;
blockNotifyClient = NULL;
} }
void BlockNotify::restart() void restartBlockNotify()
{ {
stop(); stopBlockNotify();
setup();
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 { try {
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http"; const String protocol = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE) ? "https" : "http";
@ -314,12 +314,12 @@ int BlockNotify::fetchLatestBlock() {
return 2203; // B-T-C 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;
} }

View file

@ -5,6 +5,7 @@
#include <HTTPClient.h> #include <HTTPClient.h>
#include <esp_timer.h> #include <esp_timer.h>
#include <esp_websocket_client.h> #include <esp_websocket_client.h>
#include <cstring> #include <cstring>
#include <string> #include <string>
@ -13,53 +14,28 @@
#include "lib/timers.hpp" #include "lib/timers.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
class BlockNotify { // using namespace websockets;
public:
static BlockNotify& getInstance() {
static BlockNotify instance;
return instance;
}
// Delete copy constructor and assignment operator void setupBlockNotify();
BlockNotify(const BlockNotify&) = delete;
void operator=(const BlockNotify&) = delete;
// Block notification setup and control void onWebsocketBlockEvent(void *handler_args, esp_event_base_t base,
void setup(); int32_t event_id, void *event_data);
void stop(); void onWebsocketBlockMessage(esp_websocket_event_data_t *event_data);
void restart();
bool isConnected() const;
bool isInitialized() const;
// Block height management void setBlockHeight(uint32_t newBlockHeight);
void setBlockHeight(uint32_t newBlockHeight); uint32_t getBlockHeight();
uint32_t getBlockHeight() const;
// Block fee management void setBlockMedianFee(uint16_t blockMedianFee);
void setBlockMedianFee(uint16_t blockMedianFee); uint16_t getBlockMedianFee();
uint16_t getBlockMedianFee() const;
// Block processing bool isBlockNotifyConnected();
void processNewBlock(uint32_t newBlockHeight); void stopBlockNotify();
void processNewBlockFee(uint16_t newBlockFee); void restartBlockNotify();
// Block fetch and update tracking void processNewBlock(uint32_t newBlockHeight);
int fetchLatestBlock(); void processNewBlockFee(uint16_t newBlockFee);
uint getLastBlockUpdate() const;
void setLastBlockUpdate(uint lastUpdate);
private: bool getBlockNotifyInit();
BlockNotify() = default; // Private constructor for singleton uint32_t getLastBlockUpdate();
int getBlockFetch();
void setupTask(); void setLastBlockUpdate(uint32_t lastUpdate);
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;
};

View file

@ -1,5 +1,6 @@
#include "config.hpp" #include "config.hpp"
#include "led_handler.hpp" #include "icon_manager.hpp"
#include "../icons/icons.h"
#define MAX_ATTEMPTS_WIFI_CONNECTION 20 #define MAX_ATTEMPTS_WIFI_CONNECTION 20
@ -48,11 +49,10 @@ void setup()
setupPreferences(); setupPreferences();
setupHardware(); setupHardware();
EPDManager::getInstance().initialize(); setupDisplays();
if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER)) if (preferences.getBool("ledTestOnPower", DEFAULT_LED_TEST_ON_POWER))
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_POWER_TEST);
ledHandler.queueEffect(LED_POWER_TEST);
} }
{ {
std::lock_guard<std::mutex> lockMcp(mcpMutex); std::lock_guard<std::mutex> lockMcp(mcpMutex);
@ -62,8 +62,7 @@ void setup()
preferences.remove("txPower"); preferences.remove("txPower");
WiFi.eraseAP(); WiFi.eraseAP();
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
} }
} }
@ -79,8 +78,7 @@ void setup()
else if (mcp1.read1(1) == LOW) else if (mcp1.read1(1) == LOW)
{ {
preferences.clear(); preferences.clear();
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
ledHandler.queueEffect(LED_EFFECT_WIFI_ERASE_SETTINGS);
nvs_flash_erase(); nvs_flash_erase();
delay(1000); delay(1000);
@ -104,53 +102,37 @@ void setup()
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED))
{ {
BitAxeFetch::getInstance().setup(); setupBitaxeFetchTask();
} }
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED))
{ {
MiningPoolStatsFetch::getInstance().setup(); setupMiningPoolStatsFetchTask();
} }
ButtonHandler::setup(); ButtonHandler::setup();
setupOTA(); setupOTA();
EPDManager::getInstance().waitUntilNoneBusy(); waitUntilNoneBusy();
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON)) if (!preferences.getBool("flAlwaysOn", DEFAULT_FL_ALWAYS_ON))
{ {
auto& ledHandler = getLedHandler(); frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true);
ledHandler.frontlightFadeOutAll(preferences.getUInt("flEffectDelay"), true);
flArray.allOFF(); flArray.allOFF();
} }
#endif #endif
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
} }
void setupWifi() void setupWifi()
{ {
WiFi.onEvent(WiFiEvent); 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.setAutoConnect(true);
WiFi.setAutoReconnect(true); WiFi.setAutoReconnect(true);
WiFi.begin(); WiFi.begin();
if (preferences.getInt("txPower", DEFAULT_TX_POWER)) if (preferences.getInt("txPower", DEFAULT_TX_POWER))
{ {
if (WiFi.setTxPower( if (WiFi.setTxPower(
@ -164,8 +146,7 @@ void setupWifi()
// if (!preferences.getBool("wifiConfigured", DEFAULT_WIFI_CONFIGURED) // if (!preferences.getBool("wifiConfigured", DEFAULT_WIFI_CONFIGURED)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
ledHandler.queueEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
bool buttonPress = false; bool buttonPress = false;
{ {
@ -188,7 +169,6 @@ void setupWifi()
wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT)); wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", DEFAULT_WP_TIMEOUT));
wm.setWiFiAutoReconnect(false); wm.setWiFiAutoReconnect(false);
wm.setDebugOutput(false); wm.setDebugOutput(false);
wm.setCountry("NL");
wm.setConfigPortalBlocking(true); wm.setConfigPortalBlocking(true);
wm.setAPCallback([&](WiFiManager *wifiManager) wm.setAPCallback([&](WiFiManager *wifiManager)
@ -198,8 +178,8 @@ void setupWifi()
wifiManager->getConfigPortalSSID().c_str(), wifiManager->getConfigPortalSSID().c_str(),
softAP_password.c_str()); softAP_password.c_str());
// delay(6000); // delay(6000);
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); setFgColor(GxEPD_BLACK);
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); setBgColor(GxEPD_WHITE);
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() +
";T:WPA;P:" + softAP_password.c_str() + ";;"; ";T:WPA;P:" + softAP_password.c_str() + ";;";
const String explainText = "*SSID: *\r\n" + const String explainText = "*SSID: *\r\n" +
@ -229,22 +209,58 @@ void setupWifi()
#endif #endif
"\r\n\r\n*FW build date:*\r\n" + formattedDate, "\r\n\r\n*FW build date:*\r\n" + formattedDate,
qrText}; qrText};
setEpdContent(epdContent); });
EPDManager::getInstance().setContent(epdContent); });
wm.setSaveConfigCallback([]() wm.setSaveConfigCallback([]()
{ {
preferences.putBool("wifiConfigured", true); preferences.putBool("wifiConfigured", true);
delay(1000); delay(1000);
// just restart after success // just restart after succes
ESP.restart(); }); ESP.restart(); });
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str()); bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
// waitUntilNoneBusy();
// std::array<String, NUM_SCREENS> epdContent = {"Welcome!",
// "Bienvenidos!", "Use\r\nweb-interface\r\nto configure", "Use\r\nla
// interfaz web\r\npara configurar", "Or
// restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config",
// "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo
// botón\r\r\npara iniciar\r\nQR-config", ""}; setEpdContent(epdContent);
// esp_task_wdt_init(30, false);
// uint count = 0;
// while (WiFi.status() != WL_CONNECTED)
// {
// if (Serial.available() > 0)
// {
// uint8_t b = Serial.read();
// if (parse_improv_serial_byte(x_position, b, x_buffer,
// onImprovCommandCallback, onImprovErrorCallback))
// {
// x_buffer[x_position++] = b;
// }
// else
// {
// x_position = 0;
// }
// }
// count++;
// if (count > 2000000) {
// queueLedEffect(LED_EFFECT_HEARTBEAT);
// count = 0;
// }
// }
// esp_task_wdt_deinit();
// esp_task_wdt_reset();
} }
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
setFgColor(preferences.getUInt("fgColor", isWhiteVersion() ? GxEPD_BLACK : GxEPD_WHITE));
setBgColor(preferences.getUInt("bgColor", isWhiteVersion() ? GxEPD_WHITE : GxEPD_BLACK));
} }
// else // else
// { // {
@ -265,8 +281,7 @@ void syncTime()
while (!getLocalTime(&timeinfo)) while (!getLocalTime(&timeinfo))
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_EFFECT_CONFIGURING);
ledHandler.queueEffect(LED_EFFECT_CONFIGURING);
configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0, configTime(preferences.getInt("gmtOffset", DEFAULT_TIME_OFFSET_SECONDS), 0,
NTP_SERVER); NTP_SERVER);
delay(500); delay(500);
@ -280,9 +295,9 @@ void setupPreferences()
{ {
preferences.begin("btclock", false); preferences.begin("btclock", false);
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR)); setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR)); setBgColor(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); setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
if (!preferences.isKey("enableDebugLog")) { if (!preferences.isKey("enableDebugLog")) {
@ -361,10 +376,25 @@ void setupPreferences()
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED))
{ {
addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate"); addScreenMapping(SCREEN_MINING_POOL_STATS_HASHRATE, "Mining Pool Hashrate");
if (MiningPoolStatsFetch::getInstance().getPool()->supportsDailyEarnings()) { if (getMiningPool()->supportsDailyEarnings()) {
addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings"); addScreenMapping(SCREEN_MINING_POOL_STATS_EARNINGS, "Mining Pool Earnings");
} }
} }
// Load icons based on preferences
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED)) {
IconManager::loadIcon("bitaxe", epd_icons_bitaxe_logo, epd_icons_compressed_sizes[3], epd_icons_original_sizes[3], 88, 220);
IconManager::loadIcon("rocket", epd_icons_rocket_launch, epd_icons_compressed_sizes[1], epd_icons_original_sizes[1], 122, 122);
IconManager::loadIcon("pickaxe", epd_icons_pickaxe, epd_icons_compressed_sizes[0], epd_icons_original_sizes[0], 122, 122);
}
if (preferences.getBool("nostrZapNotify", DEFAULT_ZAP_NOTIFY_ENABLED)) {
IconManager::loadIcon("lightning", epd_icons_lightning_bolt, epd_icons_compressed_sizes[2], epd_icons_original_sizes[2], 122, 122);
}
if (preferences.getBool("miningPoolStats", DEFAULT_MINING_POOL_STATS_ENABLED)) {
IconManager::loadIcon("pickaxe", epd_icons_pickaxe, epd_icons_compressed_sizes[0], epd_icons_original_sizes[0], 122, 122);
}
} }
String replaceAmbiguousChars(String input) String replaceAmbiguousChars(String input)
@ -390,7 +420,7 @@ void setupWebsocketClients(void *pvParameters)
} }
else if (dataSource == THIRD_PARTY_SOURCE) else if (dataSource == THIRD_PARTY_SOURCE)
{ {
BlockNotify::getInstance().setup(); setupBlockNotify();
setupPriceNotify(); setupPriceNotify();
} }
@ -407,14 +437,13 @@ void setupTimers()
void finishSetup() void finishSetup()
{ {
auto& ledHandler = getLedHandler();
if (preferences.getBool("ledStatus", DEFAULT_LED_STATUS)) if (preferences.getBool("ledStatus", DEFAULT_LED_STATUS))
{ {
ledHandler.restoreLedState(); restoreLedState();
} }
else else
{ {
ledHandler.clear(); clearLeds();
} }
} }
@ -463,9 +492,7 @@ void setupHardware()
Serial.println(F("Error loading WebUI")); Serial.println(F("Error loading WebUI"));
} }
// Initialize LED handler setupLeds();
auto& ledHandler = getLedHandler();
ledHandler.setup();
WiFi.setHostname(getMyHostname().c_str()); WiFi.setHostname(getMyHostname().c_str());
if (!psramInit()) if (!psramInit())
@ -477,6 +504,8 @@ void setupHardware()
Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000); Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000);
if (!mcp1.begin()) { if (!mcp1.begin()) {
Serial.println(F("Error MCP23017 1")); Serial.println(F("Error MCP23017 1"));
} else { } else {
@ -523,8 +552,7 @@ void setupHardware()
#endif #endif
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
// Initialize frontlight through LedHandler setupFrontlight();
ledHandler.initializeFrontlight();
Wire.beginTransmission(0x5C); Wire.beginTransmission(0x5C);
byte error = Wire.endTransmission(); byte error = Wire.endTransmission();
@ -546,7 +574,6 @@ void setupHardware()
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
{ {
static bool first_connect = true; static bool first_connect = true;
auto& ledHandler = getLedHandler(); // Get ledHandler reference once at the start
Serial.printf("[WiFi-event] event: %d\n", event); Serial.printf("[WiFi-event] event: %d\n", event);
@ -572,7 +599,7 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
if (!first_connect) if (!first_connect)
{ {
Serial.println(F("Disconnected from WiFi access point")); Serial.println(F("Disconnected from WiFi access point"));
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
uint8_t reason = info.wifi_sta_disconnected.reason; uint8_t reason = info.wifi_sta_disconnected.reason;
if (reason) if (reason)
Serial.printf("Disconnect reason: %s, ", Serial.printf("Disconnect reason: %s, ",
@ -588,13 +615,13 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
Serial.print("Obtained IP address: "); Serial.print("Obtained IP address: ");
Serial.println(WiFi.localIP()); Serial.println(WiFi.localIP());
if (!first_connect) if (!first_connect)
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS); queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
first_connect = false; first_connect = false;
break; break;
} }
case ARDUINO_EVENT_WIFI_STA_LOST_IP: case ARDUINO_EVENT_WIFI_STA_LOST_IP:
Serial.println(F("Lost IP address and IP address is reset to 0")); Serial.println(F("Lost IP address and IP address is reset to 0"));
ledHandler.queueEffect(LED_EFFECT_WIFI_CONNECT_ERROR); queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
WiFi.reconnect(); WiFi.reconnect();
break; break;
case ARDUINO_EVENT_WIFI_AP_START: case ARDUINO_EVENT_WIFI_AP_START:
@ -644,6 +671,30 @@ uint getLastTimeSync()
} }
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void setupFrontlight()
{
if (!flArray.begin(PCA9685_MODE1_AUTOINCR | PCA9685_MODE1_ALLCALL, PCA9685_MODE2_TOTEMPOLE))
{
Serial.println(F("FL driver error"));
return;
}
flArray.setFrequency(200);
Serial.println(F("FL driver active"));
if (!preferences.isKey("flMaxBrightness"))
{
preferences.putUInt("flMaxBrightness", DEFAULT_FL_MAX_BRIGHTNESS);
}
if (!preferences.isKey("flEffectDelay"))
{
preferences.putUInt("flEffectDelay", DEFAULT_FL_EFFECT_DELAY);
}
if (!preferences.isKey("flFlashOnUpd"))
{
preferences.putBool("flFlashOnUpd", DEFAULT_FL_FLASH_ON_UPDATE);
}
}
float getLightLevel() float getLightLevel()
{ {

View file

@ -52,10 +52,10 @@ void setupTimers();
void finishSetup(); void finishSetup();
void setupMcp(); void setupMcp();
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
extern BH1750 bh1750; void setupFrontlight();
extern bool hasLuxSensor;
float getLightLevel(); float getLightLevel();
bool hasLightLevel(); bool hasLightLevel();
extern PCA9685 flArray;
#endif #endif
String getMyHostname(); String getMyHostname();
@ -98,10 +98,6 @@ extern MCP23017 mcp1;
extern MCP23017 mcp2; extern MCP23017 mcp2;
#endif #endif
#ifdef HAS_FRONTLIGHT
extern PCA9685 flArray;
#endif
// Expose DataSourceType enum // Expose DataSourceType enum
extern DataSourceType getDataSource(); extern DataSourceType getDataSource();
extern void setDataSource(DataSourceType source); extern void setDataSource(DataSourceType source);

View file

@ -46,8 +46,8 @@
#define DEFAULT_LUX_LIGHT_TOGGLE 128 #define DEFAULT_LUX_LIGHT_TOGGLE 128
#define DEFAULT_FL_OFF_WHEN_DARK true #define DEFAULT_FL_OFF_WHEN_DARK true
#define DEFAULT_FL_ALWAYS_ON true #define DEFAULT_FL_ALWAYS_ON false
#define DEFAULT_FL_FLASH_ON_UPDATE true #define DEFAULT_FL_FLASH_ON_UPDATE false
#define DEFAULT_LED_STATUS false #define DEFAULT_LED_STATUS false
#define DEFAULT_TIMER_ACTIVE true #define DEFAULT_TIMER_ACTIVE true
@ -60,7 +60,6 @@
#define DEFAULT_MINING_POOL_STATS_ENABLED false #define DEFAULT_MINING_POOL_STATS_ENABLED false
#define DEFAULT_MINING_POOL_NAME "ocean" #define DEFAULT_MINING_POOL_NAME "ocean"
#define DEFAULT_MINING_POOL_USER "38Qkkei3SuF1Eo45BaYmRHUneRD54yyTFy" // Random actual Ocean hasher #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_ENABLED false
#define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422" #define DEFAULT_ZAP_NOTIFY_PUBKEY "b5127a08cf33616274800a4387881a9f98e04b9c37116e92de5250498635c422"

File diff suppressed because it is too large Load diff

View file

@ -9,14 +9,13 @@
#include <mutex> #include <mutex>
#include <native_pin.hpp> #include <native_pin.hpp>
#include <regex> #include <regex>
#include <array>
#include <memory>
#include "fonts/fonts.hpp" #include "fonts/fonts.hpp"
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "icons/icons.h" #include "icons/icons.h"
#include "mining_pool_stats_fetch.hpp" #include "mining_pool_stats_fetch.hpp"
#include "icon_manager.hpp"
// Font includes // Font includes
#include "../fonts/antonio-semibold20.h" #include "../fonts/antonio-semibold20.h"
@ -34,102 +33,39 @@
#include "qrcodegen.h" #include "qrcodegen.h"
#endif #endif
struct UpdateDisplayTaskItem { typedef struct {
char dispNum; char dispNum;
}; } UpdateDisplayTaskItem;
struct FontFamily { void forceFullRefresh();
GFXfont* big; void setupDisplays();
GFXfont* medium; void loadFonts(const String& fontName);
GFXfont* small;
};
class EPDManager { void splitText(const uint dispNum, const String &top, const String &bottom,
public: bool partial);
static EPDManager& getInstance();
// Delete copy constructor and assignment operator void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
EPDManager(const EPDManager&) = delete; void showChars(const uint dispNum, const String &chars, bool partial,
EPDManager& operator=(const EPDManager&) = delete; const GFXfont *font);
void initialize(); extern "C" void updateDisplay(void *pvParameters) noexcept;
void forceFullRefresh(); void updateDisplayAlt(int epdIndex);
void loadFonts(const String& fontName); void prepareDisplayUpdateTask(void *pvParameters);
void setContent(const std::array<String, NUM_SCREENS>& newContent, bool forceUpdate = false);
void setContent(const std::array<std::string, NUM_SCREENS>& newContent);
std::array<String, NUM_SCREENS> getCurrentContent() const;
int getBackgroundColor() const { return bgColor; } int getBgColor();
int getForegroundColor() const { return fgColor; } int getFgColor();
void setBackgroundColor(int color) { bgColor = color; } void setBgColor(int color);
void setForegroundColor(int color) { fgColor = color; } void setFgColor(int color);
void waitUntilNoneBusy();
private: bool renderIcon(const uint dispNum, const String &text, bool partial);
EPDManager(); // Private constructor for singleton void renderText(const uint dispNum, const String &text, bool partial);
~EPDManager(); // Private destructor void renderQr(const uint dispNum, const String &text, bool partial);
void setupDisplay(uint dispNum, const GFXfont* font); void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
void splitText(uint dispNum, const String& top, const String& bottom, bool partial); bool forceUpdate);
void showDigit(uint dispNum, char chr, bool partial, const GFXfont* font); void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
void showChars(uint dispNum, const String& chars, bool partial, const GFXfont* font);
bool renderIcon(uint dispNum, const String& text, bool partial);
void renderText(uint dispNum, const String& text, bool partial);
void renderQr(uint dispNum, const String& text, bool partial);
int16_t calculateDescent(const GFXfont* font);
static void updateDisplayTask(void* pvParameters) noexcept; void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent);
static void prepareDisplayUpdateTask(void* pvParameters);
// Member variables std::array<String, NUM_SCREENS> getCurrentEpdContent();
std::array<String, NUM_SCREENS> currentContent; void waitUntilNoneBusy();
std::array<String, NUM_SCREENS> content;
std::array<uint32_t, NUM_SCREENS> lastFullRefresh;
std::array<TaskHandle_t, NUM_SCREENS> tasks;
QueueHandle_t updateQueue;
FontFamily antonioFonts;
FontFamily oswaldFonts;
const GFXfont* fontSmall;
const GFXfont* fontBig;
const GFXfont* fontMedium;
const GFXfont* fontSatsymbol;
int bgColor;
int fgColor;
std::mutex updateMutex;
std::array<std::mutex, NUM_SCREENS> displayMutexes;
// Pin configurations based on board version
#ifdef IS_BTCLOCK_REV_B
static Native_Pin EPD_DC;
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#elif defined(IS_BTCLOCK_V8)
static Native_Pin EPD_DC;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_CS;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#else
static Native_Pin EPD_DC;
static std::array<Native_Pin, NUM_SCREENS> EPD_CS;
static std::array<Native_Pin, NUM_SCREENS> EPD_BUSY;
static std::array<MCP23X17_Pin, NUM_SCREENS> EPD_RESET;
#endif
// Display array
std::array<GxEPD2_BW<EPD_CLASS, EPD_CLASS::HEIGHT>, NUM_SCREENS> displays;
static constexpr size_t UPDATE_QUEUE_SIZE = 14;
static constexpr uint32_t BUSY_TIMEOUT_COUNT = 200;
static constexpr TickType_t BUSY_RETRY_DELAY = pdMS_TO_TICKS(10);
static constexpr size_t EPD_TASK_STACK_SIZE =
#ifdef IS_BTCLOCK_V8
4096
#else
2048
#endif
;
};

59
src/lib/icon_manager.cpp Normal file
View file

@ -0,0 +1,59 @@
#include "icon_manager.hpp"
#include "gzip_decompressor.hpp"
std::map<std::string, IconData> IconManager::loadedIcons;
void IconManager::loadIcon(const char* name, const unsigned char* compressedData, size_t compressedSize, size_t originalSize, uint width, uint height) {
// Check if icon is already loaded
if (loadedIcons.find(name) != loadedIcons.end()) {
return;
}
// Allocate memory for decompressed data
uint8_t* decompressedData = new uint8_t[originalSize];
if (!decompressedData) {
Serial.printf("Failed to allocate memory for icon %s\n", name);
return;
}
// Decompress the icon
size_t decompressedSize = originalSize;
if (!GzipDecompressor::decompressData(compressedData, compressedSize, decompressedData, &decompressedSize)) {
Serial.printf("Failed to decompress icon %s\n", name);
delete[] decompressedData;
return;
}
Serial.printf("Decompressed icon %s to %zu bytes\n", name, decompressedSize);
// Store the icon data
IconData iconData = {
.data = decompressedData,
.width = width,
.height = height
};
loadedIcons[name] = iconData;
}
void IconManager::unloadIcon(const char* name) {
auto it = loadedIcons.find(name);
if (it != loadedIcons.end()) {
delete[] it->second.data;
loadedIcons.erase(it);
}
}
IconData* IconManager::getIcon(const char* name) {
auto it = loadedIcons.find(name);
if (it != loadedIcons.end()) {
return &it->second;
}
return nullptr;
}
void IconManager::cleanup() {
for (auto& pair : loadedIcons) {
delete[] pair.second.data;
}
loadedIcons.clear();
}

22
src/lib/icon_manager.hpp Normal file
View file

@ -0,0 +1,22 @@
#pragma once
#include <Arduino.h>
#include <map>
#include <string>
struct IconData {
uint8_t* data;
uint width;
uint height;
};
class IconManager {
public:
static void loadIcon(const char* name, const unsigned char* compressedData, size_t compressedSize, size_t originalSize, uint width, uint height);
static void unloadIcon(const char* name);
static IconData* getIcon(const char* name);
static void cleanup();
private:
static std::map<std::string, IconData> loadedIcons;
};

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,6 @@
#include <Arduino.h> #include <Arduino.h>
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
#include <memory>
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/webserver.hpp" #include "lib/webserver.hpp"
@ -16,11 +15,12 @@
#define NEOPIXEL_COUNT 4 #define NEOPIXEL_COUNT 4
#endif #endif
// LED effect constants
const int LED_FLASH_ERROR = 0; const int LED_FLASH_ERROR = 0;
const int LED_FLASH_SUCCESS = 1; const int LED_FLASH_SUCCESS = 1;
const int LED_FLASH_UPDATE = 2; const int LED_FLASH_UPDATE = 2;
const int LED_EFFECT_CONFIGURING = 10; const int LED_EFFECT_CONFIGURING = 10;
const int LED_FLASH_BLOCK_NOTIFY = 4; const int LED_FLASH_BLOCK_NOTIFY = 4;
const int LED_EFFECT_START_TIMER = 5; const int LED_EFFECT_START_TIMER = 5;
const int LED_EFFECT_PAUSE_TIMER = 6; const int LED_EFFECT_PAUSE_TIMER = 6;
@ -30,15 +30,61 @@ const int LED_EFFECT_WIFI_CONNECTING = 101;
const int LED_EFFECT_WIFI_CONNECT_ERROR = 102; const int LED_EFFECT_WIFI_CONNECT_ERROR = 102;
const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103; const int LED_EFFECT_WIFI_CONNECT_SUCCESS = 103;
const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104; const int LED_EFFECT_WIFI_ERASE_SETTINGS = 104;
const int LED_PROGRESS_25 = 200; const int LED_PROGRESS_25 = 200;
const int LED_PROGRESS_50 = 201; const int LED_PROGRESS_50 = 201;
const int LED_PROGRESS_75 = 202; const int LED_PROGRESS_75 = 202;
const int LED_PROGRESS_100 = 203; const int LED_PROGRESS_100 = 203;
const int LED_DATA_PRICE_ERROR = 300; const int LED_DATA_PRICE_ERROR = 300;
const int LED_DATA_BLOCK_ERROR = 301; const int LED_DATA_BLOCK_ERROR = 301;
const int LED_EFFECT_NOSTR_ZAP = 400; const int LED_EFFECT_NOSTR_ZAP = 400;
const int LED_FLASH_IDENTIFY = 990; const int LED_FLASH_IDENTIFY = 990;
const int LED_POWER_TEST = 999; const int LED_POWER_TEST = 999;
extern TaskHandle_t ledTaskHandle;
extern Adafruit_NeoPixel pixels;
void ledTask(void *pvParameters);
void setupLeds();
void setupLedTask();
void blinkDelay(int d, int times);
void blinkDelayColor(int d, int times, uint r, uint g, uint b);
void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2);
void clearLeds();
void saveLedState();
void restoreLedState();
QueueHandle_t getLedTaskQueue();
bool queueLedEffect(uint effect);
void setLights(int r, int g, int b);
void setLights(uint32_t color);
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);
void frontlightFadeInAll();
void frontlightFadeOutAll();
void frontlightFadeIn(uint num);
void frontlightFadeOut(uint num);
std::vector<uint16_t> frontlightGetStatus();
void frontlightSetBrightness(uint brightness);
bool frontlightIsOn();
void frontlightFadeInAll(int flDelayTime);
void frontlightFadeInAll(int flDelayTime, bool staggered);
void frontlightFadeOutAll(int flDelayTime);
void frontlightFadeOutAll(int flDelayTime, bool staggered);
void frontlightFadeIn(uint num, int flDelayTime);
void frontlightFadeOut(uint num, int flDelayTime);
#endif
// Do Not Disturb mode settings // Do Not Disturb mode settings
struct DNDTimeRange { struct DNDTimeRange {
@ -48,88 +94,12 @@ struct DNDTimeRange {
uint8_t endMinute; uint8_t endMinute;
}; };
class LedHandler { extern bool dndEnabled;
public: extern bool dndTimeBasedEnabled;
static LedHandler& getInstance(); extern DNDTimeRange dndTimeRange;
// Delete copy constructor and assignment operator void setDNDEnabled(bool enabled);
LedHandler(const LedHandler&) = delete; void setDNDTimeBasedEnabled(bool enabled);
LedHandler& operator=(const LedHandler&) = delete; void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute);
bool isDNDActive();
void setup(); bool isTimeInDNDRange(uint8_t hour, uint8_t minute);
void setupTask();
bool queueEffect(uint effect);
void clear();
void setLights(int r, int g, int b);
void setLights(uint32_t color);
void saveLedState();
void restoreLedState();
QueueHandle_t getTaskQueue() const { return ledTaskQueue; }
Adafruit_NeoPixel& getPixels() { return pixels; }
// DND methods
void setDNDEnabled(bool enabled);
void setDNDTimeBasedEnabled(bool enabled);
void setDNDTimeRange(uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute);
bool isDNDActive() const;
bool isTimeInDNDRange(uint8_t hour, uint8_t minute) const;
// DND getters
bool isDNDEnabled() const { return dndEnabled; }
bool isDNDTimeBasedEnabled() const { return dndTimeBasedEnabled; }
uint8_t getDNDStartHour() const { return dndTimeRange.startHour; }
uint8_t getDNDStartMinute() const { return dndTimeRange.startMinute; }
uint8_t getDNDEndHour() const { return dndTimeRange.endHour; }
uint8_t getDNDEndMinute() const { return dndTimeRange.endMinute; }
// Effect methods
void rainbow(int wait);
void theaterChase(uint32_t color, int wait);
void theaterChaseRainbow(int wait);
void lightningStrike();
void blinkDelay(int d, int times);
void blinkDelayColor(int d, int times, uint r, uint g, uint b);
void blinkDelayTwoColor(int d, int times, const uint32_t& c1, const uint32_t& c2);
#ifdef HAS_FRONTLIGHT
void frontlightFlash(int flDelayTime);
void frontlightFadeInAll();
void frontlightFadeOutAll();
void frontlightFadeIn(uint num);
void frontlightFadeOut(uint num);
std::vector<uint16_t> frontlightGetStatus();
void frontlightSetBrightness(uint brightness);
bool frontlightIsOn() const { return frontlightOn; }
void frontlightFadeInAll(int flDelayTime, bool staggered = false);
void frontlightFadeOutAll(int flDelayTime, bool staggered = false);
void frontlightFadeIn(uint num, int flDelayTime);
void frontlightFadeOut(uint num, int flDelayTime);
void initializeFrontlight();
#endif
private:
LedHandler(); // Private constructor for singleton
void loadDNDSettings();
static void ledTask(void* pvParameters);
Adafruit_NeoPixel pixels;
TaskHandle_t ledTaskHandle;
QueueHandle_t ledTaskQueue;
uint ledTaskParams;
// DND members
bool dndEnabled;
bool dndTimeBasedEnabled;
DNDTimeRange dndTimeRange;
#ifdef HAS_FRONTLIGHT
static constexpr uint16_t FL_FADE_STEP = 25;
bool frontlightOn;
bool flInTransition;
#endif
};
// Global accessor function
inline LedHandler& getLedHandler() {
return LedHandler::getInstance();
}

View file

@ -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_BRAIINS = "braiins";
const char* PoolFactory::MINING_POOL_NAME_SATOSHI_RADIO = "satoshi_radio"; 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_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_GOBRRR_POOL = "gobrrr_pool";
const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool"; const char* PoolFactory::MINING_POOL_NAME_CKPOOL = "ckpool";
const char* PoolFactory::MINING_POOL_NAME_EU_CKPOOL = "eu_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_BRAIINS, []() { return std::make_unique<BraiinsPool>(); }},
{MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }}, {MINING_POOL_NAME_SATOSHI_RADIO, []() { return std::make_unique<SatoshiRadioPool>(); }},
{MINING_POOL_NAME_PUBLIC_POOL, []() { return std::make_unique<PublicPool>(); }}, {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_GOBRRR_POOL, []() { return std::make_unique<GoBrrrPool>(); }},
{MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }}, {MINING_POOL_NAME_CKPOOL, []() { return std::make_unique<CKPool>(); }},
{MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }} {MINING_POOL_NAME_EU_CKPOOL, []() { return std::make_unique<EUCKPool>(); }}

View file

@ -10,7 +10,6 @@
#include "ocean/ocean_pool.hpp" #include "ocean/ocean_pool.hpp"
#include "satoshi_radio/satoshi_radio_pool.hpp" #include "satoshi_radio/satoshi_radio_pool.hpp"
#include "public_pool/public_pool.hpp" #include "public_pool/public_pool.hpp"
#include "public_pool/local_public_pool.hpp"
#include "gobrrr_pool/gobrrr_pool.hpp" #include "gobrrr_pool/gobrrr_pool.hpp"
#include "ckpool/ckpool.hpp" #include "ckpool/ckpool.hpp"
#include "ckpool/eu_ckpool.hpp" #include "ckpool/eu_ckpool.hpp"
@ -29,7 +28,6 @@ class PoolFactory {
MINING_POOL_NAME_SATOSHI_RADIO, MINING_POOL_NAME_SATOSHI_RADIO,
MINING_POOL_NAME_BRAIINS, MINING_POOL_NAME_BRAIINS,
MINING_POOL_NAME_PUBLIC_POOL, MINING_POOL_NAME_PUBLIC_POOL,
MINING_POOL_NAME_LOCAL_PUBLIC_POOL,
MINING_POOL_NAME_GOBRRR_POOL, MINING_POOL_NAME_GOBRRR_POOL,
MINING_POOL_NAME_CKPOOL, MINING_POOL_NAME_CKPOOL,
MINING_POOL_NAME_EU_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_BRAIINS;
static const char* MINING_POOL_NAME_SATOSHI_RADIO; static const char* MINING_POOL_NAME_SATOSHI_RADIO;
static const char* MINING_POOL_NAME_PUBLIC_POOL; 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_GOBRRR_POOL;
static const char* MINING_POOL_NAME_CKPOOL; static const char* MINING_POOL_NAME_CKPOOL;
static const char* MINING_POOL_NAME_EU_CKPOOL; static const char* MINING_POOL_NAME_EU_CKPOOL;

View file

@ -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;
}

View file

@ -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;
};

View file

@ -1,98 +1,95 @@
#include "mining_pool_stats_fetch.hpp" #include "mining_pool_stats_fetch.hpp"
void MiningPoolStatsFetch::taskWrapper(void* pvParameters) { TaskHandle_t miningPoolStatsFetchTaskHandle;
MiningPoolStatsFetch::getInstance().task();
std::string miningPoolName;
std::string miningPoolStatsHashrate;
int miningPoolStatsDailyEarnings;
std::string getMiningPoolStatsHashRate()
{
return miningPoolStatsHashrate;
} }
void MiningPoolStatsFetch::downloadLogoTaskWrapper(void* pvParameters) { int getMiningPoolStatsDailyEarnings()
MiningPoolStatsFetch::getInstance().downloadLogoTask(); {
return miningPoolStatsDailyEarnings;
} }
std::string MiningPoolStatsFetch::getHashRate() const { void taskMiningPoolStatsFetch(void *pvParameters)
return hashrate; {
}
int MiningPoolStatsFetch::getDailyEarnings() const {
return dailyEarnings;
}
MiningPoolInterface* MiningPoolStatsFetch::getPool() {
if (!currentPool) {
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
currentPool = PoolFactory::createPool(poolName);
}
return currentPool.get();
}
const MiningPoolInterface* MiningPoolStatsFetch::getPool() const {
return currentPool.get();
}
LogoData MiningPoolStatsFetch::getLogo() const {
if (const auto* pool = getPool()) {
return pool->getLogo();
}
return LogoData{};
}
void MiningPoolStatsFetch::task() {
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
auto* poolInterface = getPool(); auto poolInterface = PoolFactory::createPool(poolName);
if (!poolInterface) return;
std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str(); std::string poolUser = preferences.getString("miningPoolUser", DEFAULT_MINING_POOL_USER).c_str();
// Main stats fetching loop // Main stats fetching loop
for (;;) { for (;;)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
HTTPClient http; HTTPClient http;
http.setUserAgent(USER_AGENT); http.setUserAgent(USER_AGENT);
poolInterface->setPoolUser(poolUser); poolInterface->setPoolUser(poolUser);
std::string apiUrl = poolInterface->getApiUrl(); std::string apiUrl = poolInterface->getApiUrl();
http.begin(apiUrl.c_str()); http.begin(apiUrl.c_str());
if (debugLogEnabled()) { if (debugLogEnabled())
{
Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str()); Serial.printf("Fetching mining pool stats from %s\r\n", apiUrl.c_str());
} }
poolInterface->prepareRequest(http); poolInterface->prepareRequest(http);
int httpCode = http.GET(); int httpCode = http.GET();
if (httpCode == 200) { if (httpCode == 200)
{
String payload = http.getString(); String payload = http.getString();
JsonDocument doc; JsonDocument doc;
deserializeJson(doc, payload); deserializeJson(doc, payload);
if (debugLogEnabled()) { if (debugLogEnabled())
{
Serial.printf("Mining pool stats response: %s\r\n", payload.c_str()); Serial.printf("Mining pool stats response: %s\r\n", payload.c_str());
} }
PoolStats stats = poolInterface->parseResponse(doc); PoolStats stats = poolInterface->parseResponse(doc);
hashrate = stats.hashrate;
if (debugLogEnabled()) { miningPoolStatsHashrate = stats.hashrate;
if (debugLogEnabled())
{
Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str()); Serial.printf("Mining pool stats parsed hashrate: %s\r\n", stats.hashrate.c_str());
} }
dailyEarnings = stats.dailyEarnings ? *stats.dailyEarnings : 0; if (stats.dailyEarnings)
{
miningPoolStatsDailyEarnings = *stats.dailyEarnings;
}
else
{
miningPoolStatsDailyEarnings = 0; // or any other default value
}
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE || ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS))
ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_EARNINGS)) { {
WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0}; WorkItem priceUpdate = {TASK_MINING_POOL_STATS_UPDATE, 0};
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
} else { }
Serial.print(F("Error retrieving mining pool data. HTTP status code: ")); else
{
Serial.print(
F("Error retrieving mining pool data. HTTP status code: "));
Serial.println(httpCode); Serial.println(httpCode);
} }
} }
} }
void MiningPoolStatsFetch::downloadLogoTask() { void downloadMiningPoolLogoTask(void *pvParameters) {
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str(); std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
auto* poolInterface = getPool(); auto poolInterface = PoolFactory::createPool(poolName);
if (!poolInterface) return; PoolFactory::downloadPoolLogo(poolName, poolInterface.get());
PoolFactory::downloadPoolLogo(poolName, poolInterface);
// If we're on the mining pool stats screen, trigger a display update // If we're on the mining pool stats screen, trigger a display update
if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) { if (ScreenHandler::getCurrentScreen() == SCREEN_MINING_POOL_STATS_HASHRATE) {
@ -100,22 +97,41 @@ void MiningPoolStatsFetch::downloadLogoTask() {
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY); xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
} }
xTaskNotifyGive(taskHandle); xTaskNotifyGive(miningPoolStatsFetchTaskHandle);
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void MiningPoolStatsFetch::setup() { void setupMiningPoolStatsFetchTask()
xTaskCreate(downloadLogoTaskWrapper, {
xTaskCreate(downloadMiningPoolLogoTask,
"logoDownload", "logoDownload",
(6 * 1024), (6 * 1024),
NULL, NULL,
tskIDLE_PRIORITY, tskIDLE_PRIORITY,
NULL); NULL);
xTaskCreate(taskWrapper, xTaskCreate(taskMiningPoolStatsFetch,
"miningPoolStatsFetch", "miningPoolStatsFetch",
(6 * 1024), (6 * 1024),
NULL, NULL,
tskIDLE_PRIORITY, tskIDLE_PRIORITY,
&taskHandle); &miningPoolStatsFetchTaskHandle);
}
std::unique_ptr<MiningPoolInterface>& getMiningPool()
{
static std::unique_ptr<MiningPoolInterface> currentMiningPool;
if (!currentMiningPool) {
std::string poolName = preferences.getString("miningPoolName", DEFAULT_MINING_POOL_NAME).c_str();
currentMiningPool = PoolFactory::createPool(poolName);
}
return currentMiningPool;
}
LogoData getMiningPoolLogo()
{
LogoData logo = getMiningPool()->getLogo();
return logo;
} }

View file

@ -2,44 +2,18 @@
#include <Arduino.h> #include <Arduino.h>
#include <HTTPClient.h> #include <HTTPClient.h>
#include <utils.hpp> #include "mining_pool/pool_factory.hpp"
#include <memory>
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/mining_pool/mining_pool_interface.hpp"
#include "mining_pool/pool_factory.hpp"
class MiningPoolStatsFetch { extern TaskHandle_t miningPoolStatsFetchTaskHandle;
public:
static MiningPoolStatsFetch& getInstance() {
static MiningPoolStatsFetch instance;
return instance;
}
void setup(); void setupMiningPoolStatsFetchTask();
std::string getHashRate() const; void taskMiningPoolStatsFetch(void *pvParameters);
int getDailyEarnings() const;
TaskHandle_t getTaskHandle() const { return taskHandle; }
static void taskWrapper(void* pvParameters);
static void downloadLogoTaskWrapper(void* pvParameters);
// Pool interface methods std::string getMiningPoolStatsHashRate();
MiningPoolInterface* getPool(); int getMiningPoolStatsDailyEarnings();
const MiningPoolInterface* getPool() const;
LogoData getLogo() const;
private: std::unique_ptr<MiningPoolInterface>& getMiningPool();
MiningPoolStatsFetch() = default; LogoData getMiningPoolLogo();
~MiningPoolStatsFetch() = default;
MiningPoolStatsFetch(const MiningPoolStatsFetch&) = delete;
MiningPoolStatsFetch& operator=(const MiningPoolStatsFetch&) = delete;
void task();
void downloadLogoTask();
TaskHandle_t taskHandle = nullptr;
std::string hashrate;
int dailyEarnings = 0;
std::unique_ptr<MiningPoolInterface> currentPool;
};

View file

@ -1,5 +1,4 @@
#include "nostr_notify.hpp" #include "nostr_notify.hpp"
#include "led_handler.hpp"
std::vector<nostr::NostrPool *> pools; std::vector<nostr::NostrPool *> pools;
nostr::Transport *transport; nostr::Transport *transport;
@ -41,7 +40,7 @@ void setupNostrNotify(bool asDatasource, bool zapNotify)
{relay}, {relay},
{// First filter {// First filter
{ {
{"kinds", {"12203"}}, {"kinds", {"1"}},
{"since", {String(getMinutesAgo(60))}}, {"since", {String(getMinutesAgo(60))}},
{"authors", {pubKey}}, {"authors", {pubKey}},
}}, }},
@ -79,9 +78,8 @@ void nostrTask(void *pvParameters)
{ {
DataSourceType dataSource = getDataSource(); DataSourceType dataSource = getDataSource();
if(dataSource == NOSTR_SOURCE) { if(dataSource == NOSTR_SOURCE) {
auto& blockNotify = BlockNotify::getInstance(); int blockFetch = getBlockFetch();
int blockFetch = blockNotify.fetchLatestBlock(); processNewBlock(blockFetch);
blockNotify.processNewBlock(blockFetch);
} }
while (1) while (1)
@ -146,7 +144,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
// Use direct value access instead of multiple comparisons // Use direct value access instead of multiple comparisons
String typeValue; String typeValue;
uint medianFee = 0; uint medianFee = 0;
uint blockHeight = 0;
for (JsonArray tag : tags) { for (JsonArray tag : tags) {
if (tag.size() != 2) continue; if (tag.size() != 2) continue;
@ -167,11 +164,6 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
medianFee = tag[1].as<uint>(); medianFee = tag[1].as<uint>();
} }
break; break;
case 'b': // blockHeight
if (strcmp(key, "block") == 0) {
blockHeight = tag[1].as<uint>();
}
break;
} }
} }
@ -179,19 +171,13 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
if (!typeValue.isEmpty()) { if (!typeValue.isEmpty()) {
if (typeValue == "priceUsd") { if (typeValue == "priceUsd") {
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD); processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
if (blockHeight != 0) {
auto& blockNotify = BlockNotify::getInstance();
blockNotify.processNewBlock(blockHeight);
}
} }
else if (typeValue == "blockHeight") { else if (typeValue == "blockHeight") {
auto& blockNotify = BlockNotify::getInstance(); processNewBlock(obj["content"].as<uint>());
blockNotify.processNewBlock(obj["content"].as<uint>());
} }
if (medianFee != 0) { if (medianFee != 0) {
auto& blockNotify = BlockNotify::getInstance(); processNewBlockFee(medianFee);
blockNotify.processNewBlockFee(medianFee);
} }
} }
} }
@ -296,11 +282,11 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
} }
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
EPDManager::getInstance().setContent(textEpdContent); setEpdContent(textEpdContent);
vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250)); vTaskDelay(pdMS_TO_TICKS(315 * NUM_SCREENS) + pdMS_TO_TICKS(250));
if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP)) if (preferences.getBool("ledFlashOnZap", DEFAULT_LED_FLASH_ON_ZAP))
{ {
getLedHandler().queueEffect(LED_EFFECT_NOSTR_ZAP); queueLedEffect(LED_EFFECT_NOSTR_ZAP);
} }
if (timerPeriod > 0) if (timerPeriod > 0)
{ {
@ -308,19 +294,3 @@ void handleNostrZapCallback(const String &subId, nostr::SignedNostrEvent *event)
timerPeriod * usPerSecond); timerPeriod * usPerSecond);
} }
} }
// void onNostrEvent(const String &subId, const nostr::Event &event) {
// // This is the callback that will be called when a new event is received
// if (event.kind == 9735) {
// // Parse the zap amount from the event
// uint16_t amount = parseZapAmount(event);
// if (amount > 0) {
// std::array<std::string, NUM_SCREENS> zapContent = parseZapNotify(amount, true);
// EPDManager::getInstance().setContent(zapContent);
// if (preferences.getBool("ledFlashOnUpd", DEFAULT_LED_FLASH_ON_UPD)) {
// getLedHandler().queueEffect(LED_FLASH_BLOCK_NOTIFY);
// }
// }
// }
// }

View file

@ -1,5 +1,4 @@
#include "ota.hpp" #include "ota.hpp"
#include "led_handler.hpp"
TaskHandle_t taskOtaHandle = NULL; TaskHandle_t taskOtaHandle = NULL;
bool isOtaUpdating = false; bool isOtaUpdating = false;
@ -32,9 +31,6 @@ void setupOTA()
void onOTAProgress(unsigned int progress, unsigned int total) void onOTAProgress(unsigned int progress, unsigned int total)
{ {
uint percentage = progress / (total / 100); uint percentage = progress / (total / 100);
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
pixels.fill(pixels.Color(0, 255, 0)); pixels.fill(pixels.Color(0, 255, 0));
if (percentage < 100) if (percentage < 100)
{ {
@ -57,10 +53,10 @@ void onOTAProgress(unsigned int progress, unsigned int total)
void onOTAStart() void onOTAStart()
{ {
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A", std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A",
"T", "E", "!"}; "T", "E", "!"};
EPDManager::getInstance().setContent(epdContent); setEpdContent(epdContent);
// Stop all timers // Stop all timers
esp_timer_stop(screenRotateTimer); esp_timer_stop(screenRotateTimer);
esp_timer_stop(minuteTimer); esp_timer_stop(minuteTimer);
@ -74,8 +70,8 @@ void onOTAStart()
ButtonHandler::suspendTask(); ButtonHandler::suspendTask();
// stopWebServer(); // stopWebServer();
auto& blockNotify = BlockNotify::getInstance(); stopBlockNotify();
blockNotify.stop(); stopPriceNotify();
} }
void handleOTATask(void *parameter) void handleOTATask(void *parameter)
@ -88,15 +84,15 @@ void handleOTATask(void *parameter)
{ {
if (msg.updateType == UPDATE_ALL) { if (msg.updateType == UPDATE_ALL) {
isOtaUpdating = true; isOtaUpdating = true;
getLedHandler().queueEffect(LED_FLASH_UPDATE); queueLedEffect(LED_FLASH_UPDATE);
int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI); int resultWebUi = downloadUpdateHandler(UPDATE_WEBUI);
getLedHandler().queueEffect(LED_FLASH_UPDATE); queueLedEffect(LED_FLASH_UPDATE);
int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE); int resultFw = downloadUpdateHandler(UPDATE_FIRMWARE);
if (resultWebUi == 0 && resultFw == 0) { if (resultWebUi == 0 && resultFw == 0) {
ESP.restart(); ESP.restart();
} else { } else {
getLedHandler().queueEffect(LED_FLASH_ERROR); queueLedEffect(LED_FLASH_ERROR);
vTaskDelay(pdMS_TO_TICKS(3000)); vTaskDelay(pdMS_TO_TICKS(3000));
ESP.restart(); ESP.restart();
} }

View file

@ -2,64 +2,103 @@
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin"; 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; uint currentPrice = 90000;
unsigned long int lastPriceUpdate; unsigned long int lastPriceUpdate;
bool priceNotifyInit = false; bool priceNotifyInit = false;
std::map<char, std::uint64_t> currencyMap; std::map<char, std::uint64_t> currencyMap;
std::map<char, unsigned long int> lastUpdateMap; std::map<char, unsigned long int> lastUpdateMap;
TaskHandle_t priceNotifyTaskHandle; WebSocketsClient priceNotifyWs;
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
void setupPriceNotify() void setupPriceNotify()
{ {
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin"); config = {.uri = wsServerPrice,
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) { .user_agent = USER_AGENT};
onWebsocketPriceEvent(type, payload, length); config.cert_pem = isrg_root_x1cert;
});
webSocket.setReconnectInterval(5000);
webSocket.enableHeartbeat(15000, 3000, 2);
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>()) // void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) {
{ // switch(type) {
if (currentPrice != doc["bitcoin"].as<long>()) // case WStype_DISCONNECTED:
{ // Serial.printf("[WSc] Disconnected!\n");
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD); // break;
} // case WStype_CONNECTED:
} // {
break; // Serial.printf("[WSc] Connected to url: %s\n", payload);
}
case WStype_BIN:
break; // break;
case WStype_ERROR: // }
case WStype_FRAGMENT_TEXT_START: // case WStype_TEXT:
case WStype_FRAGMENT_BIN_START: // String message = String((char*)payload);
case WStype_FRAGMENT: // onWebsocketPriceMessage(message);
case WStype_PING: // break;
case WStype_PONG: // case WStype_BIN:
case WStype_FRAGMENT_FIN: // break;
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) void processNewPrice(uint newPrice, char currency)
@ -136,7 +175,9 @@ void setPrice(uint newPrice, char currency)
bool isPriceNotifyConnected() bool isPriceNotifyConnected()
{ {
return webSocket.isConnected(); if (clientPrice == NULL)
return false;
return esp_websocket_client_is_connected(clientPrice);
} }
bool getPriceNotifyInit() bool getPriceNotifyInit()
@ -146,30 +187,24 @@ bool getPriceNotifyInit()
void stopPriceNotify() void stopPriceNotify()
{ {
webSocket.disconnect(); if (clientPrice == NULL)
if (priceNotifyTaskHandle != NULL) { return;
vTaskDelete(priceNotifyTaskHandle); esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
priceNotifyTaskHandle = NULL; esp_websocket_client_stop(clientPrice);
} esp_websocket_client_destroy(clientPrice);
clientPrice = NULL;
} }
void restartPriceNotify() void restartPriceNotify()
{ {
stopPriceNotify(); stopPriceNotify();
setupPriceNotify(); if (clientPrice == NULL)
}
void taskPriceNotify(void *pvParameters)
{
for (;;)
{ {
webSocket.loop(); setupPriceNotify();
vTaskDelay(10 / portTICK_PERIOD_MS); return;
} }
} // esp_websocket_client_close(clientPrice, pdMS_TO_TICKS(5000));
// esp_websocket_client_stop(clientPrice);
void setupPriceNotifyTask() // esp_websocket_client_start(clientPrice);
{
xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY,
&priceNotifyTaskHandle);
} }

View file

@ -2,22 +2,24 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <WebSocketsClient.h> #include <esp_websocket_client.h>
#include "block_notify.hpp"
#include <string> #include <string>
#include "lib/screen_handler.hpp" #include "lib/screen_handler.hpp"
extern TaskHandle_t priceNotifyTaskHandle;
void setupPriceNotify(); 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); uint getPrice(char currency);
void setPrice(uint newPrice, char currency); void setPrice(uint newPrice, char currency);
//void processNewPrice(uint newPrice);
void processNewPrice(uint newPrice, char currency); void processNewPrice(uint newPrice, char currency);
bool isPriceNotifyConnected(); bool isPriceNotifyConnected();

View file

@ -203,7 +203,7 @@ void ScreenHandler::showSystemStatusScreen() {
String((int)round(ESP.getFreeHeap() / 1024)) + "/" + String((int)round(ESP.getFreeHeap() / 1024)) + "/" +
(int)round(ESP.getHeapSize() / 1024); (int)round(ESP.getHeapSize() / 1024);
setCurrentScreen(SCREEN_CUSTOM); setCurrentScreen(SCREEN_CUSTOM);
EPDManager::getInstance().setContent(sysStatusEpdContent); setEpdContent(sysStatusEpdContent);
} }
// Keep these as free functions // Keep these as free functions
@ -220,9 +220,9 @@ void workerTask(void *pvParameters) {
currentScreenValue != SCREEN_BITAXE_BESTDIFF) break; currentScreenValue != SCREEN_BITAXE_BESTDIFF) break;
taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ? taskEpdContent = (currentScreenValue == SCREEN_BITAXE_HASHRATE) ?
parseBitaxeHashRate(BitAxeFetch::getInstance().getHashRate()) : parseBitaxeHashRate(getBitAxeHashRate()) :
parseBitaxeBestDiff(BitAxeFetch::getInstance().getBestDiff()); parseBitaxeBestDiff(getBitaxeBestDiff());
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
break; break;
} }
@ -231,11 +231,10 @@ void workerTask(void *pvParameters) {
currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break; currentScreenValue != SCREEN_MINING_POOL_STATS_EARNINGS) break;
taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ? taskEpdContent = (currentScreenValue == SCREEN_MINING_POOL_STATS_HASHRATE) ?
parseMiningPoolStatsHashRate(MiningPoolStatsFetch::getInstance().getHashRate(), *MiningPoolStatsFetch::getInstance().getPool()) : parseMiningPoolStatsHashRate(getMiningPoolStatsHashRate(), *getMiningPool()) :
parseMiningPoolStatsDailyEarnings(MiningPoolStatsFetch::getInstance().getDailyEarnings(), parseMiningPoolStatsDailyEarnings(getMiningPoolStatsDailyEarnings(),
MiningPoolStatsFetch::getInstance().getPool()->getDailyEarningsLabel(), getMiningPool()->getDailyEarningsLabel(), *getMiningPool());
*MiningPoolStatsFetch::getInstance().getPool()); setEpdContent(taskEpdContent);
EPDManager::getInstance().setContent(taskEpdContent);
break; break;
} }
@ -251,33 +250,31 @@ void workerTask(void *pvParameters) {
} else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) { } else if (currentScreenValue == SCREEN_SATS_PER_CURRENCY) {
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL)); taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
} else { } else {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent =
taskEpdContent = parseMarketCap(blockNotify.getBlockHeight(), price, currency, preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR)); parseMarketCap(getBlockHeight(), price, currency,
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
} }
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
break; break;
} }
case TASK_FEE_UPDATE: { case TASK_FEE_UPDATE: {
if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) { if (currentScreenValue == SCREEN_BLOCK_FEE_RATE) {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(getBlockMedianFee()));
taskEpdContent = parseBlockFees(static_cast<std::uint16_t>(blockNotify.getBlockMedianFee())); setEpdContent(taskEpdContent);
EPDManager::getInstance().setContent(taskEpdContent);
} }
break; break;
} }
case TASK_BLOCK_UPDATE: { case TASK_BLOCK_UPDATE: {
if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) { if (currentScreenValue != SCREEN_HALVING_COUNTDOWN) {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseBlockHeight(getBlockHeight());
taskEpdContent = parseBlockHeight(blockNotify.getBlockHeight());
} else { } else {
auto& blockNotify = BlockNotify::getInstance(); taskEpdContent = parseHalvingCountdown(getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
taskEpdContent = parseHalvingCountdown(blockNotify.getBlockHeight(), preferences.getBool("useBlkCountdown", DEFAULT_USE_BLOCK_COUNTDOWN));
} }
if (currentScreenValue == SCREEN_HALVING_COUNTDOWN || if (currentScreenValue == SCREEN_HALVING_COUNTDOWN ||
currentScreenValue == SCREEN_BLOCK_HEIGHT) { currentScreenValue == SCREEN_BLOCK_HEIGHT) {
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
} }
break; break;
} }
@ -304,7 +301,7 @@ void workerTask(void *pvParameters) {
for (uint i = 1; i < NUM_SCREENS; i++) { for (uint i = 1; i < NUM_SCREENS; i++) {
taskEpdContent[i] = timeString[i]; taskEpdContent[i] = timeString[i];
} }
EPDManager::getInstance().setContent(taskEpdContent); setEpdContent(taskEpdContent);
} }
break; break;
@ -332,6 +329,8 @@ void setupTasks() {
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY, xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
&taskScreenRotateTaskHandle); &taskScreenRotateTaskHandle);
waitUntilNoneBusy();
if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1) if (findScreenIndexByValue(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)) != -1)
ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); ScreenHandler::setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
} }

View file

@ -40,39 +40,39 @@
// "MrY=\n" // "MrY=\n"
// "-----END CERTIFICATE-----\n"; // "-----END CERTIFICATE-----\n";
// const char* isrg_root_x1cert = R"EOF( const char* isrg_root_x1cert = R"EOF(
// -----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
// MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
// TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
// cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
// WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
// ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
// MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
// h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
// 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
// A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
// T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
// B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
// B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
// KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
// OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
// jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
// qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
// rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
// HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
// hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
// ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
// 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
// NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
// ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
// TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
// jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
// oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
// 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
// mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
// emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
// -----END CERTIFICATE----- -----END CERTIFICATE-----
// )EOF"; )EOF";
#ifdef TEST_SCREENS #ifdef TEST_SCREENS
@ -180,4 +180,3 @@ void HttpHelper::end(HTTPClient* http) {
delete http; delete http;
} }
} }

View file

@ -16,8 +16,6 @@
#include <mutex> #include <mutex>
#include <utils.hpp> #include <utils.hpp>
#include <array>
#include <string>
#include "defaults.hpp" #include "defaults.hpp"
@ -68,7 +66,7 @@ const int usPerSecond = 1000000;
const int usPerMinute = 60 * usPerSecond; const int usPerMinute = 60 * usPerSecond;
// extern const char *github_root_ca; // 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 rootca_crt_bundle_start[] asm("_binary_x509_crt_bundle_start");
// extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start"); // extern const uint8_t ocean_logo_comp[] asm("_binary_ocean_gz_start");
@ -121,4 +119,3 @@ private:
static bool certBundleSet; static bool certBundleSet;
static WiFiClient insecureClient; static WiFiClient insecureClient;
}; };

View file

@ -1,5 +1,4 @@
#include "timers.hpp" #include "timers.hpp"
#include "led_handler.hpp"
esp_timer_handle_t screenRotateTimer; esp_timer_handle_t screenRotateTimer;
esp_timer_handle_t minuteTimer; esp_timer_handle_t minuteTimer;
@ -50,11 +49,11 @@ void setTimerActive(bool status) {
if (status) { if (status) {
esp_timer_start_periodic(screenRotateTimer, esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond); getTimerSeconds() * usPerSecond);
getLedHandler().queueEffect(LED_EFFECT_START_TIMER); queueLedEffect(LED_EFFECT_START_TIMER);
preferences.putBool("timerActive", true); preferences.putBool("timerActive", true);
} else { } else {
esp_timer_stop(screenRotateTimer); esp_timer_stop(screenRotateTimer);
getLedHandler().queueEffect(LED_EFFECT_PAUSE_TIMER); queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false); preferences.putBool("timerActive", false);
} }
@ -69,14 +68,12 @@ void IRAM_ATTR minuteTimerISR(void *arg) {
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0}; WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken); xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
TaskHandle_t bitaxeHandle = BitAxeFetch::getInstance().getTaskHandle(); if (bitaxeFetchTaskHandle != NULL) {
if (bitaxeHandle != NULL) { vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
vTaskNotifyGiveFromISR(bitaxeHandle, &xHigherPriorityTaskWoken);
} }
TaskHandle_t miningPoolHandle = MiningPoolStatsFetch::getInstance().getTaskHandle(); if (miningPoolStatsFetchTaskHandle != NULL) {
if (miningPoolHandle != NULL) { vTaskNotifyGiveFromISR(miningPoolStatsFetchTaskHandle, &xHigherPriorityTaskWoken);
vTaskNotifyGiveFromISR(miningPoolHandle, &xHigherPriorityTaskWoken);
} }
if (xHigherPriorityTaskWoken == pdTRUE) { if (xHigherPriorityTaskWoken == pdTRUE) {

View file

@ -106,11 +106,6 @@ namespace V2Notify
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeMsgPack(doc, payload, length); DeserializationError error = deserializeMsgPack(doc, payload, length);
if (error) {
Serial.println(F("Error deserializing message"));
break;
}
V2Notify::handleV2Message(doc); V2Notify::handleV2Message(doc);
break; break;
} }
@ -127,33 +122,24 @@ namespace V2Notify
void handleV2Message(JsonDocument doc) void handleV2Message(JsonDocument doc)
{ {
if (doc["blockheight"].is<uint>()) if (doc.containsKey("blockheight"))
{ {
uint newBlockHeight = doc["blockheight"].as<uint>(); uint newBlockHeight = doc["blockheight"].as<uint>();
if (newBlockHeight == BlockNotify::getInstance().getBlockHeight()) if (newBlockHeight == getBlockHeight())
{ {
return; return;
} }
if (debugLogEnabled()) { processNewBlock(newBlockHeight);
Serial.print(F("processNewBlock "));
Serial.println(newBlockHeight);
}
BlockNotify::getInstance().processNewBlock(newBlockHeight);
} }
else if (doc["blockfee"].is<uint>()) else if (doc.containsKey("blockfee"))
{ {
uint medianFee = doc["blockfee"].as<uint>(); uint medianFee = doc["blockfee"].as<uint>();
if (debugLogEnabled()) { processNewBlockFee(medianFee);
Serial.print(F("processNewBlockFee "));
Serial.println(medianFee);
}
BlockNotify::getInstance().processNewBlockFee(medianFee);
} }
else if (doc["price"].is<JsonObject>()) else if (doc.containsKey("price"))
{ {
// Iterate through the key-value pairs of the "price" object // Iterate through the key-value pairs of the "price" object
@ -172,7 +158,7 @@ namespace V2Notify
for (;;) for (;;)
{ {
webSocket.loop(); webSocket.loop();
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(10 / portTICK_PERIOD_MS);
} }
} }

View file

@ -1,11 +1,9 @@
#include "webserver.hpp" #include "webserver.hpp"
#include "lib/led_handler.hpp"
#include "lib/shared.hpp"
static const char* JSON_CONTENT = "application/json"; static const char* JSON_CONTENT = "application/json";
static const char *const PROGMEM strSettings[] = { 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"}; static const char *const PROGMEM uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness", "flMaxBrightness", "flEffectDelay", "luxLightToggle", "wpTimeout"};
@ -30,8 +28,7 @@ TaskHandle_t eventSourceTaskHandle;
void setupWebserver() void setupWebserver()
{ {
events.onConnect([](AsyncEventSourceClient *client) events.onConnect([](AsyncEventSourceClient *client)
{ client->send("welcome", NULL, millis(), 1000); { client->send("welcome", NULL, millis(), 1000); });
});
server.addHandler(&events); server.addHandler(&events);
AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html"); AsyncStaticWebHandler &staticHandler = server.serveStatic("/", LittleFS, "/").setDefaultFile("index.html");
@ -234,7 +231,6 @@ void asyncFirmwareUpdateHandler(AsyncWebServerRequest *request, String filename,
JsonDocument getStatusObject() JsonDocument getStatusObject()
{ {
auto& ledHandler = getLedHandler();
JsonDocument root; JsonDocument root;
root["currentScreen"] = ScreenHandler::getCurrentScreen(); root["currentScreen"] = ScreenHandler::getCurrentScreen();
@ -242,22 +238,25 @@ JsonDocument getStatusObject()
root["timerRunning"] = isTimerActive(); root["timerRunning"] = isTimerActive();
root["isOTAUpdating"] = getIsOTAUpdating(); root["isOTAUpdating"] = getIsOTAUpdating();
root["espUptime"] = esp_timer_get_time() / 1000000; root["espUptime"] = esp_timer_get_time() / 1000000;
// root["currentPrice"] = getPrice();
// root["currentBlockHeight"] = getBlockHeight();
root["espFreeHeap"] = ESP.getFreeHeap(); root["espFreeHeap"] = ESP.getFreeHeap();
root["espHeapSize"] = ESP.getHeapSize(); root["espHeapSize"] = ESP.getHeapSize();
// root["espFreePsram"] = ESP.getFreePsram();
// root["espPsramSize"] = ESP.getPsramSize();
JsonObject conStatus = root["connectionStatus"].to<JsonObject>(); JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
conStatus["price"] = isPriceNotifyConnected(); conStatus["price"] = isPriceNotifyConnected();
auto& blockNotify = BlockNotify::getInstance(); conStatus["blocks"] = isBlockNotifyConnected();
conStatus["blocks"] = blockNotify.isConnected();
conStatus["V2"] = V2Notify::isV2NotifyConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected();
conStatus["nostr"] = nostrConnected(); conStatus["nostr"] = nostrConnected();
root["rssi"] = WiFi.RSSI(); root["rssi"] = WiFi.RSSI();
root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency()); root["currency"] = getCurrencyCode(ScreenHandler::getCurrentCurrency());
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
std::vector<uint16_t> statuses = ledHandler.frontlightGetStatus(); std::vector<uint16_t> statuses = frontlightGetStatus();
uint16_t arr[NUM_SCREENS]; uint16_t arr[NUM_SCREENS];
std::copy(statuses.begin(), statuses.end(), arr); std::copy(statuses.begin(), statuses.end(), arr);
@ -271,24 +270,22 @@ JsonDocument getStatusObject()
#endif #endif
// Add DND status // Add DND status
root["dnd"]["enabled"] = ledHandler.isDNDEnabled(); root["dnd"]["enabled"] = dndEnabled;
root["dnd"]["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled;
root["dnd"]["startTime"] = String(ledHandler.getDNDStartHour()) + ":" + root["dnd"]["startTime"] = String(dndTimeRange.startHour) + ":" +
(ledHandler.getDNDStartMinute() < 10 ? "0" : "") + String(ledHandler.getDNDStartMinute()); (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute);
root["dnd"]["endTime"] = String(ledHandler.getDNDEndHour()) + ":" + root["dnd"]["endTime"] = String(dndTimeRange.endHour) + ":" +
(ledHandler.getDNDEndMinute() < 10 ? "0" : "") + String(ledHandler.getDNDEndMinute()); (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute);
root["dnd"]["active"] = ledHandler.isDNDActive(); root["dnd"]["active"] = isDNDActive();
return root; return root;
} }
JsonDocument getLedStatusObject() JsonDocument getLedStatusObject()
{ {
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonDocument root; JsonDocument root;
JsonArray colors = root["data"].to<JsonArray>(); JsonArray colors = root["data"].to<JsonArray>();
// Adafruit_NeoPixel pix = getPixels();
for (uint i = 0; i < pixels.numPixels(); i++) for (uint i = 0; i < pixels.numPixels(); i++)
{ {
@ -298,7 +295,13 @@ JsonDocument getLedStatusObject()
uint blue = pixColor & 0xFF; uint blue = pixColor & 0xFF;
char hexColor[8]; char hexColor[8];
snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue); snprintf(hexColor, sizeof(hexColor), "#%02X%02X%02X", red, green, blue);
colors.add(hexColor);
JsonObject object = colors.add<JsonObject>();
object["red"] = red;
object["green"] = green;
object["blue"] = blue;
object["hex"] = hexColor;
} }
return root; return root;
@ -307,18 +310,14 @@ JsonDocument getLedStatusObject()
void eventSourceUpdate() { void eventSourceUpdate() {
if (!events.count()) return; if (!events.count()) return;
static JsonDocument doc; JsonDocument doc = getStatusObject();
doc.clear(); doc["leds"] = getLedStatusObject()["data"];
JsonDocument root = getStatusObject();
root["leds"] = getLedStatusObject()["data"];
// Get current EPD content directly as array // Get current EPD content directly as array
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
// Add EPD content arrays // Add EPD content arrays
JsonArray data = root["data"].to<JsonArray>(); JsonArray data = doc["data"].to<JsonArray>();
// Copy array elements directly // Copy array elements directly
for(const auto& content : epdContent) { for(const auto& content : epdContent) {
@ -326,7 +325,7 @@ void eventSourceUpdate() {
} }
String buffer; String buffer;
serializeJson(root, buffer); serializeJson(doc, buffer);
events.send(buffer.c_str(), "status"); events.send(buffer.c_str(), "status");
} }
@ -342,7 +341,7 @@ void onApiStatus(AsyncWebServerRequest *request)
JsonDocument root = getStatusObject(); JsonDocument root = getStatusObject();
// Get current EPD content directly as array // Get current EPD content directly as array
std::array<String, NUM_SCREENS> epdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> epdContent = getCurrentEpdContent();
// Add EPD content arrays // Add EPD content arrays
JsonArray data = root["data"].to<JsonArray>(); JsonArray data = root["data"].to<JsonArray>();
@ -384,9 +383,11 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
*/ */
void onApiFullRefresh(AsyncWebServerRequest *request) void onApiFullRefresh(AsyncWebServerRequest *request)
{ {
EPDManager::getInstance().forceFullRefresh(); forceFullRefresh();
std::array<String, NUM_SCREENS> newEpdContent = EPDManager::getInstance().getCurrentContent(); std::array<String, NUM_SCREENS> newEpdContent = getCurrentEpdContent();
EPDManager::getInstance().setContent(newEpdContent, true);
setEpdContent(newEpdContent, true);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -433,7 +434,7 @@ void onApiShowText(AsyncWebServerRequest *request)
textEpdContent[i] = t[i]; textEpdContent[i] = t[i];
} }
EPDManager::getInstance().setContent(textEpdContent); setEpdContent(textEpdContent);
} }
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
request->send(HTTP_OK); request->send(HTTP_OK);
@ -451,7 +452,7 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
i++; i++;
} }
EPDManager::getInstance().setContent(epdContent); setEpdContent(epdContent);
ScreenHandler::setCurrentScreen(SCREEN_CUSTOM); ScreenHandler::setCurrentScreen(SCREEN_CUSTOM);
request->send(HTTP_OK); request->send(HTTP_OK);
@ -479,13 +480,13 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
if (inverted) { if (inverted) {
preferences.putUInt("fgColor", GxEPD_WHITE); preferences.putUInt("fgColor", GxEPD_WHITE);
preferences.putUInt("bgColor", GxEPD_BLACK); preferences.putUInt("bgColor", GxEPD_BLACK);
EPDManager::getInstance().setForegroundColor(GxEPD_WHITE); setFgColor(GxEPD_WHITE);
EPDManager::getInstance().setBackgroundColor(GxEPD_BLACK); setBgColor(GxEPD_BLACK);
} else { } else {
preferences.putUInt("fgColor", GxEPD_BLACK); preferences.putUInt("fgColor", GxEPD_BLACK);
preferences.putUInt("bgColor", GxEPD_WHITE); preferences.putUInt("bgColor", GxEPD_WHITE);
EPDManager::getInstance().setForegroundColor(GxEPD_BLACK); setFgColor(GxEPD_BLACK);
EPDManager::getInstance().setBackgroundColor(GxEPD_WHITE); setBgColor(GxEPD_WHITE);
} }
Serial.printf("Setting invertedColor to %d\r\n", inverted); Serial.printf("Setting invertedColor to %d\r\n", inverted);
settingsChanged = true; settingsChanged = true;
@ -618,28 +619,26 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
} }
// Handle DND settings // Handle DND settings
if (settings["dnd"].is<JsonObject>()) { if (settings.containsKey("dnd")) {
JsonObject dndObj = settings["dnd"]; JsonObject dndObj = settings["dnd"];
auto& ledHandler = getLedHandler(); if (dndObj.containsKey("timeBasedEnabled")) {
setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as<bool>());
if (dndObj["timeBasedEnabled"].is<bool>()) {
ledHandler.setDNDTimeBasedEnabled(dndObj["timeBasedEnabled"].as<bool>());
} }
if (dndObj["startHour"].is<uint8_t>() && dndObj["startMinute"].is<uint8_t>() && if (dndObj.containsKey("startHour") && dndObj.containsKey("startMinute") &&
dndObj["endHour"].is<uint8_t>() && dndObj["endMinute"].is<uint8_t>()) { dndObj.containsKey("endHour") && dndObj.containsKey("endMinute")) {
ledHandler.setDNDTimeRange( setDNDTimeRange(
dndObj["startHour"].as<uint8_t>(), dndObj["startHour"].as<uint8_t>(),
dndObj["startMinute"].as<uint8_t>(), dndObj["startMinute"].as<uint8_t>(),
dndObj["endHour"].as<uint8_t>(), dndObj["endHour"].as<uint8_t>(),
dndObj["endMinute"].as<uint8_t>()); dndObj["endMinute"].as<uint8_t>()
);
} }
} }
request->send(HTTP_OK); request->send(HTTP_OK);
if (settingsChanged) if (settingsChanged)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_FLASH_SUCCESS);
ledHandler.queueEffect(LED_FLASH_SUCCESS);
} }
} }
@ -660,8 +659,7 @@ void onApiRestart(AsyncWebServerRequest *request)
void onApiIdentify(AsyncWebServerRequest *request) void onApiIdentify(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); queueLedEffect(LED_FLASH_IDENTIFY);
ledHandler.queueEffect(LED_FLASH_IDENTIFY);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -684,7 +682,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
JsonDocument root; JsonDocument root;
root["numScreens"] = NUM_SCREENS; root["numScreens"] = NUM_SCREENS;
root["invertedColor"] = preferences.getBool("invertedColor", EPDManager::getInstance().getForegroundColor() == GxEPD_WHITE); root["invertedColor"] = preferences.getBool("invertedColor", getFgColor() == GxEPD_WHITE);
root["timerSeconds"] = getTimerSeconds(); root["timerSeconds"] = getTimerSeconds();
root["timerRunning"] = isTimerActive(); root["timerRunning"] = isTimerActive();
root["minSecPriceUpd"] = preferences.getUInt( root["minSecPriceUpd"] = preferences.getUInt(
@ -701,9 +699,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
root["mempoolSecure"] = preferences.getBool("mempoolSecure", DEFAULT_MEMPOOL_SECURE); 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) // Nostr settings (used for NOSTR_SOURCE or when zapNotify is enabled)
root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB); root["nostrPubKey"] = preferences.getString("nostrPubKey", DEFAULT_NOSTR_NPUB);
root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY); root["nostrRelay"] = preferences.getString("nostrRelay", DEFAULT_NOSTR_RELAY);
@ -802,13 +797,12 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL); root["ceDisableSSL"] = preferences.getBool("ceDisableSSL", DEFAULT_CUSTOM_ENDPOINT_DISABLE_SSL);
// Add DND settings // Add DND settings
auto& ledHandler = getLedHandler(); root["dnd"]["enabled"] = dndEnabled;
root["dnd"]["enabled"] = ledHandler.isDNDEnabled(); root["dnd"]["timeBasedEnabled"] = dndTimeBasedEnabled;
root["dnd"]["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); root["dnd"]["startHour"] = dndTimeRange.startHour;
root["dnd"]["startHour"] = ledHandler.getDNDStartHour(); root["dnd"]["startMinute"] = dndTimeRange.startMinute;
root["dnd"]["startMinute"] = ledHandler.getDNDStartMinute(); root["dnd"]["endHour"] = dndTimeRange.endHour;
root["dnd"]["endHour"] = ledHandler.getDNDEndHour(); root["dnd"]["endMinute"] = dndTimeRange.endMinute;
root["dnd"]["endMinute"] = ledHandler.getDNDEndMinute();
AsyncResponseStream *response = AsyncResponseStream *response =
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
@ -825,7 +819,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
const AsyncWebParameter *fgColor = request->getParam("fgColor", true); const AsyncWebParameter *fgColor = request->getParam("fgColor", true);
uint32_t color = strtol(fgColor->value().c_str(), NULL, 16); uint32_t color = strtol(fgColor->value().c_str(), NULL, 16);
preferences.putUInt("fgColor", color); preferences.putUInt("fgColor", color);
EPDManager::getInstance().setForegroundColor(color); setFgColor(color);
// Serial.print(F("Setting foreground color to ")); // Serial.print(F("Setting foreground color to "));
// Serial.println(fgColor->value().c_str()); // Serial.println(fgColor->value().c_str());
settingsChanged = true; settingsChanged = true;
@ -836,7 +830,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
uint32_t color = strtol(bgColor->value().c_str(), NULL, 16); uint32_t color = strtol(bgColor->value().c_str(), NULL, 16);
preferences.putUInt("bgColor", color); preferences.putUInt("bgColor", color);
EPDManager::getInstance().setBackgroundColor(color); setBgColor(color);
// Serial.print(F("Setting background color to ")); // Serial.print(F("Setting background color to "));
// Serial.println(bgColor->value().c_str()); // Serial.println(bgColor->value().c_str());
settingsChanged = true; settingsChanged = true;
@ -915,7 +909,7 @@ void onApiStopDataSources(AsyncWebServerRequest *request)
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
stopPriceNotify(); stopPriceNotify();
BlockNotify::getInstance().stop(); stopBlockNotify();
request->send(response); request->send(response);
} }
@ -926,15 +920,16 @@ void onApiRestartDataSources(AsyncWebServerRequest *request)
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
restartPriceNotify(); restartPriceNotify();
BlockNotify::getInstance().restart(); restartBlockNotify();
// setupPriceNotify();
// setupBlockNotify();
request->send(response); request->send(response);
} }
void onApiLightsOff(AsyncWebServerRequest *request) void onApiLightsOff(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); setLights(0, 0, 0);
ledHandler.setLights(0, 0, 0);
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -949,15 +944,13 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
if (rgbColor.compareTo("off") == 0) if (rgbColor.compareTo("off") == 0)
{ {
auto& ledHandler = getLedHandler(); setLights(0, 0, 0);
ledHandler.setLights(0, 0, 0);
} }
else else
{ {
uint r, g, b; uint r, g, b;
sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b); sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b);
auto& ledHandler = getLedHandler(); setLights(r, g, b);
ledHandler.setLights(r, g, b);
} }
JsonDocument doc; JsonDocument doc;
@ -975,9 +968,6 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
{ {
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonArray lights = json.as<JsonArray>(); JsonArray lights = json.as<JsonArray>();
if (lights.size() != pixels.numPixels()) if (lights.size() != pixels.numPixels())
@ -1026,7 +1016,7 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
} }
pixels.show(); pixels.show();
ledHandler.saveLedState(); saveLedState();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -1090,21 +1080,19 @@ void onApiShowCurrency(AsyncWebServerRequest *request)
#ifdef HAS_FRONTLIGHT #ifdef HAS_FRONTLIGHT
void onApiFrontlightOn(AsyncWebServerRequest *request) void onApiFrontlightOn(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFadeInAll();
ledHandler.frontlightFadeInAll();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
void onApiFrontlightStatus(AsyncWebServerRequest *request) void onApiFrontlightStatus(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler();
AsyncResponseStream *response = AsyncResponseStream *response =
request->beginResponseStream(JSON_CONTENT); request->beginResponseStream(JSON_CONTENT);
JsonDocument root; JsonDocument root;
std::vector<uint16_t> statuses = ledHandler.frontlightGetStatus(); std::vector<uint16_t> statuses = frontlightGetStatus();
uint16_t arr[NUM_SCREENS]; uint16_t arr[NUM_SCREENS];
std::copy(statuses.begin(), statuses.end(), arr); std::copy(statuses.begin(), statuses.end(), arr);
@ -1117,8 +1105,7 @@ void onApiFrontlightStatus(AsyncWebServerRequest *request)
void onApiFrontlightFlash(AsyncWebServerRequest *request) void onApiFrontlightFlash(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFlash(preferences.getUInt("flEffectDelay"));
ledHandler.frontlightFlash(preferences.getUInt("flEffectDelay"));
request->send(HTTP_OK); request->send(HTTP_OK);
} }
@ -1127,8 +1114,7 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request)
{ {
if (request->hasParam("b")) if (request->hasParam("b"))
{ {
auto& ledHandler = getLedHandler(); frontlightSetBrightness(request->getParam("b")->value().toInt());
ledHandler.frontlightSetBrightness(request->getParam("b")->value().toInt());
request->send(HTTP_OK); request->send(HTTP_OK);
} }
else else
@ -1139,51 +1125,21 @@ void onApiFrontlightSetBrightness(AsyncWebServerRequest *request)
void onApiFrontlightOff(AsyncWebServerRequest *request) void onApiFrontlightOff(AsyncWebServerRequest *request)
{ {
auto& ledHandler = getLedHandler(); frontlightFadeOutAll();
ledHandler.frontlightFadeOutAll();
request->send(HTTP_OK); request->send(HTTP_OK);
} }
#endif #endif
void onApiDNDTimeBasedEnable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler();
ledHandler.setDNDTimeBasedEnabled(true);
request->send(200);
}
void onApiDNDTimeBasedDisable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler();
ledHandler.setDNDTimeBasedEnabled(false);
request->send(200);
}
void onApiDNDSetTimeRange(AsyncWebServerRequest *request) {
if (request->hasParam("startHour") && request->hasParam("startMinute") &&
request->hasParam("endHour") && request->hasParam("endMinute")) {
auto& ledHandler = getLedHandler();
uint8_t startHour = request->getParam("startHour")->value().toInt();
uint8_t startMinute = request->getParam("startMinute")->value().toInt();
uint8_t endHour = request->getParam("endHour")->value().toInt();
uint8_t endMinute = request->getParam("endMinute")->value().toInt();
ledHandler.setDNDTimeRange(startHour, startMinute, endHour, endMinute);
request->send(200);
} else {
request->send(400);
}
}
void onApiDNDStatus(AsyncWebServerRequest *request) { void onApiDNDStatus(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler();
JsonDocument doc; JsonDocument doc;
doc["enabled"] = ledHandler.isDNDEnabled(); doc["enabled"] = dndEnabled;
doc["timeBasedEnabled"] = ledHandler.isDNDTimeBasedEnabled(); doc["timeBasedEnabled"] = dndTimeBasedEnabled;
doc["startTime"] = String(ledHandler.getDNDStartHour()) + ":" + doc["startTime"] = String(dndTimeRange.startHour) + ":" +
(ledHandler.getDNDStartMinute() < 10 ? "0" : "") + String(ledHandler.getDNDStartMinute()); (dndTimeRange.startMinute < 10 ? "0" : "") + String(dndTimeRange.startMinute);
doc["endTime"] = String(ledHandler.getDNDEndHour()) + ":" + doc["endTime"] = String(dndTimeRange.endHour) + ":" +
(ledHandler.getDNDEndMinute() < 10 ? "0" : "") + String(ledHandler.getDNDEndMinute()); (dndTimeRange.endMinute < 10 ? "0" : "") + String(dndTimeRange.endMinute);
doc["active"] = ledHandler.isDNDActive(); doc["active"] = isDNDActive();
String response; String response;
serializeJson(doc, response); serializeJson(doc, response);
@ -1191,71 +1147,11 @@ void onApiDNDStatus(AsyncWebServerRequest *request) {
} }
void onApiDNDEnable(AsyncWebServerRequest *request) { void onApiDNDEnable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler(); setDNDEnabled(true);
ledHandler.setDNDEnabled(true);
request->send(200); request->send(200);
} }
void onApiDNDDisable(AsyncWebServerRequest *request) { void onApiDNDDisable(AsyncWebServerRequest *request) {
auto& ledHandler = getLedHandler(); setDNDEnabled(false);
ledHandler.setDNDEnabled(false);
request->send(200);
}
void onApiLightsGet(AsyncWebServerRequest *request)
{
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonDocument doc;
JsonArray lights = doc.createNestedArray("lights");
for (uint i = 0; i < pixels.numPixels(); i++)
{
uint32_t pixColor = pixels.getPixelColor(pixels.numPixels() - i - 1);
JsonObject light = lights.createNestedObject();
light["r"] = (uint8_t)(pixColor >> 16);
light["g"] = (uint8_t)(pixColor >> 8);
light["b"] = (uint8_t)pixColor;
}
String output;
serializeJson(doc, output);
request->send(200, "application/json", output);
}
void onApiLightsPost(AsyncWebServerRequest *request, uint8_t *data, size_t len,
size_t index, size_t total)
{
auto& ledHandler = getLedHandler();
auto& pixels = ledHandler.getPixels();
JsonDocument doc;
DeserializationError error = deserializeJson(doc, data);
if (error)
{
request->send(400);
return;
}
JsonArray lights = doc["lights"];
if (lights.size() != pixels.numPixels())
{
request->send(400);
return;
}
for (uint i = 0; i < pixels.numPixels(); i++)
{
JsonObject light = lights[i];
uint8_t red = light["r"];
uint8_t green = light["g"];
uint8_t blue = light["b"];
pixels.setPixelColor((pixels.numPixels() - i - 1),
pixels.Color(red, green, blue));
}
pixels.show();
request->send(200); request->send(200);
} }

View file

@ -18,8 +18,6 @@
#define WEBSERVER_H #define WEBSERVER_H
#include "ESPAsyncWebServer.h" #include "ESPAsyncWebServer.h"
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/led_handler.hpp"
#include "lib/block_notify.hpp"
uint wifiLostConnection; uint wifiLostConnection;
uint priceNotifyLostConnection = 0; uint priceNotifyLostConnection = 0;
@ -50,8 +48,7 @@ void handleBlockNotifyDisconnection() {
if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout if ((getUptime() - blockNotifyLostConnection) > 300) { // 5 minutes timeout
Serial.println(F("Block notification connection lost for 5 minutes, restarting handler...")); Serial.println(F("Block notification connection lost for 5 minutes, restarting handler..."));
auto& blockNotify = BlockNotify::getInstance(); restartBlockNotify();
blockNotify.restart();
blockNotifyLostConnection = 0; blockNotifyLostConnection = 0;
} }
} }
@ -61,14 +58,13 @@ void handleFrontlight() {
if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) { if (hasLightLevel() && preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) {
uint lightLevel = getLightLevel(); uint lightLevel = getLightLevel();
uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE); uint luxThreshold = preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE);
auto& ledHandler = getLedHandler();
if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) { if (lightLevel <= 1 && preferences.getBool("flOffWhenDark", DEFAULT_FL_OFF_WHEN_DARK)) {
if (ledHandler.frontlightIsOn()) ledHandler.frontlightFadeOutAll(); if (frontlightIsOn()) frontlightFadeOutAll();
} else if (lightLevel < luxThreshold && !ledHandler.frontlightIsOn()) { } else if (lightLevel < luxThreshold && !frontlightIsOn()) {
ledHandler.frontlightFadeInAll(); frontlightFadeInAll();
} else if (ledHandler.frontlightIsOn() && lightLevel > luxThreshold) { } else if (frontlightIsOn() && lightLevel > luxThreshold) {
ledHandler.frontlightFadeOutAll(); frontlightFadeOutAll();
} }
} }
#endif #endif
@ -94,18 +90,19 @@ void checkWiFiConnection() {
void checkMissedBlocks() { void checkMissedBlocks() {
Serial.println(F("Long time (45 min) since last block, checking if I missed anything...")); Serial.println(F("Long time (45 min) since last block, checking if I missed anything..."));
auto& blockNotify = BlockNotify::getInstance(); int currentBlock = getBlockFetch();
int currentBlock = blockNotify.fetchLatestBlock();
if (currentBlock != -1) { if (currentBlock != -1) {
if (currentBlock != blockNotify.getBlockHeight()) { if (currentBlock != getBlockHeight()) {
Serial.println(F("Detected stuck block height... restarting block handler.")); Serial.println(F("Detected stuck block height... restarting block handler."));
blockNotify.restart(); restartBlockNotify();
} }
blockNotify.setLastBlockUpdate(getUptime()); setLastBlockUpdate(getUptime());
} }
} }
void monitorDataConnections() { void monitorDataConnections() {
// Price notification monitoring // Price notification monitoring
if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) { if (getPriceNotifyInit() && !preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE) && !isPriceNotifyConnected()) {
handlePriceNotifyDisconnection(); handlePriceNotifyDisconnection();
@ -114,10 +111,9 @@ void monitorDataConnections() {
} }
// Block notification monitoring // Block notification monitoring
auto& blockNotify = BlockNotify::getInstance(); if (getBlockNotifyInit() && !isBlockNotifyConnected()) {
if (blockNotify.isInitialized() && !blockNotify.isConnected()) {
handleBlockNotifyDisconnection(); handleBlockNotifyDisconnection();
} else if (blockNotifyLostConnection > 0 && blockNotify.isConnected()) { } else if (blockNotifyLostConnection > 0 && isBlockNotifyConnected()) {
blockNotifyLostConnection = 0; blockNotifyLostConnection = 0;
} }
@ -129,7 +125,7 @@ void monitorDataConnections() {
} }
// Check for missed blocks // Check for missed blocks
if ((blockNotify.getLastBlockUpdate() - getUptime()) > 45 * 60) { if ((getLastBlockUpdate() - getUptime()) > 45 * 60) {
checkMissedBlocks(); checkMissedBlocks();
} }
} }
@ -141,6 +137,7 @@ extern "C" void app_main() {
bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE; bool thirdPartySource = getDataSource() == THIRD_PARTY_SOURCE;
while (true) { while (true) {
if (eventSourceTaskHandle != NULL) { if (eventSourceTaskHandle != NULL) {
xTaskNotifyGive(eventSourceTaskHandle); xTaskNotifyGive(eventSourceTaskHandle);