Compare commits

..

No commits in common. "main" and "2023-11-03-sysstats-on-webif" have entirely different histories.

31 changed files with 190 additions and 454 deletions

View file

@ -29,22 +29,21 @@ jobs:
python-version: '3.9' python-version: '3.9'
- name: Get current date - name: Get current date
id: dateAndTime id: dateAndTime
# run: echo "::set-output name=dateAndTime::$(date +'%Y-%m-%d-%H:%M')" run: echo "::set-output name=dateAndTime::$(date +'%Y-%m-%d-%H:%M')"
run: echo "dateAndTime=$(date +'%Y-%m-%d-%H:%M')" >> $GITHUB_OUTPUT
- name: Install PlatformIO Core - name: Install PlatformIO Core
run: pip install --upgrade platformio run: pip install --upgrade platformio
- name: Build BTClock firmware - name: Build BTClock firmware
run: pio run -e default run: pio run -e esp32wemos-s3-mini_BW
- name: Build BTClock filesystem - name: Build BTClock filesystem
run: pio run -e default --target buildfs run: pio run -e esp32wemos-s3-mini_BW --target buildfs
- name: Install esptools.py - name: Install esptools.py
run: pip install --upgrade esptool run: pip install --upgrade esptool
- name: Create merged firmware binary - name: Create merged firmware binary
run: mkdir -p output && esptool.py --chip esp32s3 merge_bin -o output/full-firmware.bin --flash_mode dio 0x0000 .pio/build/default/bootloader.bin 0x8000 .pio/build/default/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/default/firmware.bin 0x330000 .pio/build/default/spiffs.bin run: mkdir -p output && esptool.py --chip esp32s3 merge_bin -o output/full-firmware.bin --flash_mode dio 0x0000 .pio/build/esp32wemos-s3-mini_BW/bootloader.bin 0x8000 .pio/build/esp32wemos-s3-mini_BW/partitions.bin 0xe000 ~/.platformio/packages/framework-arduinoespressif32/tools/partitions/boot_app0.bin 0x10000 .pio/build/esp32wemos-s3-mini_BW/firmware.bin 0x330000 .pio/build/esp32wemos-s3-mini_BW/spiffs.bin
- name: Create checksum for merged binary - name: Create checksum for merged binary
run: shasum -a 256 output/full-firmware.bin | awk '{print $1}' > output/full-firmware.sha256 run: shasum -a 256 output/full-firmware.bin | awk '{print $1}' > output/full-firmware.sha256
@ -58,15 +57,17 @@ jobs:
- name: Upload artifacts - name: Upload artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name:
path: | path: |
.pio/build/default/*.bin .pio/build/esp32wemos-s3-mini_BW/*.bin
output/full-firmware.bin output/full-firmware.bin
output/full-firmware.sha256 output/full-firmware.sha256
- name: Create release - name: Create release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
name: release-${{ steps.dateAndTime.outputs.dateAndTime }} name: release-${{ steps.date.outputs.dateAndTime }}
artifacts: "output/full-firmware.bin,output/full-firmware.sha256,.pio/build/default/*.bin" artifacts: "output/full-firmware.bin,output/full-firmware.sha256,.pio/build/esp32wemos-s3-mini_BW/*.bin"
allowUpdates: true allowUpdates: true
removeArtifacts: true removeArtifacts: true
- name: Pushes full-firmware.bin to web flasher - name: Pushes full-firmware.bin to web flasher

View file

@ -63,8 +63,8 @@
<div class="progress-bar progress-bar-striped" style="width: {{ memUsage }}%">{{ memUsage }}%</div> <div class="progress-bar progress-bar-striped" style="width: {{ memUsage }}%">{{ memUsage }}%</div>
</div> </div>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div>Memory free</div> <div>Memory usage</div>
<div>{{ memFree }} / {{ memTotal }} KiB</div> <div>{{ memFree }} / {{ memTotal }} kB</div>
</div> </div>
</div> </div>
<hr> <hr>
@ -191,13 +191,6 @@
<input type="text" name="mempoolInstance" id="mempoolInstance" class="form-control"> <input type="text" name="mempoolInstance" id="mempoolInstance" class="form-control">
</div> </div>
</div> </div>
<div class="row">
<label for="hostnamePrefix" class="col-sm-6 col-form-label col-form-label-sm">Hostname prefix</label>
<div class="col-sm-6">
<input type="text" name="hostnamePrefix" id="hostnamePrefix" class="form-control">
<div class="form-text">A restart is required to apply new hostname prefix.</div>
</div>
</div>
<div class="row"> <div class="row">
<div class=" col-sm-6"> <div class=" col-sm-6">
<div class="form-check form-switch"> <div class="form-check form-switch">
@ -234,7 +227,7 @@
<script id="screens-template" type="text/x-handlebars-template"> <script id="screens-template" type="text/x-handlebars-template">
{{#each screens }} {{#each screens }}
<div class="row"> <div class="row">
<div class="col-sm-12"> <div class=" col-sm-6">
<div class="form-check form-switch"> <div class="form-check form-switch">
<input class="form-check-input" type="checkbox" id="screen{{id}}" name="screen[{{id}}]" value="1" {{#if enabled}}checked{{/if}}> <input class="form-check-input" type="checkbox" id="screen{{id}}" name="screen[{{id}}]" value="1" {{#if enabled}}checked{{/if}}>
<label class="form-check-label" for="screen{{id}}">{{name}}</label> <label class="form-check-label" for="screen{{id}}">{{name}}</label>

View file

@ -1,6 +1,6 @@
import './helpers.js'; import './helpers.js';
var screens = ["Block Height", "Moscow Time", "Ticker", "Time", "Halving countdown", "Market Cap"]; var screens = ["Block Height", "Moscow Time", "Ticker", "Time", "Halving countdown"];
toTime = (secs) => { toTime = (secs) => {
var hours = Math.floor(secs / (60 * 60)); var hours = Math.floor(secs / (60 * 60));
@ -28,7 +28,7 @@ getBcStatus = () => {
var source = document.getElementById("entry-template").innerHTML; var source = document.getElementById("entry-template").innerHTML;
var template = Handlebars.compile(source); var template = Handlebars.compile(source);
var context = { timerRunning: jsonData.timerRunning, memUsage: Math.round(jsonData.espFreeHeap / jsonData.espHeapSize * 100), memFree: (jsonData.espFreeHeap / 1024), memTotal: (jsonData.espHeapSize / 1024), uptime: toTime(jsonData.espUptime), currentScreen: jsonData.currentScreen, rendered: jsonData.rendered, data: jsonData.data, screens: screens, ledStatus: jsonData.ledStatus ? jsonData.ledStatus.map((t) => (t).toString(16)) : [] }; var context = { timerRunning: jsonData.timerRunning, memUsage: Math.round(jsonData.espFreeHeap / jsonData.espHeapSize * 100), memFree: (jsonData.espFreeHeap / 1000), memTotal: (jsonData.espHeapSize / 1000), uptime: toTime(jsonData.espUptime), currentScreen: jsonData.currentScreen, rendered: jsonData.rendered, data: jsonData.data, screens: screens, ledStatus: jsonData.ledStatus ? jsonData.ledStatus.map((t) => (t).toString(16)) : [] };
document.getElementById('output').innerHTML = template(context); document.getElementById('output').innerHTML = template(context);
@ -76,7 +76,6 @@ fetch('/api/settings', {
document.getElementById('fullRefreshMin').value = jsonData.fullRefreshMin; document.getElementById('fullRefreshMin').value = jsonData.fullRefreshMin;
document.getElementById('wpTimeout').value = jsonData.wpTimeout; document.getElementById('wpTimeout').value = jsonData.wpTimeout;
document.getElementById('mempoolInstance').value = jsonData.mempoolInstance; document.getElementById('mempoolInstance').value = jsonData.mempoolInstance;
document.getElementById('hostnamePrefix').value = jsonData.hostnamePrefix;
if (jsonData.gitRev) if (jsonData.gitRev)
document.getElementById('gitRev').innerHTML = "Version: " + jsonData.gitRev; document.getElementById('gitRev').innerHTML = "Version: " + jsonData.gitRev;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 MiB

View file

@ -19,19 +19,21 @@ upload_speed = 921600
monitor_filters = esp32_exception_decoder, colorize monitor_filters = esp32_exception_decoder, colorize
extra_scripts = post:scripts/extra_script.py extra_scripts = post:scripts/extra_script.py
build_flags = !python scripts/git_rev.py build_flags = !python scripts/git_rev.py
lib_deps =
bblanchon/ArduinoJson@^6.21.2
fbiego/ESP32Time@^2.0.1
https://github.com/dsbaars/GxEPD2#universal_pin
https://github.com/dsbaars/universal_pin
adafruit/Adafruit MCP23017 Arduino Library@^2.3.0
adafruit/Adafruit NeoPixel@^1.11.0
https://github.com/me-no-dev/ESPAsyncWebServer.git
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
[esp32wemos-s3-mini_BW_base] [esp32wemos-s3-mini_BW_base]
platform = espressif32 platform = espressif32
framework = arduino framework = arduino
board = lolin_s3_mini board = lolin_s3_mini
board_build.partitions = partition.csv board_build.partitions = partition.csv
lib_deps =
bblanchon/ArduinoJson@^6.21.2
fbiego/ESP32Time@^2.0.1
adafruit/Adafruit MCP23017 Arduino Library@^2.3.0
adafruit/Adafruit NeoPixel@^1.11.0
https://github.com/me-no-dev/ESPAsyncWebServer.git
https://github.com/tzapu/WiFiManager.git#v2.0.16-rc.2
build_flags = build_flags =
!python scripts/git_rev.py !python scripts/git_rev.py
-DLAST_BUILD_TIME=$UNIX_TIME -DLAST_BUILD_TIME=$UNIX_TIME
@ -45,34 +47,15 @@ build_flags =
-D ARDUINO_USB_CDC_ON_BOOT -D ARDUINO_USB_CDC_ON_BOOT
-D HOSTNAME="\"btclock3\"" -D HOSTNAME="\"btclock3\""
-mfix-esp32-psram-cache-issue -mfix-esp32-psram-cache-issue
-fexceptions
-DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
build_unflags = -fno-exceptions
zinggjm/GxEPD2@^1.5.2
[env:esp32wemos-s3-mini_BW] [env:esp32wemos-s3-mini_BW]
extends = esp32wemos-s3-mini_BW_base extends = esp32wemos-s3-mini_BW_base
build_flags = build_flags =
${esp32wemos-s3-mini_BW_base.build_flags} ${esp32wemos-s3-mini_BW_base.build_flags}
https://github.com/dsbaars/GxEPD2#universal_pin
https://github.com/dsbaars/universal_pin
-DUSE_UNIVERSAL_PIN
-D NUM_SCREENS=7 -D NUM_SCREENS=7
lib_deps =
${esp32wemos-s3-mini_BW_base.lib_deps}
[env:esp32wemos-s3-mini_BW_9disp] [env:esp32wemos-s3-mini_BW_9disp]
extends = esp32wemos-s3-mini_BW_base extends = esp32wemos-s3-mini_BW_base
build_flags = build_flags =
${esp32wemos-s3-mini_BW_base.build_flags} ${esp32wemos-s3-mini_BW_base.build_flags}
-D NUM_SCREENS=9 -D NUM_SCREENS=9
[env:default]
extends = esp32wemos-s3-mini_BW_base
build_flags =
${esp32wemos-s3-mini_BW_base.build_flags}
-D NUM_SCREENS=7
lib_deps =
${esp32wemos-s3-mini_BW_base.lib_deps}
zinggjm/GxEPD2@^1.5.2

View file

@ -26,7 +26,7 @@ void setFgColor(int color)
void showSetupQr(const String &ssid, const String &password) void showSetupQr(const String &ssid, const String &password)
{ {
uint displayIndex = 6; char displayIndex = 6;
const String text = "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;"; const String text = "WIFI:S:" + ssid + ";T:WPA;P:" + password + ";;";

View file

@ -36,8 +36,8 @@ void setupSoftAP()
{ {
byte mac[6]; byte mac[6];
WiFi.macAddress(mac); WiFi.macAddress(mac);
softAP_SSID = getMyHostname().c_str(); softAP_SSID = String("BTClock" + String(mac[5], 16) + String(mac[1], 16));
WiFi.setHostname(getMyHostname().c_str()); WiFi.setHostname(softAP_SSID.c_str());
softAP_password = base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)).substring(2, 10); softAP_password = base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)).substring(2, 10);
} }
@ -85,7 +85,7 @@ void setupComponents()
pixels.show(); pixels.show();
// delay(200); // delay(200);
pinMode(MCP_INT_PIN, INPUT); pinMode(MCP_INT_PIN, INPUT);
mcp.setupInterrupts(false, false, LOW); mcp.setupInterrupts(true, false, LOW);
} }
#endif #endif
@ -180,9 +180,7 @@ void setupPreferences()
{SCREEN_MSCW_TIME, "Sats per dollar"}, {SCREEN_MSCW_TIME, "Sats per dollar"},
{SCREEN_BTC_TICKER, "Ticker"}, {SCREEN_BTC_TICKER, "Ticker"},
{SCREEN_TIME, "Time"}, {SCREEN_TIME, "Time"},
{SCREEN_HALVING_COUNTDOWN, "Halving countdown"}, {SCREEN_HALVING_COUNTDOWN, "Halving countdown"}};
{SCREEN_MARKET_CAP, "Market Cap"}
};
#ifdef WITH_RGB_LED #ifdef WITH_RGB_LED
pixels.setBrightness(preferences.getUInt("ledBrightness", 128)); pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
@ -224,23 +222,27 @@ void handleScreenTasks(uint screen)
vTaskSuspend(blockNotifyTaskHandle); vTaskSuspend(blockNotifyTaskHandle);
if (getPriceTaskHandle) if (getPriceTaskHandle)
vTaskSuspend(getPriceTaskHandle); vTaskSuspend(getPriceTaskHandle);
if (minuteTaskHandle)
vTaskSuspend(minuteTaskHandle);
switch (currentScreen) switch (currentScreen)
{ {
case SCREEN_BLOCK_HEIGHT: case SCREEN_BLOCK_HEIGHT:
if (blockNotifyTaskHandle)
{
vTaskResume(blockNotifyTaskHandle);
}
break;
case SCREEN_HALVING_COUNTDOWN: case SCREEN_HALVING_COUNTDOWN:
if (blockNotifyTaskHandle) if (blockNotifyTaskHandle)
vTaskResume(blockNotifyTaskHandle); vTaskResume(blockNotifyTaskHandle);
break; break;
case SCREEN_BTC_TICKER: case SCREEN_BTC_TICKER:
case SCREEN_MSCW_TIME:
if (getPriceTaskHandle) if (getPriceTaskHandle)
vTaskResume(getPriceTaskHandle); vTaskResume(getPriceTaskHandle);
break; break;
case SCREEN_MARKET_CAP: case SCREEN_MSCW_TIME:
if (getPriceTaskHandle) if (getPriceTaskHandle)
vTaskResume(getPriceTaskHandle); vTaskResume(getPriceTaskHandle);
if (blockNotifyTaskHandle)
vTaskResume(blockNotifyTaskHandle);
break; break;
case SCREEN_TIME: case SCREEN_TIME:
if (minuteTaskHandle) if (minuteTaskHandle)
@ -374,21 +376,18 @@ void showNetworkSettings()
String ipAddr = WiFi.localIP().toString(); String ipAddr = WiFi.localIP().toString();
String subNet = WiFi.subnetMask().toString(); String subNet = WiFi.subnetMask().toString();
epdContent[0] = "IP/Subnet"; epdContent[1] = "IP/Subnet";
int ipAddrPos = 0; int ipAddrPos = 0;
int subnetPos = 0; int subnetPos = 0;
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
epdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.')); epdContent[2 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.'));
ipAddrPos = ipAddr.indexOf('.') + 1; ipAddrPos = ipAddr.indexOf('.') + 1;
subnetPos = subNet.indexOf('.') + 1; subnetPos = subNet.indexOf('.') + 1;
ipAddr = ipAddr.substring(ipAddrPos); ipAddr = ipAddr.substring(ipAddrPos);
subNet = subNet.substring(subnetPos); subNet = subNet.substring(subnetPos);
} }
epdContent[NUM_SCREENS-2] = "RAM/Status";
epdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1024)) + "/" + (int)round(ESP.getHeapSize()/1024);
CustomTextScreen::setText(epdContent); CustomTextScreen::setText(epdContent);

View file

@ -5,7 +5,6 @@
//#include <WiFiMulti.h> //#include <WiFiMulti.h>
#include "config.h" #include "config.h"
#include "utils.hpp"
#include "shared.hpp" #include "shared.hpp"
#include "Adafruit_GFX.h" #include "Adafruit_GFX.h"
#include "lib/epd.hpp" #include "lib/epd.hpp"

View file

@ -1,54 +0,0 @@
#include "utils.hpp";
double getSupplyAtBlock(uint blockNr) {
if (blockNr >= 33 * 210000) {
return 20999999.9769;
}
const int initialBlockReward = 50; // Initial block reward
const int halvingInterval = 210000; // Number of blocks before halving
int halvingCount = blockNr / halvingInterval;
double totalBitcoinInCirculation = 0;
for (int i = 0; i < halvingCount; ++i) {
totalBitcoinInCirculation += halvingInterval * initialBlockReward * std::pow(0.5, i);
}
totalBitcoinInCirculation += (blockNr % halvingInterval) * initialBlockReward * std::pow(0.5, halvingCount);
return totalBitcoinInCirculation;
}
std::string formatNumberWithSuffix(int64_t num) {
const long long quadrillion = 1000000000000000LL;
const long long trillion = 1000000000000LL;
const long long billion = 1000000000;
const long long million = 1000000;
const long long thousand = 1000;
if (num >= quadrillion) {
return std::to_string(num / quadrillion) + "Q";
} else if (num >= trillion) {
return std::to_string(num / trillion) + "T";
} else if (num >= billion) {
return std::to_string(num / billion) + "B";
} else if (num >= million) {
return std::to_string(num / million) + "M";
} else if (num >= thousand) {
return std::to_string(num / thousand) + "K";
} else {
return std::to_string(num);
}
}
String getMyHostname() {
uint8_t mac[6];
//WiFi.macAddress(mac);
esp_efuse_mac_get_default(mac);
char hostname[15];
String hostnamePrefix = preferences.getString("hostnamePrefix", "btclock");
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x",
hostnamePrefix, mac[3], mac[4], mac[5]);
return hostname;
}

View file

@ -1,7 +0,0 @@
#pragma once
#include "shared.hpp"
double getSupplyAtBlock(uint blockNr);
std::string formatNumberWithSuffix(int64_t num);
String getMyHostname();

View file

@ -52,7 +52,7 @@ void setupWebserver()
// Start server // Start server
server.begin(); server.begin();
if (!MDNS.begin(getMyHostname())) if (!MDNS.begin(HOSTNAME))
{ {
Serial.println(F("Error setting up MDNS responder!")); Serial.println(F("Error setting up MDNS responder!"));
while (1) while (1)
@ -61,9 +61,6 @@ void setupWebserver()
} }
} }
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
MDNS.addServiceTxt("http", "tcp", "model", "BTClock");
MDNS.addServiceTxt("http", "tcp", "version", "2.0");
MDNS.addServiceTxt("http", "tcp", "rev", GIT_REV);
Serial.println(F("Webserver should be running")); Serial.println(F("Webserver should be running"));
} }
@ -173,7 +170,7 @@ void onApiActionUpdate(AsyncWebServerRequest *request)
*/ */
void onApiSettingsGet(AsyncWebServerRequest *request) void onApiSettingsGet(AsyncWebServerRequest *request)
{ {
StaticJsonDocument<1536> root; StaticJsonDocument<768> root;
root["numScreens"] = NUM_SCREENS; root["numScreens"] = NUM_SCREENS;
root["fgColor"] = getFgColor(); root["fgColor"] = getFgColor();
root["bgColor"] = getBgColor(); root["bgColor"] = getBgColor();
@ -187,8 +184,6 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
root["rpcUser"] = preferences.getString("rpcUser", BITCOIND_RPC_USER); root["rpcUser"] = preferences.getString("rpcUser", BITCOIND_RPC_USER);
root["rpcHost"] = preferences.getString("rpcHost", BITCOIND_HOST); root["rpcHost"] = preferences.getString("rpcHost", BITCOIND_HOST);
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE); root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
root["hostnamePrefix"] = preferences.getString("hostnamePrefix", "btclock");
root["hostname"] = getMyHostname();
#ifdef IS_BW #ifdef IS_BW
root["epdColors"] = 2; root["epdColors"] = 2;
@ -295,14 +290,6 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
settingsChanged = true; settingsChanged = true;
} }
if (request->hasParam("hostnamePrefix", true))
{
AsyncWebParameter *hostnamePrefix = request->getParam("hostnamePrefix", true);
preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str());
settingsChanged = true;
}
if (request->hasParam("ledBrightness", true)) if (request->hasParam("ledBrightness", true))
{ {
AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true); AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);

