Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ec1b048f79 | ||
|
497f8464ad |
29 changed files with 1681 additions and 235 deletions
|
@ -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">
|
||||||
|
|
|
@ -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 |
|
@ -13,7 +13,7 @@ data_dir = data/build
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
framework = arduino
|
framework = arduino, espidf
|
||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
upload_speed = 921600
|
upload_speed = 921600
|
||||||
monitor_filters = esp32_exception_decoder, colorize
|
monitor_filters = esp32_exception_decoder, colorize
|
||||||
|
@ -22,7 +22,7 @@ build_flags = !python scripts/git_rev.py
|
||||||
|
|
||||||
[esp32wemos-s3-mini_BW_base]
|
[esp32wemos-s3-mini_BW_base]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
framework = arduino
|
framework = arduino, espidf
|
||||||
board = lolin_s3_mini
|
board = lolin_s3_mini
|
||||||
board_build.partitions = partition.csv
|
board_build.partitions = partition.csv
|
||||||
lib_deps =
|
lib_deps =
|
||||||
|
@ -37,7 +37,7 @@ build_flags =
|
||||||
-DLAST_BUILD_TIME=$UNIX_TIME
|
-DLAST_BUILD_TIME=$UNIX_TIME
|
||||||
-D IS_S3
|
-D IS_S3
|
||||||
-D IS_BW
|
-D IS_BW
|
||||||
# -D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
-D CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||||
-D WITH_RGB_LED
|
-D WITH_RGB_LED
|
||||||
-D NEOPIXEL_COUNT=4
|
-D NEOPIXEL_COUNT=4
|
||||||
-DASYNCWEBSERVER_REGEX
|
-DASYNCWEBSERVER_REGEX
|
||||||
|
@ -47,7 +47,9 @@ build_flags =
|
||||||
-mfix-esp32-psram-cache-issue
|
-mfix-esp32-psram-cache-issue
|
||||||
-fexceptions
|
-fexceptions
|
||||||
-DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
|
-DPIO_FRAMEWORK_ARDUINO_ENABLE_EXCEPTIONS
|
||||||
build_unflags = -fno-exceptions
|
build_unflags =
|
||||||
|
-fno-exceptions
|
||||||
|
-Werror=all
|
||||||
|
|
||||||
zinggjm/GxEPD2@^1.5.2
|
zinggjm/GxEPD2@^1.5.2
|
||||||
|
|
||||||
|
|
1525
sdkconfig.default
Normal file
1525
sdkconfig.default
Normal file
File diff suppressed because it is too large
Load diff
21
sdkconfig.defaults
Normal file
21
sdkconfig.defaults
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
CONFIG_AUTOSTART_ARDUINO=y
|
||||||
|
# CONFIG_WS2812_LED_ENABLE is not set
|
||||||
|
CONFIG_FREERTOS_HZ=1000
|
||||||
|
CONFIG_FREERTOS_USE_TRACE_FACILITY=y
|
||||||
|
CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS=y
|
||||||
|
CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=y
|
||||||
|
|
||||||
|
CONFIG_MBEDTLS_PSK_MODES=y
|
||||||
|
CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y
|
||||||
|
|
||||||
|
CONFIG_BOOTLOADER_LOG_LEVEL=0
|
||||||
|
CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
|
||||||
|
CONFIG_BOOTLOADER_LOG_LEVEL_NONE=y
|
||||||
|
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL_NONE=y
|
||||||
|
CONFIG_LOG_DEFAULT_LEVEL=0
|
||||||
|
CONFIG_LOG_MAXIMUM_LEVEL=0
|
||||||
|
CONFIG_LOG_BOOTLOADER_LEVEL_NONE=y
|
||||||
|
CONFIG_LOG_BOOTLOADER_LEVEL=0
|
||||||
|
|
||||||
|
CONFIG_HEAP_CORRUPTION_DETECTION=CONFIG_HEAP_POISONING_LIGHT
|
|
@ -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 + ";;";
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,8 +60,25 @@ void setupComponents()
|
||||||
pixels.show();
|
pixels.show();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// delay(3000);
|
// delay(6000);
|
||||||
// Serial.println(F("Leds should be on"));
|
// Serial.println(F("I2C Master"));
|
||||||
|
|
||||||
|
// int i2c_master_port = 0;
|
||||||
|
// i2c_config_t conf = {
|
||||||
|
// .mode = I2C_MODE_MASTER,
|
||||||
|
// .sda_io_num = 35, // select SDA GPIO specific to your project
|
||||||
|
// .scl_io_num = 36, // select SCL GPIO specific to your project
|
||||||
|
// .sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||||
|
// .scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||||
|
// .master = {
|
||||||
|
// .clk_speed = 400000,
|
||||||
|
// }, // select frequency specific to your project
|
||||||
|
// .clk_flags = 0, // optional; you can use I2C_SCLK_SRC_FLAG_* flags to choose i2c source clock here
|
||||||
|
// };
|
||||||
|
|
||||||
|
// i2c_param_config(i2c_master_port, &conf);
|
||||||
|
// ESP_ERROR_CHECK(i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0));
|
||||||
|
Wire.begin(35, 36);
|
||||||
|
|
||||||
#ifndef NO_MCP
|
#ifndef NO_MCP
|
||||||
if (!mcp.begin_I2C(0x20))
|
if (!mcp.begin_I2C(0x20))
|
||||||
|
@ -72,8 +89,8 @@ void setupComponents()
|
||||||
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
||||||
pixels.setPixelColor(3, pixels.Color(255, 0, 0));
|
pixels.setPixelColor(3, pixels.Color(255, 0, 0));
|
||||||
pixels.show();
|
pixels.show();
|
||||||
while (1)
|
// while (1)
|
||||||
;
|
// ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -180,9 +197,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 +239,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)
|
||||||
|
@ -388,7 +407,9 @@ void showNetworkSettings()
|
||||||
}
|
}
|
||||||
epdContent[NUM_SCREENS-2] = "RAM/Status";
|
epdContent[NUM_SCREENS-2] = "RAM/Status";
|
||||||
|
|
||||||
epdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1024)) + "/" + (int)round(ESP.getHeapSize()/1024);
|
// char buf[32];
|
||||||
|
// snprintf(buf, sizeof(buf), "%s/%s", round(ESP.getFreeHeap()/1000), );
|
||||||
|
epdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1000)) + "/" + (int)round(ESP.getHeapSize()/1000);
|
||||||
|
|
||||||
CustomTextScreen::setText(epdContent);
|
CustomTextScreen::setText(epdContent);
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "shared.hpp"
|
|
||||||
|
|
||||||
double getSupplyAtBlock(uint blockNr);
|
|
||||||
std::string formatNumberWithSuffix(int64_t num);
|
|
||||||
String getMyHostname();
|
|
|
@ -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,16 +61,13 @@ 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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/status")
|
* @Path("/api/status")
|
||||||
*/
|
*/
|
||||||
void onApiStatus(AsyncWebServerRequest *request)
|
void onApiStatus(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||||
|
@ -113,7 +110,7 @@ void onApiStatus(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/pause")
|
* @Path("/api/action/pause")
|
||||||
*/
|
*/
|
||||||
void onApiActionPause(AsyncWebServerRequest *request)
|
void onApiActionPause(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
timerRunning = false;
|
timerRunning = false;
|
||||||
|
@ -125,7 +122,7 @@ void onApiActionPause(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/full_refresh")
|
* @Path("/api/action/full_refresh")
|
||||||
*/
|
*/
|
||||||
void onApiFullRefresh(AsyncWebServerRequest *request)
|
void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -137,7 +134,7 @@ void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||||
/**
|
/**
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/timer_restart")
|
* @Path("/api/action/timer_restart")
|
||||||
*/
|
*/
|
||||||
void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
// moment = millis();
|
// moment = millis();
|
||||||
|
@ -151,7 +148,7 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||||
* @Api
|
* @Api
|
||||||
* @Path("/api/action/update")
|
* @Path("/api/action/update")
|
||||||
* @Parameter int rate Time in minutes
|
* @Parameter int rate Time in minutes
|
||||||
*/
|
*/
|
||||||
void onApiActionUpdate(AsyncWebServerRequest *request)
|
void onApiActionUpdate(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
if (request->hasParam("rate"))
|
if (request->hasParam("rate"))
|
||||||
|
@ -170,10 +167,10 @@ void onApiActionUpdate(AsyncWebServerRequest *request)
|
||||||
* @Api
|
* @Api
|
||||||
* @Method GET
|
* @Method GET
|
||||||
* @Path("/api/settings")
|
* @Path("/api/settings")
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
|
|
|
@ -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,6 @@ void setup()
|
||||||
BlockHeightScreen::init();
|
BlockHeightScreen::init();
|
||||||
HalvingCountdownScreen::init();
|
HalvingCountdownScreen::init();
|
||||||
TickerScreen::init();
|
TickerScreen::init();
|
||||||
MarketCapScreen::init();
|
|
||||||
|
|
||||||
#ifdef WITH_BUTTONS
|
#ifdef WITH_BUTTONS
|
||||||
setupButtonTask();
|
setupButtonTask();
|
||||||
|
@ -89,4 +87,5 @@ void setup()
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(5000));
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,3 @@ std::array<String, NUM_SCREENS> BlockHeightScreen::getEpdContent()
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint BlockHeightScreen::getBlockNr() {
|
|
||||||
return blockNr;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
};
|
};
|
|
@ -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;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
};
|
|
30
src/screens/sats_per_dollar.cpp
Normal file
30
src/screens/sats_per_dollar.cpp
Normal 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;
|
||||||
|
// }
|
17
src/screens/sats_per_dollar.hpp
Normal file
17
src/screens/sats_per_dollar.hpp
Normal 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();
|
||||||
|
// };
|
|
@ -49,7 +49,3 @@ std::array<String, NUM_SCREENS> TickerScreen::getEpdContentSats() {
|
||||||
|
|
||||||
return epdContentSats;
|
return epdContentSats;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint TickerScreen::getPrice() {
|
|
||||||
return price;
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
};
|
};
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -192,9 +192,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;
|
||||||
|
@ -328,7 +325,7 @@ 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
|
displays[epdIndex].init(0, false, 20); // Little longer reset duration because of MCP
|
||||||
#ifndef USE_UNIVERSAL_PIN
|
#ifndef USE_UNIVERSAL_PIN
|
||||||
resetSingleDisplay(epdIndex);
|
resetSingleDisplay(epdIndex);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,12 +11,10 @@
|
||||||
#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
|
#ifdef USE_UNIVERSAL_PIN
|
||||||
#include <native_pin.hpp>
|
#include <native_pin.hpp>
|
||||||
#include <mcp23x17_pin.hpp>
|
#include <mcp23x17_pin.hpp>
|
||||||
|
|
|
@ -1,56 +1,41 @@
|
||||||
#include "minute.hpp"
|
#include "minute.hpp"
|
||||||
|
|
||||||
TaskHandle_t minuteTaskHandle = NULL;
|
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"};
|
callback();
|
||||||
|
}
|
||||||
esp_timer_create(&minuteTimerConfig, &minuteTimer);
|
|
||||||
|
|
||||||
time_t currentTime;
|
|
||||||
struct tm timeinfo;
|
|
||||||
time(¤tTime);
|
|
||||||
localtime_r(¤tTime, &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();
|
|
||||||
}
|
}
|
||||||
|
if(rtc.getMinute() % 5 != 0 && eventTriggered) { // Reset the event triggered flag if the second is not 0
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
eventTriggered = false;
|
||||||
}
|
}
|
||||||
}
|
vTaskDelay(pdMS_TO_TICKS(1000)); // Sleep for 1000 milliseconds to avoid busy waiting
|
||||||
|
#else
|
||||||
void IRAM_ATTR minuteTimerISR(void *arg)
|
if(rtc.getSecond() == 0 && !eventTriggered) {
|
||||||
{
|
eventTriggered = true;
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
for(auto &callback : minuteEventCallbacks) { // Loop through all the event callbacks and call them
|
||||||
vTaskNotifyGiveFromISR(minuteTaskHandle, &xHigherPriorityTaskWoken);
|
callback();
|
||||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
}
|
||||||
{
|
}
|
||||||
portYIELD_FROM_ISR();
|
if(rtc.getSecond() != 0) { // 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
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupMinuteEvent()
|
void setupMinuteEvent()
|
||||||
{
|
{
|
||||||
xTaskCreate(minuteTask, "MinuteTask", 4096, NULL, 1, &minuteTaskHandle); // Create the FreeRTOS task
|
xTaskCreate(minuteTask, "MinuteTask", 4096, NULL, 1, &minuteTaskHandle); // Create the FreeRTOS task
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerNewMinuteCallback(const EventCallback cb)
|
void registerNewMinuteCallback(const EventCallback cb)
|
||||||
|
|
|
@ -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);
|
Loading…
Reference in a new issue