Fix WebUI currency converter, reorganize some code

This commit is contained in:
Djuri Baars 2024-09-18 02:00:10 +02:00
parent 5dd47c2275
commit ff50acf913
14 changed files with 228 additions and 195 deletions

2
data

@ -1 +1 @@
Subproject commit 761c7f2991d347e97e77470ea3bf5511d7a7e507 Subproject commit 7d82b1e1a9014e80f725478333774f4d53e22134

View file

@ -11,6 +11,7 @@
#include "lib/led_handler.hpp" #include "lib/led_handler.hpp"
#include "lib/screen_handler.hpp" #include "lib/screen_handler.hpp"
#include "lib/timers.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
// using namespace websockets; // using namespace websockets;

View file

@ -4,6 +4,7 @@
#include "lib/screen_handler.hpp" #include "lib/screen_handler.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/timers.hpp"
extern TaskHandle_t buttonTaskHandle; extern TaskHandle_t buttonTaskHandle;

View file

@ -404,7 +404,7 @@ void setupWebsocketClients(void *pvParameters)
{ {
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE))
{ {
setupV2Notify(); V2Notify::setupV2Notify();
} }
else else
{ {
@ -553,7 +553,7 @@ void setupHardware()
{ {
Serial.println(F("Found BH1750")); Serial.println(F("Found BH1750"));
hasLuxSensor = true; hasLuxSensor = true;
bh1750.begin(BH1750::CONTINUOUS_LOW_RES_MODE, 0x5C); bh1750.begin(BH1750::CONTINUOUS_HIGH_RES_MODE, 0x5C);
} }
else else
{ {

View file

@ -12,6 +12,7 @@
#include "price_notify.hpp" #include "price_notify.hpp"
#include "block_notify.hpp" #include "block_notify.hpp"
#include "lib/timers.hpp"
void setupNostrNotify(bool asDatasource, bool zapNotify); void setupNostrNotify(bool asDatasource, bool zapNotify);

View file

@ -5,6 +5,7 @@
#include "lib/config.hpp" #include "lib/config.hpp"
#include "lib/shared.hpp" #include "lib/shared.hpp"
#include "lib/timers.hpp"
#ifndef UPDATE_MESSAGE_HPP #ifndef UPDATE_MESSAGE_HPP
#define UPDATE_MESSAGE_HPP #define UPDATE_MESSAGE_HPP

View file

@ -5,8 +5,7 @@
// TaskHandle_t timeUpdateTaskHandle; // TaskHandle_t timeUpdateTaskHandle;
TaskHandle_t taskScreenRotateTaskHandle; TaskHandle_t taskScreenRotateTaskHandle;
TaskHandle_t workerTaskHandle; TaskHandle_t workerTaskHandle;
esp_timer_handle_t screenRotateTimer;
esp_timer_handle_t minuteTimer;
std::array<std::string, NUM_SCREENS> taskEpdContent = {}; std::array<std::string, NUM_SCREENS> taskEpdContent = {};
std::string priceString; std::string priceString;
@ -23,8 +22,6 @@ void workerTask(void *pvParameters) {
while (1) { while (1) {
// Wait for a work item to be available in the queue // Wait for a work item to be available in the queue
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) { if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
uint firstIndex = 0;
// Process the work item based on its type // Process the work item based on its type
switch (receivedItem.type) { switch (receivedItem.type) {
case TASK_BITAXE_UPDATE: { case TASK_BITAXE_UPDATE: {
@ -42,10 +39,7 @@ void workerTask(void *pvParameters) {
case TASK_PRICE_UPDATE: { case TASK_PRICE_UPDATE: {
uint currency = getCurrentCurrency(); uint currency = getCurrentCurrency();
uint price = getPrice(currency); uint price = getPrice(currency);
// u_char priceSymbol = '$';
// if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) {
// priceSymbol = '[';
// }
if (getCurrentScreen() == SCREEN_BTC_TICKER) { if (getCurrentScreen() == SCREEN_BTC_TICKER) {
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE)); taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE));
} else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) { } else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) {
@ -121,29 +115,6 @@ void taskScreenRotate(void *pvParameters) {
} }
} }
void IRAM_ATTR minuteTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
if (bitaxeFetchTaskHandle != NULL) {
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
}
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
void IRAM_ATTR screenRotateTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
void setupTasks() { void setupTasks() {
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem)); workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
@ -159,65 +130,6 @@ void setupTasks() {
setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN)); setCurrentScreen(preferences.getUInt("currentScreen", DEFAULT_CURRENT_SCREEN));
} }
void setupTimeUpdateTimer(void *pvParameters) {
const esp_timer_create_args_t minuteTimerConfig = {
.callback = &minuteTimerISR, .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);
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
// xTaskNotifyGive(timeUpdateTaskHandle);
vTaskDelete(NULL);
}
void setupScreenRotateTimer(void *pvParameters) {
const esp_timer_create_args_t screenRotateTimerConfig = {
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) {
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
}
vTaskDelete(NULL);
}
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); }
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
void setTimerActive(bool status) {
if (status) {
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
queueLedEffect(LED_EFFECT_START_TIMER);
preferences.putBool("timerActive", true);
} else {
esp_timer_stop(screenRotateTimer);
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false);
}
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
}
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
uint getCurrentScreen() { return currentScreen; } uint getCurrentScreen() { return currentScreen; }
void setCurrentScreen(uint newScreen) { void setCurrentScreen(uint newScreen) {

View file

@ -16,9 +16,6 @@
extern TaskHandle_t workerTaskHandle; extern TaskHandle_t workerTaskHandle;
extern TaskHandle_t taskScreenRotateTaskHandle; extern TaskHandle_t taskScreenRotateTaskHandle;
extern esp_timer_handle_t screenRotateTimer;
extern esp_timer_handle_t minuteTimer;
extern QueueHandle_t workQueue; extern QueueHandle_t workQueue;
typedef enum { typedef enum {
@ -42,21 +39,14 @@ void previousScreen();
void showSystemStatusScreen(); void showSystemStatusScreen();
void setupTimeUpdateTimer(void *pvParameters);
void setupScreenRotateTimer(void *pvParameters);
void IRAM_ATTR minuteTimerISR(void *arg);
void IRAM_ATTR screenRotateTimerISR(void *arg);
// void taskPriceUpdate(void *pvParameters); // void taskPriceUpdate(void *pvParameters);
// void taskBlockUpdate(void *pvParameters); // void taskBlockUpdate(void *pvParameters);
// void taskTimeUpdate(void *pvParameters); // void taskTimeUpdate(void *pvParameters);
void taskScreenRotate(void *pvParameters); void taskScreenRotate(void *pvParameters);
uint getTimerSeconds();
bool isTimerActive();
void setTimerActive(bool status);
void toggleTimerActive();
void setupTasks(); void setupTasks();
void setCurrentCurrency(char currency); void setCurrentCurrency(char currency);

86
src/lib/timers.cpp Normal file
View file

@ -0,0 +1,86 @@
#include "timers.hpp"
esp_timer_handle_t screenRotateTimer;
esp_timer_handle_t minuteTimer;
void setupTimeUpdateTimer(void *pvParameters) {
const esp_timer_create_args_t minuteTimerConfig = {
.callback = &minuteTimerISR, .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);
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
// xTaskNotifyGive(timeUpdateTaskHandle);
vTaskDelete(NULL);
}
void setupScreenRotateTimer(void *pvParameters) {
const esp_timer_create_args_t screenRotateTimerConfig = {
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
if (preferences.getBool("timerActive", DEFAULT_TIMER_ACTIVE)) {
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
}
vTaskDelete(NULL);
}
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", DEFAULT_TIMER_SECONDS); }
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
void setTimerActive(bool status) {
if (status) {
esp_timer_start_periodic(screenRotateTimer,
getTimerSeconds() * usPerSecond);
queueLedEffect(LED_EFFECT_START_TIMER);
preferences.putBool("timerActive", true);
} else {
esp_timer_stop(screenRotateTimer);
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false);
}
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
}
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
void IRAM_ATTR minuteTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
if (bitaxeFetchTaskHandle != NULL) {
vTaskNotifyGiveFromISR(bitaxeFetchTaskHandle, &xHigherPriorityTaskWoken);
}
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}
void IRAM_ATTR screenRotateTimerISR(void *arg) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE) {
portYIELD_FROM_ISR();
}
}

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

@ -0,0 +1,22 @@
#pragma once
#include <esp_timer.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "lib/shared.hpp"
#include "lib/screen_handler.hpp"
extern esp_timer_handle_t screenRotateTimer;
extern esp_timer_handle_t minuteTimer;
void setupTimeUpdateTimer(void *pvParameters);
void setupScreenRotateTimer(void *pvParameters);
void IRAM_ATTR minuteTimerISR(void *arg);
void IRAM_ATTR screenRotateTimerISR(void *arg);
uint getTimerSeconds();
bool isTimerActive();
void setTimerActive(bool status);
void toggleTimerActive();

View file

@ -1,41 +1,51 @@
#include "v2_notify.hpp" #include "v2_notify.hpp"
WebSocketsClient webSocket; using namespace V2Notify;
TaskHandle_t v2NotifyTaskHandle;
void setupV2Notify() namespace V2Notify
{ {
String hostname = "ws.btclock.dev"; WebSocketsClient webSocket;
if ( preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE)) {
Serial.println(F("Connecting to V2 staging source")); TaskHandle_t v2NotifyTaskHandle;
hostname = "ws-staging.btclock.dev";
} else { void setupV2Notify()
Serial.println(F("Connecting to V2 source")); {
String hostname = "ws.btclock.dev";
if (preferences.getBool("stagingSource", DEFAULT_STAGING_SOURCE))
{
Serial.println(F("Connecting to V2 staging source"));
hostname = "ws-staging.btclock.dev";
}
else
{
Serial.println(F("Connecting to V2 source"));
}
webSocket.beginSSL(hostname, 443, "/api/v2/ws");
webSocket.onEvent(V2Notify::onWebsocketV2Event);
webSocket.setReconnectInterval(5000);
webSocket.enableHeartbeat(15000, 3000, 2);
V2Notify::setupV2NotifyTask();
} }
webSocket.beginSSL(hostname, 443, "/api/v2/ws"); void onWebsocketV2Event(WStype_t type, uint8_t *payload, size_t length)
webSocket.onEvent(onWebsocketV2Event); {
webSocket.setReconnectInterval(5000); switch (type)
webSocket.enableHeartbeat(15000, 3000, 2);
setupV2NotifyTask();
}
void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length) {
switch(type) {
case WStype_DISCONNECTED:
Serial.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
{ {
Serial.printf("[WSc] Connected to url: %s\n", payload); case WStype_DISCONNECTED:
Serial.printf("[WSc] Disconnected!\n");
break;
case WStype_CONNECTED:
{
Serial.printf("[WSc] Connected to url: %s\n", payload);
JsonDocument response; JsonDocument response;
response["type"] = "subscribe"; response["type"] = "subscribe";
response["eventType"] = "blockfee"; response["eventType"] = "blockfee";
size_t responseLength = measureMsgPack(response); size_t responseLength = measureMsgPack(response);
uint8_t* buffer = new uint8_t[responseLength]; uint8_t *buffer = new uint8_t[responseLength];
serializeMsgPack(response, buffer, responseLength); serializeMsgPack(response, buffer, responseLength);
webSocket.sendBIN(buffer, responseLength); webSocket.sendBIN(buffer, responseLength);
delete[] buffer; delete[] buffer;
@ -62,83 +72,89 @@ void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length) {
{ {
currenciesArray.add(str); currenciesArray.add(str);
} }
// response["currencies"] = currenciesArray; // response["currencies"] = currenciesArray;
responseLength = measureMsgPack(response); responseLength = measureMsgPack(response);
buffer = new uint8_t[responseLength]; buffer = new uint8_t[responseLength];
serializeMsgPack(response, buffer, responseLength); serializeMsgPack(response, buffer, responseLength);
webSocket.sendBIN(buffer, responseLength); webSocket.sendBIN(buffer, responseLength);
break; break;
} }
case WStype_TEXT: case WStype_TEXT:
Serial.printf("[WSc] get text: %s\n", payload); Serial.printf("[WSc] get text: %s\n", payload);
// send message to server // send message to server
// webSocket.sendTXT("message here"); // webSocket.sendTXT("message here");
break; break;
case WStype_BIN: case WStype_BIN:
{ {
JsonDocument doc; JsonDocument doc;
DeserializationError error = deserializeMsgPack(doc, payload, length); DeserializationError error = deserializeMsgPack(doc, payload, length);
handleV2Message(doc); V2Notify::handleV2Message(doc);
break; break;
} }
case WStype_ERROR: case WStype_ERROR:
case WStype_FRAGMENT_TEXT_START: case WStype_FRAGMENT_TEXT_START:
case WStype_FRAGMENT_BIN_START: case WStype_FRAGMENT_BIN_START:
case WStype_FRAGMENT: case WStype_FRAGMENT:
case WStype_PING: case WStype_PING:
case WStype_PONG: case WStype_PONG:
case WStype_FRAGMENT_FIN: case WStype_FRAGMENT_FIN:
break; break;
} }
}
void handleV2Message(JsonDocument doc) {
if (doc.containsKey("blockheight"))
{
uint newBlockHeight = doc["blockheight"].as<uint>();
if (newBlockHeight == getBlockHeight()) {
return;
} }
processNewBlock(newBlockHeight); void handleV2Message(JsonDocument doc)
} {
else if (doc.containsKey("blockfee")) if (doc.containsKey("blockheight"))
{ {
uint medianFee = doc["blockfee"].as<uint>(); uint newBlockHeight = doc["blockheight"].as<uint>();
processNewBlockFee(medianFee); if (newBlockHeight == getBlockHeight())
} else if (doc.containsKey("price")) {
{ return;
}
// Iterate through the key-value pairs of the "price" object processNewBlock(newBlockHeight);
for (JsonPair kv : doc["price"].as<JsonObject>()) { }
const char* currency = kv.key().c_str(); else if (doc.containsKey("blockfee"))
uint newPrice = kv.value().as<uint>(); {
uint medianFee = doc["blockfee"].as<uint>();
processNewPrice(newPrice, getCurrencyChar(currency));
processNewBlockFee(medianFee);
}
else if (doc.containsKey("price"))
{
// Iterate through the key-value pairs of the "price" object
for (JsonPair kv : doc["price"].as<JsonObject>())
{
const char *currency = kv.key().c_str();
uint newPrice = kv.value().as<uint>();
processNewPrice(newPrice, getCurrencyChar(currency));
}
}
} }
}
}
void taskV2Notify(void *pvParameters) { void taskV2Notify(void *pvParameters)
for(;;) { {
webSocket.loop(); for (;;)
vTaskDelay(10 / portTICK_PERIOD_MS); {
webSocket.loop();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
} }
}
void setupV2NotifyTask() { void setupV2NotifyTask()
xTaskCreate(taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY, {
&v2NotifyTaskHandle); xTaskCreate(V2Notify::taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY,
&V2Notify::v2NotifyTaskHandle);
}
} bool isV2NotifyConnected()
{
bool isV2NotifyConnected() return webSocket.isConnected();
{ }
return webSocket.isConnected(); }
}

View file

@ -8,16 +8,18 @@
#include "lib/screen_handler.hpp" #include "lib/screen_handler.hpp"
extern TaskHandle_t v2NotifyTaskHandle; namespace V2Notify {
extern TaskHandle_t v2NotifyTaskHandle;
void setupV2NotifyTask(); void setupV2NotifyTask();
void taskV2Notify(void *pvParameters); void taskV2Notify(void *pvParameters);
void setupV2Notify(); void setupV2Notify();
void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length); void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length);
void handleV2Message(JsonDocument doc); void handleV2Message(JsonDocument doc);
bool isV2NotifyConnected(); bool isV2NotifyConnected();
}
// void stopV2Notify(); // void stopV2Notify();
// void restartV2Notify(); // void restartV2Notify();
// bool getPriceNotifyInit(); // bool getPriceNotifyInit();

View file

@ -256,9 +256,10 @@ JsonDocument getStatusObject()
// root["espPsramSize"] = ESP.getPsramSize(); // root["espPsramSize"] = ESP.getPsramSize();
JsonObject conStatus = root["connectionStatus"].to<JsonObject>(); JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
conStatus["price"] = isPriceNotifyConnected(); conStatus["price"] = isPriceNotifyConnected();
conStatus["blocks"] = isBlockNotifyConnected(); conStatus["blocks"] = isBlockNotifyConnected();
conStatus["V2"] = isV2NotifyConnected(); conStatus["V2"] = V2Notify::isV2NotifyConnected();
conStatus["nostr"] = nostrConnected(); conStatus["nostr"] = nostrConnected();

View file

@ -51,7 +51,7 @@ extern "C" void app_main()
if (hasLightLevel()) { if (hasLightLevel()) {
if (preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0) if (preferences.getUInt("luxLightToggle", DEFAULT_LUX_LIGHT_TOGGLE) != 0)
{ {
if (hasLightLevel() && getLightLevel() == 0) if (hasLightLevel() && getLightLevel() <= 2)
{ {
if (frontlightIsOn()) { if (frontlightIsOn()) {
frontlightFadeOutAll(); frontlightFadeOutAll();