View file

@ -18,7 +18,6 @@
#include "screens/ticker.hpp" #include "screens/ticker.hpp"
#include "screens/time.hpp" #include "screens/time.hpp"
#include "screens/halvingcountdown.hpp" #include "screens/halvingcountdown.hpp"
#include "screens/market_cap.hpp"
#include "tasks/ha.hpp" #include "tasks/ha.hpp"
#include "tasks/epd.hpp" #include "tasks/epd.hpp"
@ -63,7 +62,7 @@ void setup()
BlockHeightScreen::init(); BlockHeightScreen::init();
HalvingCountdownScreen::init(); HalvingCountdownScreen::init();
TickerScreen::init(); TickerScreen::init();
MarketCapScreen::init(); // SatsPerDollarScreen::init();
#ifdef WITH_BUTTONS #ifdef WITH_BUTTONS
setupButtonTask(); setupButtonTask();
@ -78,15 +77,15 @@ void setup()
registerNewBlockCallback(BlockHeightScreen::onNewBlock); registerNewBlockCallback(BlockHeightScreen::onNewBlock);
registerNewBlockCallback(HalvingCountdownScreen::onNewBlock); registerNewBlockCallback(HalvingCountdownScreen::onNewBlock);
registerNewPriceCallback(TickerScreen::onPriceUpdate); registerNewPriceCallback(TickerScreen::onPriceUpdate);
// registerNewPriceCallback(SatsPerDollarScreen::onPriceUpdate);
setupDisplays(); setupDisplays();
} } else {
else
{
setupI2C(); setupI2C();
} }
} }
void loop() void loop()
{ {
// put your main code here, to run repeatedly:
} }

View file

@ -58,7 +58,3 @@ std::array<String, NUM_SCREENS> BlockHeightScreen::getEpdContent()
return ret; return ret;
} }
uint BlockHeightScreen::getBlockNr() {
return blockNr;
}

View file

@ -17,5 +17,4 @@ public:
static void showScreen(); static void showScreen();
static void onNewBlock(uint blockNr); static void onNewBlock(uint blockNr);
static std::array<String, NUM_SCREENS> getEpdContent(); static std::array<String, NUM_SCREENS> getEpdContent();
static uint getBlockNr();
}; };

View file

@ -1,30 +0,0 @@
#include "market_cap.hpp"
uint MarketCapScreen::satsPerDollar = 0;
std::array<String, NUM_SCREENS> MarketCapScreen::epdContent = {"", "", "", "", "", "", ""};
void MarketCapScreen::init()
{
// Dependent on price and blocks
MarketCapScreen::showScreen();
}
void MarketCapScreen::showScreen()
{
double supply = getSupplyAtBlock(BlockHeightScreen::getBlockNr());
int64_t marketCap = static_cast<std::int64_t>(supply * double(TickerScreen::getPrice()));
std::string priceString = "$" + formatNumberWithSuffix(marketCap);
priceString.insert(priceString.begin(), NUM_SCREENS - priceString.length(), ' ');
epdContent[0] = "USD/MCAP";
for (uint i = 1; i < NUM_SCREENS; i++)
{
MarketCapScreen::epdContent[i] = priceString[i];
}
}
std::array<String, NUM_SCREENS> MarketCapScreen::getEpdContent()
{
return MarketCapScreen::epdContent;
}

View file

@ -1,20 +0,0 @@
#pragma once
#include "base.hpp"
#include "config.h"
#include "shared.hpp"
#include "lib/utils.hpp"
#include "blockheight.hpp";
#include "ticker.hpp";
#include "tasks/epd.hpp"
class MarketCapScreen {
protected:
static uint satsPerDollar;
static std::array<String, NUM_SCREENS> epdContent;
public:
static void init();
static void showScreen();
static void onPriceUpdate(uint price);
static std::array<String, NUM_SCREENS> getEpdContent();
};

View file

@ -0,0 +1,30 @@
// #include "sats_per_dollar.hpp"
// uint SatsPerDollarScreen::satsPerDollar = 0;
// std::array<String, NUM_SCREENS> SatsPerDollarScreen::epdContent = { "", "", "", "", "", "", "" };
// void SatsPerDollarScreen::init() {
// SatsPerDollarScreen::satsPerDollar = int(round(1 / preferences.getFloat("btcPrice", 12345) * 10e7));
// setupGetPriceTask();
// SatsPerDollarScreen::showScreen();
// }
// void SatsPerDollarScreen::showScreen() {
// std::string satsPerDollarString = String(SatsPerDollarScreen::satsPerDollar).c_str();
// satsPerDollarString.insert(satsPerDollarString.begin(), 7 - satsPerDollarString.length(), ' ');
// epdContent[0] = "MSCW/TIME";
// for (uint i = 1; i < NUM_SCREENS; i++)
// {
// SatsPerDollarScreen::epdContent[i] = satsPerDollarString[i];
// }
// }
// void SatsPerDollarScreen::onPriceUpdate(uint price) {
// SatsPerDollarScreen::satsPerDollar = int(round(1 / float(price) * 10e7));
// SatsPerDollarScreen::showScreen();
// }
// std::array<String, NUM_SCREENS> SatsPerDollarScreen::getEpdContent() {
// return SatsPerDollarScreen::epdContent;
// }

View file

@ -0,0 +1,17 @@
// #pragma once
// #include "base.hpp"
// #include "config.h"
// #include "shared.hpp"
// #include "tasks/epd.hpp"
// class SatsPerDollarScreen {
// protected:
// static uint satsPerDollar;
// static std::array<String, NUM_SCREENS> epdContent;
// public:
// static void init();
// static void showScreen();
// static void onPriceUpdate(uint price);
// static std::array<String, NUM_SCREENS> getEpdContent();
// };

View file

@ -49,7 +49,3 @@ std::array<String, NUM_SCREENS> TickerScreen::getEpdContentSats() {
return epdContentSats; return epdContentSats;
} }
uint TickerScreen::getPrice() {
return price;
}

View file

@ -18,5 +18,4 @@ public:
static void onPriceUpdate(uint price); static void onPriceUpdate(uint price);
static std::array<String, NUM_SCREENS> getEpdContent(); static std::array<String, NUM_SCREENS> getEpdContent();
static std::array<String, NUM_SCREENS> getEpdContentSats(); static std::array<String, NUM_SCREENS> getEpdContentSats();
static uint getPrice();
}; };

View file

@ -55,11 +55,9 @@ const PROGMEM int SCREEN_MSCW_TIME = 1;
const PROGMEM int SCREEN_BTC_TICKER = 2; const PROGMEM int SCREEN_BTC_TICKER = 2;
const PROGMEM int SCREEN_TIME = 3; const PROGMEM int SCREEN_TIME = 3;
const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4; const PROGMEM int SCREEN_HALVING_COUNTDOWN = 4;
const PROGMEM int SCREEN_MARKET_CAP = 5;
const PROGMEM int SCREEN_COUNTDOWN = 98; const PROGMEM int SCREEN_COUNTDOWN = 98;
const PROGMEM int SCREEN_CUSTOM = 99; const PROGMEM int SCREEN_CUSTOM = 99;
const PROGMEM int screens[6] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP }; const PROGMEM int screens[5] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN };
const uint screenCount = sizeof(screens) / sizeof(int); const uint screenCount = sizeof(screens) / sizeof(int);

View file

@ -82,9 +82,6 @@ void checkBitcoinBlock(void *pvParameters)
Serial.print(F("Error in HTTP request to mempool API: ")); Serial.print(F("Error in HTTP request to mempool API: "));
Serial.print(httpCode); Serial.print(httpCode);
Serial.println(http->errorToString(httpCode)); Serial.println(http->errorToString(httpCode));
if (httpCode == -1) {
WiFi.reconnect();
}
} }
http->end(); http->end();

View file

@ -8,65 +8,66 @@
#include "button.hpp" #include "button.hpp"
#ifndef NO_MCP #ifndef NO_MCP
TaskHandle_t buttonTaskHandle = NULL; TaskHandle_t buttonTaskHandle = NULL;
// Define a type for the event callback
std::vector<EventCallback> buttonEventCallbacks; // Define a vector to hold multiple event callbacks std::vector<EventCallback> buttonEventCallbacks; // Define a vector to hold multiple event callbacks
const TickType_t debounceDelay = pdMS_TO_TICKS(50); volatile boolean buttonPressed = false;
TickType_t lastDebounceTime = 0;
void buttonTask(void *parameter) void buttonTask(void *parameter)
{ {
while (1) while (1)
{ {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
TickType_t currentTime = xTaskGetTickCount();
if ((currentTime - lastDebounceTime) >= debounceDelay)
{
lastDebounceTime = currentTime;
if (!digitalRead(MCP_INT_PIN)) if (!digitalRead(MCP_INT_PIN))
{ {
uint pin = mcp.getLastInterruptPin(); uint pin = mcp.getLastInterruptPin();
if (pin == 3) {
switch (pin) // xTaskCreate(fullRefresh, "FullRefresh", 2048, NULL, 1, NULL);
{
case 3:
toggleScreenTimer(); toggleScreenTimer();
break;
case 2:
nextScreen();
break;
case 1:
previousScreen();
break;
case 0:
showNetworkSettings();
break;
} }
} else if (pin == 1)
mcp.clearInterrupts();
// Very ugly, but for some reason this is necessary
while (!digitalRead(MCP_INT_PIN))
{ {
mcp.clearInterrupts(); previousScreen();
} }
else if (pin == 2)
{
nextScreen();
} }
else if (pin == 0)
{
showNetworkSettings();
}
vTaskDelay(250); // debounce
mcp.clearInterrupts(); // clear
}
vTaskDelay(pdMS_TO_TICKS(250));
} }
} }
void IRAM_ATTR handleButtonInterrupt() void IRAM_ATTR handleButtonInterrupt()
{ {
BaseType_t xHigherPriorityTaskWoken = pdFALSE; buttonPressed = true;
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken); // Serial.println(F("ISR"));
if (xHigherPriorityTaskWoken == pdTRUE) // uint pin = mcp.getLastInterruptPin();
{
portYIELD_FROM_ISR(); // if (pin == 1)
} // {
// nextScreen();
// }
// else if (pin == 2)
// {
// previousScreen();
// }
// vTaskDelay(pdMS_TO_TICKS(250));
// mcp.clearInterrupts();
} }
void setupButtonTask() void setupButtonTask()
{ {
xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, 1, &buttonTaskHandle); // Create the FreeRTOS task xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, 1, &buttonTaskHandle); // Create the FreeRTOS task
// Use interrupt instead of task // Use interrupt instead of task
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE); // attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, FALLING);
} }
void registerNewButtonCallback(const EventCallback cb) void registerNewButtonCallback(const EventCallback cb)

View file

@ -1,57 +1,28 @@
#include "epd.hpp" #include "epd.hpp"
#ifdef IS_S3 #ifdef IS_S3
#ifdef USE_UNIVERSAL_PIN
Native_Pin EPD_CS[NUM_SCREENS] = { Native_Pin EPD_CS[NUM_SCREENS] = {
Native_Pin(2), Native_Pin(2), Native_Pin(4), Native_Pin(6), Native_Pin(10), Native_Pin(33), Native_Pin(21), Native_Pin(17),
Native_Pin(4),
Native_Pin(6),
Native_Pin(10),
Native_Pin(33),
Native_Pin(21),
Native_Pin(17),
#if NUM_SCREENS == 9 #if NUM_SCREENS == 9
// MCP23X17_Pin(mcp2, 7),
Native_Pin(-1), Native_Pin(-1),
Native_Pin(-1), Native_Pin(-1),
#endif #endif
}; };
Native_Pin EPD_BUSY[NUM_SCREENS] = { Native_Pin EPD_BUSY[NUM_SCREENS] = {
Native_Pin(3), Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9), Native_Pin(37), Native_Pin(18), Native_Pin(16),
Native_Pin(5),
Native_Pin(7),
Native_Pin(9),
Native_Pin(37),
Native_Pin(18),
Native_Pin(16),
#if NUM_SCREENS == 9 #if NUM_SCREENS == 9
// MCP23X17_Pin(mcp2, 6),
Native_Pin(-1), Native_Pin(-1),
Native_Pin(-1), Native_Pin(-1),
#endif #endif
}; };
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = { MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
MCP23X17_Pin(mcp, 8), MCP23X17_Pin(mcp, 8), MCP23X17_Pin(mcp, 9), MCP23X17_Pin(mcp, 10), MCP23X17_Pin(mcp, 11), MCP23X17_Pin(mcp, 12), MCP23X17_Pin(mcp, 13), MCP23X17_Pin(mcp, 14),
MCP23X17_Pin(mcp, 9),
MCP23X17_Pin(mcp, 10),
MCP23X17_Pin(mcp, 11),
MCP23X17_Pin(mcp, 12),
MCP23X17_Pin(mcp, 13),
MCP23X17_Pin(mcp, 14),
#if NUM_SCREENS == 9 #if NUM_SCREENS == 9
MCP23X17_Pin(mcp2, 2), MCP23X17_Pin(mcp, 15),
MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp, 16)
// MCP23X17_Pin(mcp, 15),
// MCP23X17_Pin(mcp, 16)
#endif #endif
}; };
#if NUM_SCREENS == 9
MCP23X17_Pin EPD8_BUSY = MCP23X17_Pin(mcp2, 3);
MCP23X17_Pin EPD8_CS = MCP23X17_Pin(mcp2, 4);
MCP23X17_Pin EPD9_BUSY = MCP23X17_Pin(mcp2, 6);
MCP23X17_Pin EPD9_CS = MCP23X17_Pin(mcp2, 7);
#endif
Native_Pin EPD_DC = Native_Pin(14); Native_Pin EPD_DC = Native_Pin(14);
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = { GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
@ -63,29 +34,11 @@ GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
GxEPD2_213_B74(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]), GxEPD2_213_B74(&EPD_CS[5], &EPD_DC, &EPD_RESET_MPD[5], &EPD_BUSY[5]),
GxEPD2_213_B74(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]), GxEPD2_213_B74(&EPD_CS[6], &EPD_DC, &EPD_RESET_MPD[6], &EPD_BUSY[6]),
#if NUM_SCREENS == 9 #if NUM_SCREENS == 9
GxEPD2_213_B74(&EPD8_CS, &EPD_DC, &EPD_RESET_MPD[7], &EPD8_BUSY), GxEPD2_213_B74(&EPD_CS[7], &EPD_DC, &EPD_RESET_MPD[7], &EPD_BUSY[7]),
GxEPD2_213_B74(&EPD9_CS, &EPD_DC, &EPD_RESET_MPD[8], &EPD9_BUSY), GxEPD2_213_B74(&EPD_CS[8], &EPD_DC, &EPD_RESET_MPD[8], &EPD_BUSY[8]),
#endif #endif
}; };
#else
// Non Universal Pin
const char EPD_CS[NUM_SCREENS] = {2, 4, 6, 10, 33, 21, 17};
const char EPD_BUSY[NUM_SCREENS] = {3, 5, 7, 9, 37, 18, 16};
const char EPD_RESET_MPD[NUM_SCREENS] = {8, 9, 10, 11, 12, 13, 14};
const char EPD_DC = 14;
const char RST_PIN = 15;
GxEPD2_BW<GxEPD2_213_B74, GxEPD2_213_B74::HEIGHT> displays[NUM_SCREENS] = {
GxEPD2_213_B74(EPD_CS[0], EPD_DC, /*RST=*/-1, EPD_BUSY[0]),
GxEPD2_213_B74(EPD_CS[1], EPD_DC, /*RST=*/-1, EPD_BUSY[1]),
GxEPD2_213_B74(EPD_CS[2], EPD_DC, /*RST=*/-1, EPD_BUSY[2]),
GxEPD2_213_B74(EPD_CS[3], EPD_DC, /*RST=*/-1, EPD_BUSY[3]),
GxEPD2_213_B74(EPD_CS[4], EPD_DC, /*RST=*/-1, EPD_BUSY[4]),
GxEPD2_213_B74(EPD_CS[5], EPD_DC, /*RST=*/-1, EPD_BUSY[5]),
GxEPD2_213_B74(EPD_CS[6], EPD_DC, /*RST=*/-1, EPD_BUSY[6]),
};
#endif
const int SEM_WAIT_TIME = 10000; const int SEM_WAIT_TIME = 10000;
#endif #endif
@ -104,21 +57,9 @@ void setupDisplays()
void initDisplays() void initDisplays()
{ {
#ifndef USE_UNIVERSAL_PIN
resetAllDisplays();
#endif
for (uint i = 0; i < NUM_SCREENS; i++) for (uint i = 0; i < NUM_SCREENS; i++)
{ {
#ifndef USE_UNIVERSAL_PIN
mcp.pinMode(EPD_RESET_MPD[i], OUTPUT);
#endif
displays[i].init(); displays[i].init();
#ifndef USE_UNIVERSAL_PIN
resetSingleDisplay(i);
#endif
} }
for (uint i = 0; i < NUM_SCREENS; i++) for (uint i = 0; i < NUM_SCREENS; i++)
@ -133,19 +74,7 @@ void initDisplays()
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, 1, &tasks[i]); // create task xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, 1, &tasks[i]); // create task
// delay(1000); // delay(1000);
} }
epdContent = { "B", epdContent = {"B", "T", "C", "L", "O", "C", "K"};
"T",
"C",
"L",
"O",
"C",
"K"
#if NUM_SCREENS == 9
,
"0",
"9"
#endif
};
for (uint i = 0; i < NUM_SCREENS; i++) for (uint i = 0; i < NUM_SCREENS; i++)
{ {
xTaskNotifyGive(tasks[i]); xTaskNotifyGive(tasks[i]);
@ -153,24 +82,6 @@ void initDisplays()
vTaskDelay(pdMS_TO_TICKS(displays[0].epd2.full_refresh_time)); vTaskDelay(pdMS_TO_TICKS(displays[0].epd2.full_refresh_time));
} }
void resetAllDisplays()
{
for (int i = 0; i < NUM_SCREENS; i++)
{
resetSingleDisplay(i);
}
}
void resetSingleDisplay(int i)
{
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
delay(20);
mcp.digitalWrite(EPD_RESET_MPD[i], LOW);
delay(20);
mcp.digitalWrite(EPD_RESET_MPD[i], HIGH);
delay(200);
}
void taskEpd(void *pvParameters) void taskEpd(void *pvParameters)
{ {
while (1) while (1)
@ -192,9 +103,6 @@ void taskEpd(void *pvParameters)
case SCREEN_HALVING_COUNTDOWN: case SCREEN_HALVING_COUNTDOWN:
epdContent = HalvingCountdownScreen::getEpdContent(); epdContent = HalvingCountdownScreen::getEpdContent();
break; break;
case SCREEN_MARKET_CAP:
epdContent = MarketCapScreen::getEpdContent();
break;
case SCREEN_COUNTDOWN: case SCREEN_COUNTDOWN:
epdContent = CountdownScreen::getEpdContent(); epdContent = CountdownScreen::getEpdContent();
break; break;
@ -306,8 +214,6 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
void fullRefresh(void *pvParameters) void fullRefresh(void *pvParameters)
{ {
resetAllDisplays();
for (uint i = 0; i < NUM_SCREENS; i++) for (uint i = 0; i < NUM_SCREENS; i++)
{ {
lastFullRefresh[i] = NULL; lastFullRefresh[i] = NULL;
@ -316,7 +222,7 @@ void fullRefresh(void *pvParameters)
vTaskDelete(NULL); vTaskDelete(NULL);
} }
extern "C" void updateDisplay(void *pvParameters) noexcept void updateDisplay(void *pvParameters)
{ {
const int epdIndex = *(int *)pvParameters; const int epdIndex = *(int *)pvParameters;
delete (int *)pvParameters; delete (int *)pvParameters;
@ -328,11 +234,9 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0) if (epdContent[epdIndex].compareTo(currentEpdContent[epdIndex]) != 0)
{ {
displays[epdIndex].init(0, false); // Little longer reset duration because of MCP currentEpdContent[epdIndex] = epdContent[epdIndex];
#ifndef USE_UNIVERSAL_PIN
resetSingleDisplay(epdIndex);
#endif
displays[epdIndex].init(0, false, 20); // Little longer reset duration because of MCP
bool updatePartial = true; bool updatePartial = true;
// Full Refresh every half hour // Full Refresh every half hour
@ -353,26 +257,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
} }
#ifdef USE_UNIVERSAL_PIN
char tries = 0;
while (tries < 3)
{
if (displays[epdIndex].displayWithReturn(updatePartial))
{
displays[epdIndex].hibernate();
currentEpdContent[epdIndex] = epdContent[epdIndex];
break;
}
delay(100);
tries++;
}
#else
displays[epdIndex].display(updatePartial); displays[epdIndex].display(updatePartial);
displays[epdIndex].hibernate(); displays[epdIndex].hibernate();
currentEpdContent[epdIndex] = epdContent[epdIndex];
#endif
#endif #endif
} }
xSemaphoreGive(epdUpdateSemaphore[epdIndex]); xSemaphoreGive(epdUpdateSemaphore[epdIndex]);

View file

@ -11,17 +11,12 @@
#include "screens/blockheight.hpp" #include "screens/blockheight.hpp"
#include "screens/ticker.hpp" #include "screens/ticker.hpp"
#include "screens/time.hpp" #include "screens/time.hpp"
#include "screens/market_cap.hpp" #include "screens/sats_per_dollar.hpp"
#include "screens/countdown.hpp" #include "screens/countdown.hpp"
#include "screens/custom_text.hpp" #include "screens/custom_text.hpp"
#include "screens/halvingcountdown.hpp" #include "screens/halvingcountdown.hpp"
#ifdef USE_UNIVERSAL_PIN
#include <native_pin.hpp> #include <native_pin.hpp>
#include <mcp23x17_pin.hpp> #include <mcp23x17_pin.hpp>
#include <universal_pin.hpp>
#endif
#include <freertos/FreeRTOS.h> #include <freertos/FreeRTOS.h>
#include <freertos/task.h> #include <freertos/task.h>
@ -41,13 +36,11 @@ void taskEpd(void *pvParameters);
std::array<String, NUM_SCREENS> getCurrentEpdContent(); std::array<String, NUM_SCREENS> getCurrentEpdContent();
void resetAllDisplays();
void resetSingleDisplay(int i);
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent); void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
void splitText(const uint dispNum, String top, String bottom, bool partial); void splitText(const uint dispNum, String top, String bottom, bool partial);
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font); void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
void refreshDisplay(void *pvParameters); void refreshDisplay(void *pvParameters);
void fullRefresh(void *pvParameters); void fullRefresh(void *pvParameters);
extern "C" void updateDisplay(void *pvParameters) noexcept; void updateDisplay(void *pvParameters);
//void genQrCode(String text, uint8_t *qrcode[qrcodegen_BUFFER_LEN_MAX]); //void genQrCode(String text, uint8_t *qrcode[qrcodegen_BUFFER_LEN_MAX]);

View file

@ -56,9 +56,6 @@ void taskGetPrice(void *pvParameters)
{ {
Serial.print(F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: ")); Serial.print(F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
Serial.println(httpCode); Serial.println(httpCode);
if (httpCode == -1) {
WiFi.reconnect();
}
} }
} else { } else {
@ -89,9 +86,6 @@ void taskGetPrice(void *pvParameters)
{ {
Serial.print(F("Error retrieving BTC/USD price (CoinDesk). HTTP status code: ")); Serial.print(F("Error retrieving BTC/USD price (CoinDesk). HTTP status code: "));
Serial.println(httpCode); Serial.println(httpCode);
if (httpCode == -1) {
WiFi.reconnect();
}
} }
} }

View file

@ -4,47 +4,32 @@ TaskHandle_t minuteTaskHandle = NULL;
// Define a type for the event callback // Define a type for the event callback
std::vector<EventCallback> minuteEventCallbacks; // Define a vector to hold multiple event callbacks std::vector<EventCallback> minuteEventCallbacks; // Define a vector to hold multiple event callbacks
bool eventTriggered = false; // Initialize the event triggered flag to false bool eventTriggered = false; // Initialize the event triggered flag to false
const int usPerMinute = 60 * 1000000;
void minuteTask(void *parameter) void minuteTask(void * parameter) {
{ while(1) {
#ifdef IS_3C // wait 5 minutes in case of a 3 color screen otherwise it keeps refreshing
esp_timer_handle_t minuteTimer; if(rtc.getMinute() % 5 == 0 && !eventTriggered) {
const esp_timer_create_args_t minuteTimerConfig = { eventTriggered = true;
.callback = &minuteTimerISR, for(auto &callback : minuteEventCallbacks) { // Loop through all the event callbacks and call them
.name = "minute_timer"};
esp_timer_create(&minuteTimerConfig, &minuteTimer);
time_t currentTime;
struct tm timeinfo;
time(&currentTime);
localtime_r(&currentTime, &timeinfo);
uint32_t secondsUntilNextMinute = 60 - timeinfo.tm_sec;
if (secondsUntilNextMinute > 0)
vTaskDelay(pdMS_TO_TICKS((secondsUntilNextMinute * 1000)));
esp_timer_start_periodic(minuteTimer, usPerMinute);
while (1)
{
for (auto &callback : minuteEventCallbacks)
{
callback(); callback();
} }
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); if(rtc.getMinute() % 5 != 0 && eventTriggered) { // Reset the event triggered flag if the second is not 0
eventTriggered = false;
}
vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1000 milliseconds to avoid busy waiting
#else
if(rtc.getSecond() == 0 && !eventTriggered) {
eventTriggered = true;
for(auto &callback : minuteEventCallbacks) { // Loop through all the event callbacks and call them
callback();
} }
} }
if(rtc.getSecond() != 0) { // Reset the event triggered flag if the second is not 0
void IRAM_ATTR minuteTimerISR(void *arg) eventTriggered = false;
{ }
BaseType_t xHigherPriorityTaskWoken = pdFALSE; vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1000 milliseconds to avoid busy waiting
vTaskNotifyGiveFromISR(minuteTaskHandle, &xHigherPriorityTaskWoken); #endif
if (xHigherPriorityTaskWoken == pdTRUE)
{
portYIELD_FROM_ISR();
} }
} }

View file

@ -6,13 +6,9 @@
#include <freertos/task.h> #include <freertos/task.h>
#include <vector> #include <vector>
#include "shared.hpp" #include "shared.hpp"
#include <esp_timer.h>
#include <time.h>
extern TaskHandle_t minuteTaskHandle; extern TaskHandle_t minuteTaskHandle;
void minuteTask(void *pvParameters); void minuteTask(void *pvParameters);
void setupMinuteEvent(); void setupMinuteEvent();
void IRAM_ATTR minuteTimerISR(void* arg);
void registerNewMinuteCallback(const EventCallback cb); void registerNewMinuteCallback(const EventCallback cb);