Price notify refactor
This commit is contained in:
parent
e19cad05bc
commit
e987e9afd5
18 changed files with 628 additions and 297 deletions
|
@ -1,7 +1,7 @@
|
||||||
#include "config.hpp"
|
#include "config.hpp"
|
||||||
#include "led_handler.hpp"
|
|
||||||
|
|
||||||
#define MAX_ATTEMPTS_WIFI_CONNECTION 20
|
// Global instance definitions
|
||||||
|
PriceNotify::PriceNotifyManager priceManager;
|
||||||
|
|
||||||
// zlib_turbo zt;
|
// zlib_turbo zt;
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ void setupPreferences()
|
||||||
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
EPDManager::getInstance().setForegroundColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||||
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
EPDManager::getInstance().setBackgroundColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||||
setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
|
setBlockHeight(preferences.getUInt("blockHeight", INITIAL_BLOCK_HEIGHT));
|
||||||
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
priceManager.processNewPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
||||||
|
|
||||||
if (!preferences.isKey("enableDebugLog")) {
|
if (!preferences.isKey("enableDebugLog")) {
|
||||||
preferences.putBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG);
|
preferences.putBool("enableDebugLog", DEFAULT_ENABLE_DEBUG_LOG);
|
||||||
|
@ -375,6 +375,14 @@ void setupWebsocketClients(void *pvParameters)
|
||||||
{
|
{
|
||||||
setupBlockNotify();
|
setupBlockNotify();
|
||||||
setupPriceNotify();
|
setupPriceNotify();
|
||||||
|
|
||||||
|
// Create task for price manager loop
|
||||||
|
xTaskCreate([](void* param) {
|
||||||
|
for (;;) {
|
||||||
|
priceManager.loop();
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}, "priceManagerLoop", (6 * 1024), NULL, tskIDLE_PRIORITY, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
vTaskDelete(NULL);
|
||||||
|
@ -753,3 +761,17 @@ DataSourceType getDataSource() {
|
||||||
void setDataSource(DataSourceType source) {
|
void setDataSource(DataSourceType source) {
|
||||||
preferences.putUChar("dataSource", static_cast<uint8_t>(source));
|
preferences.putUChar("dataSource", static_cast<uint8_t>(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupPriceNotify() {
|
||||||
|
priceManager.init(PriceNotify::PriceSource::COINCAP);
|
||||||
|
priceManager.onPriceUpdate([](PriceNotify::Currency currency, uint64_t price) {
|
||||||
|
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||||
|
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||||
|
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||||
|
{
|
||||||
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, static_cast<char>(currency)};
|
||||||
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
priceManager.connect();
|
||||||
|
}
|
||||||
|
|
|
@ -1,107 +1,88 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <MCP23017.h>
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFi.h>
|
||||||
#include <WiFiManager.h>
|
|
||||||
#include <base64.h>
|
|
||||||
#include <esp_task_wdt.h>
|
#include <esp_task_wdt.h>
|
||||||
|
#include <WiFiClientSecure.h>
|
||||||
|
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
#include <map>
|
#include <WiFiManager.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
#include "lib/block_notify.hpp"
|
|
||||||
#include "lib/button_handler.hpp"
|
|
||||||
#include "lib/epd.hpp"
|
|
||||||
// #include "lib/improv.hpp"
|
|
||||||
#include "lib/led_handler.hpp"
|
|
||||||
#include "lib/ota.hpp"
|
|
||||||
#include "lib/nostr_notify.hpp"
|
|
||||||
#include "lib/bitaxe_fetch.hpp"
|
|
||||||
#include "lib/mining_pool_stats_fetch.hpp"
|
|
||||||
|
|
||||||
#include "lib/v2_notify.hpp"
|
|
||||||
|
|
||||||
#include "lib/price_notify.hpp"
|
|
||||||
#include "lib/screen_handler.hpp"
|
|
||||||
#include "lib/shared.hpp"
|
|
||||||
#include "lib/webserver.hpp"
|
|
||||||
#ifdef HAS_FRONTLIGHT
|
|
||||||
#include "PCA9685.h"
|
|
||||||
#include "BH1750.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#include "block_notify.hpp"
|
||||||
|
#include "led_handler.hpp"
|
||||||
|
#include "nostr_notify.hpp"
|
||||||
|
#include "price_notify/price_notify.hpp"
|
||||||
|
#include "screen_handler.hpp"
|
||||||
#include "shared.hpp"
|
#include "shared.hpp"
|
||||||
#include "defaults.hpp"
|
#include "timers.hpp"
|
||||||
|
#include "v2_notify.hpp"
|
||||||
|
#include "webserver.hpp"
|
||||||
|
#include "button_handler.hpp"
|
||||||
|
#include "bitaxe_fetch.hpp"
|
||||||
|
#include "mining_pool_stats_fetch.hpp"
|
||||||
|
#include "epd.hpp"
|
||||||
|
|
||||||
#define NTP_SERVER "pool.ntp.org"
|
#ifdef HAS_FRONTLIGHT
|
||||||
#define DEFAULT_TIME_OFFSET_SECONDS 3600
|
#include <BH1750.h>
|
||||||
#ifndef MCP_DEV_ADDR
|
#include <PCA9685.h>
|
||||||
#define MCP_DEV_ADDR 0x20
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern Preferences preferences;
|
||||||
|
extern QueueHandle_t workQueue;
|
||||||
|
extern PriceNotify::PriceNotifyManager priceManager;
|
||||||
|
|
||||||
void setup();
|
void setupConfig();
|
||||||
void syncTime();
|
|
||||||
uint getLastTimeSync();
|
|
||||||
void setupPreferences();
|
|
||||||
void setupWebsocketClients(void *pvParameters);
|
|
||||||
void setupHardware();
|
|
||||||
void setupWifi();
|
void setupWifi();
|
||||||
|
void setupOTA();
|
||||||
|
void setupMDNS();
|
||||||
|
void setupDataSources();
|
||||||
|
void stopDataSources();
|
||||||
|
void restartDataSources();
|
||||||
|
void setupTasks();
|
||||||
void setupTimers();
|
void setupTimers();
|
||||||
|
void setupLittleFS();
|
||||||
|
void setupPreferences();
|
||||||
|
void setupWDT();
|
||||||
|
void setupWorkQueue();
|
||||||
|
void setupLedHandler();
|
||||||
|
void setupScreenHandler();
|
||||||
|
void setupWebserver();
|
||||||
|
void setupNostrNotify();
|
||||||
|
void setupBlockNotify();
|
||||||
|
void setupV2Notify();
|
||||||
|
void setupPriceNotify();
|
||||||
|
void setupHardware();
|
||||||
void finishSetup();
|
void finishSetup();
|
||||||
void setupMcp();
|
void syncTime();
|
||||||
|
|
||||||
|
void handleOTA();
|
||||||
|
void handleWifi();
|
||||||
|
void handleWDT();
|
||||||
|
void handleWorkQueue();
|
||||||
|
|
||||||
|
void setWifiTxPower(int8_t power);
|
||||||
|
void onWifiEvent(WiFiEvent_t event);
|
||||||
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
|
|
||||||
|
DataSourceType getDataSource();
|
||||||
|
void setDataSource(DataSourceType source);
|
||||||
|
String getMyHostname();
|
||||||
|
uint getLastTimeSync();
|
||||||
|
bool debugLogEnabled();
|
||||||
|
|
||||||
#ifdef HAS_FRONTLIGHT
|
#ifdef HAS_FRONTLIGHT
|
||||||
extern BH1750 bh1750;
|
|
||||||
extern bool hasLuxSensor;
|
|
||||||
float getLightLevel();
|
float getLightLevel();
|
||||||
bool hasLightLevel();
|
bool hasLightLevel();
|
||||||
|
|
||||||
|
extern PCA9685 flArray;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
String getMyHostname();
|
|
||||||
std::vector<ScreenMapping> getScreenNameMap();
|
|
||||||
|
|
||||||
std::vector<std::string> getLocalUrl();
|
|
||||||
// bool improv_connectWifi(std::string ssid, std::string password);
|
|
||||||
// void improvGetAvailableWifiNetworks();
|
|
||||||
// bool onImprovCommandCallback(improv::ImprovCommand cmd);
|
|
||||||
// void onImprovErrorCallback(improv::Error err);
|
|
||||||
// void improv_set_state(improv::State state);
|
|
||||||
// void improv_send_response(std::vector<uint8_t> &response);
|
|
||||||
// void improv_set_error(improv::Error error);
|
|
||||||
//void addCurrencyMappings(const std::vector<std::string>& currencies);
|
|
||||||
std::vector<std::string> getActiveCurrencies();
|
|
||||||
std::vector<std::string> getAvailableCurrencies();
|
|
||||||
|
|
||||||
bool isActiveCurrency(std::string ¤cy);
|
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
|
||||||
String getHwRev();
|
String getHwRev();
|
||||||
bool isWhiteVersion();
|
bool isWhiteVersion();
|
||||||
String getFsRev();
|
String getFsRev();
|
||||||
|
|
||||||
bool debugLogEnabled();
|
#define NTP_SERVER "pool.ntp.org"
|
||||||
|
#define DEFAULT_TIME_OFFSET_SECONDS 3600
|
||||||
void addScreenMapping(int value, const char* name);
|
|
||||||
// void addScreenMapping(int value, const String& name);
|
|
||||||
// void addScreenMapping(int value, const std::string& name);
|
|
||||||
|
|
||||||
int findScreenIndexByValue(int value);
|
|
||||||
String replaceAmbiguousChars(String input);
|
|
||||||
const char* getFirmwareFilename();
|
|
||||||
const char* getWebUiFilename();
|
|
||||||
// void loadIcons();
|
|
||||||
|
|
||||||
extern Preferences preferences;
|
|
||||||
extern MCP23017 mcp1;
|
|
||||||
#ifdef IS_BTCLOCK_V8
|
|
||||||
extern MCP23017 mcp2;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAS_FRONTLIGHT
|
|
||||||
extern PCA9685 flArray;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Expose DataSourceType enum
|
|
||||||
extern DataSourceType getDataSource();
|
|
||||||
extern void setDataSource(DataSourceType source);
|
|
6
src/lib/globals.hpp
Normal file
6
src/lib/globals.hpp
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "price_notify/price_notify.hpp"
|
||||||
|
|
||||||
|
// Global instances
|
||||||
|
extern PriceNotify::PriceNotifyManager priceManager;
|
|
@ -1,5 +1,6 @@
|
||||||
#include "nostr_notify.hpp"
|
#include "nostr_notify.hpp"
|
||||||
#include "led_handler.hpp"
|
#include "led_handler.hpp"
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
std::vector<nostr::NostrPool *> pools;
|
std::vector<nostr::NostrPool *> pools;
|
||||||
nostr::Transport *transport;
|
nostr::Transport *transport;
|
||||||
|
@ -171,7 +172,7 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
|
||||||
// Process the data
|
// Process the data
|
||||||
if (!typeValue.isEmpty()) {
|
if (!typeValue.isEmpty()) {
|
||||||
if (typeValue == "priceUsd") {
|
if (typeValue == "priceUsd") {
|
||||||
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
|
priceManager.processNewPrice(obj["content"].as<uint>(), static_cast<PriceNotify::Currency>(CURRENCY_USD));
|
||||||
}
|
}
|
||||||
else if (typeValue == "blockHeight") {
|
else if (typeValue == "blockHeight") {
|
||||||
processNewBlock(obj["content"].as<uint>());
|
processNewBlock(obj["content"].as<uint>());
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
#include "NostrEvent.h"
|
#include "NostrEvent.h"
|
||||||
#include "NostrPool.h"
|
#include "NostrPool.h"
|
||||||
|
|
||||||
#include "price_notify.hpp"
|
|
||||||
#include "block_notify.hpp"
|
#include "block_notify.hpp"
|
||||||
|
#include "price_notify/price_notify.hpp"
|
||||||
#include "lib/timers.hpp"
|
#include "lib/timers.hpp"
|
||||||
|
|
||||||
void setupNostrNotify(bool asDatasource, bool zapNotify);
|
void setupNostrNotify(bool asDatasource, bool zapNotify);
|
||||||
|
|
|
@ -1,175 +0,0 @@
|
||||||
#include "price_notify.hpp"
|
|
||||||
|
|
||||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
|
||||||
|
|
||||||
WebSocketsClient webSocket;
|
|
||||||
uint currentPrice = 90000;
|
|
||||||
unsigned long int lastPriceUpdate;
|
|
||||||
bool priceNotifyInit = false;
|
|
||||||
std::map<char, std::uint64_t> currencyMap;
|
|
||||||
std::map<char, unsigned long int> lastUpdateMap;
|
|
||||||
TaskHandle_t priceNotifyTaskHandle;
|
|
||||||
|
|
||||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
|
||||||
|
|
||||||
void setupPriceNotify()
|
|
||||||
{
|
|
||||||
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin");
|
|
||||||
webSocket.onEvent([](WStype_t type, uint8_t * payload, size_t length) {
|
|
||||||
onWebsocketPriceEvent(type, payload, length);
|
|
||||||
});
|
|
||||||
webSocket.setReconnectInterval(5000);
|
|
||||||
webSocket.enableHeartbeat(15000, 3000, 2);
|
|
||||||
|
|
||||||
setupPriceNotifyTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length) {
|
|
||||||
switch(type) {
|
|
||||||
case WStype_DISCONNECTED:
|
|
||||||
Serial.println(F("Price WS Connection Closed"));
|
|
||||||
break;
|
|
||||||
case WStype_CONNECTED:
|
|
||||||
{
|
|
||||||
Serial.println("Connected to " + String(wsServerPrice));
|
|
||||||
priceNotifyInit = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WStype_TEXT:
|
|
||||||
{
|
|
||||||
JsonDocument doc;
|
|
||||||
deserializeJson(doc, (char *)payload);
|
|
||||||
|
|
||||||
if (doc["bitcoin"].is<JsonObject>())
|
|
||||||
{
|
|
||||||
if (currentPrice != doc["bitcoin"].as<long>())
|
|
||||||
{
|
|
||||||
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case WStype_BIN:
|
|
||||||
break;
|
|
||||||
case WStype_ERROR:
|
|
||||||
case WStype_FRAGMENT_TEXT_START:
|
|
||||||
case WStype_FRAGMENT_BIN_START:
|
|
||||||
case WStype_FRAGMENT:
|
|
||||||
case WStype_PING:
|
|
||||||
case WStype_PONG:
|
|
||||||
case WStype_FRAGMENT_FIN:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void processNewPrice(uint newPrice, char currency)
|
|
||||||
{
|
|
||||||
uint minSecPriceUpd = preferences.getUInt(
|
|
||||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
|
||||||
uint currentTime = esp_timer_get_time() / 1000000;
|
|
||||||
|
|
||||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end() ||
|
|
||||||
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
|
||||||
{
|
|
||||||
currencyMap[currency] = newPrice;
|
|
||||||
|
|
||||||
// Store price in preferences if enough time has passed
|
|
||||||
if (lastUpdateMap[currency] == 0 || (currentTime - lastUpdateMap[currency]) > 120)
|
|
||||||
{
|
|
||||||
String prefKey = String("lastPrice_") + getCurrencyCode(currency).c_str();
|
|
||||||
preferences.putUInt(prefKey.c_str(), newPrice);
|
|
||||||
}
|
|
||||||
|
|
||||||
lastUpdateMap[currency] = currentTime;
|
|
||||||
|
|
||||||
if (workQueue != nullptr && (ScreenHandler::getCurrentScreen() == SCREEN_BTC_TICKER ||
|
|
||||||
ScreenHandler::getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
|
||||||
ScreenHandler::getCurrentScreen() == SCREEN_MARKET_CAP))
|
|
||||||
{
|
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void loadStoredPrices()
|
|
||||||
{
|
|
||||||
// Load prices for all supported currencies
|
|
||||||
std::vector<std::string> currencies = getAvailableCurrencies();
|
|
||||||
|
|
||||||
for (const std::string ¤cy : currencies) {
|
|
||||||
// Get first character as the currency identifier
|
|
||||||
String prefKey = String("lastPrice_") + currency.c_str();
|
|
||||||
uint storedPrice = preferences.getUInt(prefKey.c_str(), 0);
|
|
||||||
|
|
||||||
if (storedPrice > 0) {
|
|
||||||
currencyMap[getCurrencyChar(currency)] = storedPrice;
|
|
||||||
// Initialize lastUpdateMap to 0 so next update will store immediately
|
|
||||||
lastUpdateMap[getCurrencyChar(currency)] = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint getLastPriceUpdate(char currency)
|
|
||||||
{
|
|
||||||
if (lastUpdateMap.find(currency) == lastUpdateMap.end())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return lastUpdateMap[currency];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint getPrice(char currency)
|
|
||||||
{
|
|
||||||
if (currencyMap.find(currency) == currencyMap.end())
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return currencyMap[currency];
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPrice(uint newPrice, char currency)
|
|
||||||
{
|
|
||||||
currencyMap[currency] = newPrice;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isPriceNotifyConnected()
|
|
||||||
{
|
|
||||||
return webSocket.isConnected();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getPriceNotifyInit()
|
|
||||||
{
|
|
||||||
return priceNotifyInit;
|
|
||||||
}
|
|
||||||
|
|
||||||
void stopPriceNotify()
|
|
||||||
{
|
|
||||||
webSocket.disconnect();
|
|
||||||
if (priceNotifyTaskHandle != NULL) {
|
|
||||||
vTaskDelete(priceNotifyTaskHandle);
|
|
||||||
priceNotifyTaskHandle = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void restartPriceNotify()
|
|
||||||
{
|
|
||||||
stopPriceNotify();
|
|
||||||
setupPriceNotify();
|
|
||||||
}
|
|
||||||
|
|
||||||
void taskPriceNotify(void *pvParameters)
|
|
||||||
{
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
webSocket.loop();
|
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupPriceNotifyTask()
|
|
||||||
{
|
|
||||||
xTaskCreate(taskPriceNotify, "priceNotify", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
|
||||||
&priceNotifyTaskHandle);
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <Arduino.h>
|
|
||||||
#include <ArduinoJson.h>
|
|
||||||
#include <WebSocketsClient.h>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "lib/screen_handler.hpp"
|
|
||||||
|
|
||||||
extern TaskHandle_t priceNotifyTaskHandle;
|
|
||||||
|
|
||||||
void setupPriceNotify();
|
|
||||||
void setupPriceNotifyTask();
|
|
||||||
void taskPriceNotify(void *pvParameters);
|
|
||||||
|
|
||||||
void onWebsocketPriceEvent(WStype_t type, uint8_t * payload, size_t length);
|
|
||||||
|
|
||||||
uint getPrice(char currency);
|
|
||||||
void setPrice(uint newPrice, char currency);
|
|
||||||
|
|
||||||
void processNewPrice(uint newPrice, char currency);
|
|
||||||
|
|
||||||
bool isPriceNotifyConnected();
|
|
||||||
void stopPriceNotify();
|
|
||||||
void restartPriceNotify();
|
|
||||||
|
|
||||||
bool getPriceNotifyInit();
|
|
||||||
uint getLastPriceUpdate(char currency);
|
|
||||||
void loadStoredPrices();
|
|
53
src/lib/price_notify/interfaces/price_source.hpp
Normal file
53
src/lib/price_notify/interfaces/price_source.hpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <WebSocketsClient.h>
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
using std::function;
|
||||||
|
using std::map;
|
||||||
|
using std::string;
|
||||||
|
|
||||||
|
// Convert char-based currency to enum for type safety
|
||||||
|
enum class Currency : char {
|
||||||
|
USD = '$',
|
||||||
|
EUR = '[',
|
||||||
|
GBP = ']',
|
||||||
|
JPY = '^',
|
||||||
|
AUD = '_',
|
||||||
|
CAD = '`'
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPriceSource {
|
||||||
|
public:
|
||||||
|
virtual ~IPriceSource() = default;
|
||||||
|
|
||||||
|
// Initialize and connect to the websocket
|
||||||
|
virtual void connect() = 0;
|
||||||
|
|
||||||
|
// Disconnect and cleanup
|
||||||
|
virtual void disconnect() = 0;
|
||||||
|
|
||||||
|
// Check connection status
|
||||||
|
virtual bool isConnected() const = 0;
|
||||||
|
|
||||||
|
// Get the last known price for a currency
|
||||||
|
virtual uint64_t getPrice(Currency currency) const = 0;
|
||||||
|
|
||||||
|
// Get the last update timestamp for a currency
|
||||||
|
virtual uint32_t getLastUpdate(Currency currency) const = 0;
|
||||||
|
|
||||||
|
// Set callback for price updates
|
||||||
|
virtual void onPriceUpdate(function<void(Currency, uint64_t)> callback) = 0;
|
||||||
|
|
||||||
|
// Process websocket loop - should be called regularly
|
||||||
|
virtual void loop() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
function<void(Currency, uint64_t)> priceUpdateCallback;
|
||||||
|
};
|
||||||
|
} // namespace PriceNotify
|
115
src/lib/price_notify/price_notify.cpp
Normal file
115
src/lib/price_notify/price_notify.cpp
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include "price_notify.hpp"
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
using std::make_unique;
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
PriceNotifyManager::PriceNotifyManager() : currentSource(PriceSource::NONE) {}
|
||||||
|
|
||||||
|
PriceNotifyManager::~PriceNotifyManager() {
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::init(PriceSource source) {
|
||||||
|
currentSource = source;
|
||||||
|
setPriceSource(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::connect() {
|
||||||
|
if (priceSource) {
|
||||||
|
priceSource->connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::disconnect() {
|
||||||
|
if (priceSource) {
|
||||||
|
priceSource->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PriceNotifyManager::isConnected() const {
|
||||||
|
return priceSource ? priceSource->isConnected() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t PriceNotifyManager::getPrice(Currency currency) const {
|
||||||
|
if (priceSource) {
|
||||||
|
return priceSource->getPrice(currency);
|
||||||
|
}
|
||||||
|
// If no price source, return from internal storage
|
||||||
|
auto it = prices.find(currency);
|
||||||
|
return (it != prices.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t PriceNotifyManager::getLastUpdate(Currency currency) const {
|
||||||
|
if (priceSource) {
|
||||||
|
return priceSource->getLastUpdate(currency);
|
||||||
|
}
|
||||||
|
// If no price source, return from internal storage
|
||||||
|
auto it = lastUpdates.find(currency);
|
||||||
|
return (it != lastUpdates.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::onPriceUpdate(function<void(Currency, uint64_t)> callback) {
|
||||||
|
userCallback = callback;
|
||||||
|
if (priceSource) {
|
||||||
|
priceSource->onPriceUpdate([this](Currency currency, uint64_t price) {
|
||||||
|
if (userCallback) {
|
||||||
|
userCallback(currency, price);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::loop() {
|
||||||
|
if (priceSource) {
|
||||||
|
priceSource->loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::setPriceSource(PriceSource source) {
|
||||||
|
// Store the callback before destroying the old source
|
||||||
|
auto oldCallback = userCallback;
|
||||||
|
|
||||||
|
// Disconnect and destroy old source
|
||||||
|
if (priceSource) {
|
||||||
|
priceSource->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create new source
|
||||||
|
switch (source) {
|
||||||
|
case PriceSource::COINCAP:
|
||||||
|
priceSource = make_unique<CoinCapSource>();
|
||||||
|
break;
|
||||||
|
case PriceSource::KRAKEN:
|
||||||
|
priceSource = make_unique<KrakenSource>();
|
||||||
|
break;
|
||||||
|
case PriceSource::NONE:
|
||||||
|
priceSource.reset();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentSource = source;
|
||||||
|
|
||||||
|
// Restore callback if it exists
|
||||||
|
if (oldCallback) {
|
||||||
|
onPriceUpdate(oldCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PriceSource PriceNotifyManager::getCurrentSource() const {
|
||||||
|
return currentSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PriceNotifyManager::processNewPrice(uint64_t price, Currency currency) {
|
||||||
|
// Store the price and timestamp
|
||||||
|
prices[currency] = price;
|
||||||
|
lastUpdates[currency] = esp_timer_get_time() / 1000000; // Current time in seconds
|
||||||
|
|
||||||
|
// If we have a callback, notify about the price update
|
||||||
|
if (userCallback) {
|
||||||
|
userCallback(currency, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PriceNotify
|
68
src/lib/price_notify/price_notify.hpp
Normal file
68
src/lib/price_notify/price_notify.hpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "interfaces/price_source.hpp"
|
||||||
|
#include "sources/coincap_source.hpp"
|
||||||
|
#include "sources/kraken_source.hpp"
|
||||||
|
#include <memory>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
using std::unique_ptr;
|
||||||
|
using std::function;
|
||||||
|
using std::map;
|
||||||
|
|
||||||
|
enum class PriceSource {
|
||||||
|
NONE, // Added for when no explicit source is set
|
||||||
|
COINCAP,
|
||||||
|
KRAKEN
|
||||||
|
};
|
||||||
|
|
||||||
|
class PriceNotifyManager {
|
||||||
|
public:
|
||||||
|
PriceNotifyManager();
|
||||||
|
~PriceNotifyManager();
|
||||||
|
|
||||||
|
// Initialize with a specific price source
|
||||||
|
void init(PriceSource source);
|
||||||
|
|
||||||
|
// Connect to the price source
|
||||||
|
void connect();
|
||||||
|
|
||||||
|
// Disconnect from the price source
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
// Check if connected to price source
|
||||||
|
bool isConnected() const;
|
||||||
|
|
||||||
|
// Get the last known price for a currency
|
||||||
|
uint64_t getPrice(Currency currency) const;
|
||||||
|
|
||||||
|
// Get the last update timestamp for a currency
|
||||||
|
uint32_t getLastUpdate(Currency currency) const;
|
||||||
|
|
||||||
|
// Set callback for price updates
|
||||||
|
void onPriceUpdate(function<void(Currency, uint64_t)> callback);
|
||||||
|
|
||||||
|
// Process websocket loop - should be called regularly
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
// Change the price source
|
||||||
|
void setPriceSource(PriceSource source);
|
||||||
|
|
||||||
|
// Get current price source
|
||||||
|
PriceSource getCurrentSource() const;
|
||||||
|
|
||||||
|
// Process new price from external source
|
||||||
|
void processNewPrice(uint64_t price, Currency currency);
|
||||||
|
|
||||||
|
private:
|
||||||
|
unique_ptr<IPriceSource> priceSource;
|
||||||
|
PriceSource currentSource;
|
||||||
|
function<void(Currency, uint64_t)> userCallback;
|
||||||
|
|
||||||
|
// For storing prices when no explicit source is set
|
||||||
|
map<Currency, uint64_t> prices;
|
||||||
|
map<Currency, uint32_t> lastUpdates;
|
||||||
|
};
|
||||||
|
} // namespace PriceNotify
|
96
src/lib/price_notify/sources/coincap_source.cpp
Normal file
96
src/lib/price_notify/sources/coincap_source.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
#include "coincap_source.hpp"
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
CoinCapSource* CoinCapSource::instance = nullptr;
|
||||||
|
|
||||||
|
CoinCapSource::CoinCapSource() : connected(false) {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoinCapSource::~CoinCapSource() {
|
||||||
|
disconnect();
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::connect() {
|
||||||
|
webSocket.beginSSL("ws.coincap.io", 443, "/prices?assets=bitcoin");
|
||||||
|
webSocket.onEvent([](WStype_t type, uint8_t* payload, size_t length) {
|
||||||
|
if (instance) {
|
||||||
|
instance->handleWebSocketEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::disconnect() {
|
||||||
|
webSocket.disconnect();
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CoinCapSource::isConnected() const {
|
||||||
|
return connected && webSocket.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t CoinCapSource::getPrice(Currency currency) const {
|
||||||
|
auto it = prices.find(currency);
|
||||||
|
return (it != prices.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CoinCapSource::getLastUpdate(Currency currency) const {
|
||||||
|
auto it = lastUpdates.find(currency);
|
||||||
|
return (it != lastUpdates.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::onPriceUpdate(function<void(Currency, uint64_t)> callback) {
|
||||||
|
priceUpdateCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::handleWebSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
Serial.println(F("CoinCap WS Disconnected"));
|
||||||
|
connected = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
Serial.println(F("CoinCap WS Connected"));
|
||||||
|
connected = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WStype_TEXT:
|
||||||
|
processMessage((char*)payload);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CoinCapSource::processMessage(const char* payload) {
|
||||||
|
StaticJsonDocument<512> doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.println(F("Failed to parse CoinCap message"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doc["bitcoin"].is<JsonObject>()) {
|
||||||
|
uint64_t price = doc["bitcoin"].as<uint64_t>();
|
||||||
|
uint32_t timestamp = esp_timer_get_time() / 1000000; // Current time in seconds
|
||||||
|
|
||||||
|
prices[Currency::USD] = price;
|
||||||
|
lastUpdates[Currency::USD] = timestamp;
|
||||||
|
|
||||||
|
if (priceUpdateCallback) {
|
||||||
|
priceUpdateCallback(Currency::USD, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace PriceNotify
|
36
src/lib/price_notify/sources/coincap_source.hpp
Normal file
36
src/lib/price_notify/sources/coincap_source.hpp
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../interfaces/price_source.hpp"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
|
||||||
|
class CoinCapSource : public IPriceSource {
|
||||||
|
public:
|
||||||
|
CoinCapSource();
|
||||||
|
~CoinCapSource() override;
|
||||||
|
|
||||||
|
void connect() override;
|
||||||
|
void disconnect() override;
|
||||||
|
bool isConnected() const override;
|
||||||
|
uint64_t getPrice(Currency currency) const override;
|
||||||
|
uint32_t getLastUpdate(Currency currency) const override;
|
||||||
|
void onPriceUpdate(function<void(Currency, uint64_t)> callback) override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void onWebSocketEvent(WStype_t type, uint8_t* payload, size_t length);
|
||||||
|
void handleWebSocketEvent(WStype_t type, uint8_t* payload, size_t length);
|
||||||
|
void processMessage(const char* payload);
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
map<Currency, uint64_t> prices;
|
||||||
|
map<Currency, uint32_t> lastUpdates;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
static CoinCapSource* instance; // For callback handling
|
||||||
|
};
|
||||||
|
} // namespace PriceNotify
|
118
src/lib/price_notify/sources/kraken_source.cpp
Normal file
118
src/lib/price_notify/sources/kraken_source.cpp
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
#include "kraken_source.hpp"
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
KrakenSource* KrakenSource::instance = nullptr;
|
||||||
|
|
||||||
|
KrakenSource::KrakenSource() : connected(false) {
|
||||||
|
instance = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
KrakenSource::~KrakenSource() {
|
||||||
|
disconnect();
|
||||||
|
instance = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::connect() {
|
||||||
|
webSocket.beginSSL("ws.kraken.com", 443, "/ws");
|
||||||
|
webSocket.onEvent([](WStype_t type, uint8_t* payload, size_t length) {
|
||||||
|
if (instance) {
|
||||||
|
instance->handleWebSocketEvent(type, payload, length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
webSocket.enableHeartbeat(15000, 3000, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::disconnect() {
|
||||||
|
webSocket.disconnect();
|
||||||
|
connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool KrakenSource::isConnected() const {
|
||||||
|
return connected && webSocket.isConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t KrakenSource::getPrice(Currency currency) const {
|
||||||
|
auto it = prices.find(currency);
|
||||||
|
return (it != prices.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t KrakenSource::getLastUpdate(Currency currency) const {
|
||||||
|
auto it = lastUpdates.find(currency);
|
||||||
|
return (it != lastUpdates.end()) ? it->second : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::onPriceUpdate(function<void(Currency, uint64_t)> callback) {
|
||||||
|
priceUpdateCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::loop() {
|
||||||
|
webSocket.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::handleWebSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
|
||||||
|
switch(type) {
|
||||||
|
case WStype_DISCONNECTED:
|
||||||
|
Serial.println(F("Kraken WS Disconnected"));
|
||||||
|
connected = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WStype_CONNECTED:
|
||||||
|
Serial.println(F("Kraken WS Connected"));
|
||||||
|
connected = true;
|
||||||
|
subscribe();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WStype_TEXT:
|
||||||
|
processMessage((char*)payload);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::subscribe() {
|
||||||
|
// Subscribe to XBT/USD ticker
|
||||||
|
StaticJsonDocument<256> doc;
|
||||||
|
doc["event"] = "subscribe";
|
||||||
|
JsonArray pair = doc.createNestedArray("pair");
|
||||||
|
pair.add("XBT/USD");
|
||||||
|
doc["subscription"]["name"] = "ticker";
|
||||||
|
|
||||||
|
String message;
|
||||||
|
serializeJson(doc, message);
|
||||||
|
webSocket.sendTXT(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void KrakenSource::processMessage(const char* payload) {
|
||||||
|
StaticJsonDocument<512> doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.println(F("Failed to parse Kraken message"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it's a ticker update (array format)
|
||||||
|
if (doc.is<JsonArray>() && doc.size() >= 4) {
|
||||||
|
JsonArray arr = doc.as<JsonArray>();
|
||||||
|
if (arr[2] == "ticker" && arr[3] == "XBT/USD") {
|
||||||
|
JsonObject tickerData = arr[1].as<JsonObject>();
|
||||||
|
if (tickerData.containsKey("c")) {
|
||||||
|
// Get the first value from the "c" array which is the last trade price
|
||||||
|
uint64_t price = tickerData["c"][0].as<float>() * 100; // Convert to cents
|
||||||
|
uint32_t timestamp = esp_timer_get_time() / 1000000; // Current time in seconds
|
||||||
|
|
||||||
|
prices[Currency::USD] = price;
|
||||||
|
lastUpdates[Currency::USD] = timestamp;
|
||||||
|
|
||||||
|
if (priceUpdateCallback) {
|
||||||
|
priceUpdateCallback(Currency::USD, price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace PriceNotify
|
37
src/lib/price_notify/sources/kraken_source.hpp
Normal file
37
src/lib/price_notify/sources/kraken_source.hpp
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../interfaces/price_source.hpp"
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <esp_timer.h>
|
||||||
|
|
||||||
|
namespace PriceNotify {
|
||||||
|
|
||||||
|
using std::map;
|
||||||
|
|
||||||
|
class KrakenSource : public IPriceSource {
|
||||||
|
public:
|
||||||
|
KrakenSource();
|
||||||
|
~KrakenSource() override;
|
||||||
|
|
||||||
|
void connect() override;
|
||||||
|
void disconnect() override;
|
||||||
|
bool isConnected() const override;
|
||||||
|
uint64_t getPrice(Currency currency) const override;
|
||||||
|
uint32_t getLastUpdate(Currency currency) const override;
|
||||||
|
void onPriceUpdate(function<void(Currency, uint64_t)> callback) override;
|
||||||
|
void loop() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void onWebSocketEvent(WStype_t type, uint8_t* payload, size_t length);
|
||||||
|
void handleWebSocketEvent(WStype_t type, uint8_t* payload, size_t length);
|
||||||
|
void processMessage(const char* payload);
|
||||||
|
void subscribe();
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
map<Currency, uint64_t> prices;
|
||||||
|
map<Currency, uint32_t> lastUpdates;
|
||||||
|
bool connected;
|
||||||
|
|
||||||
|
static KrakenSource* instance; // For callback handling
|
||||||
|
};
|
||||||
|
} // namespace PriceNotify
|
|
@ -241,7 +241,7 @@ void workerTask(void *pvParameters) {
|
||||||
|
|
||||||
case TASK_PRICE_UPDATE: {
|
case TASK_PRICE_UPDATE: {
|
||||||
uint currency = ScreenHandler::getCurrentCurrency();
|
uint currency = ScreenHandler::getCurrentCurrency();
|
||||||
uint price = getPrice(currency);
|
uint price = priceManager.getPrice(static_cast<PriceNotify::Currency>(currency));
|
||||||
|
|
||||||
if (currentScreenValue == SCREEN_BTC_TICKER) {
|
if (currentScreenValue == SCREEN_BTC_TICKER) {
|
||||||
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE),
|
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE),
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "v2_notify.hpp"
|
#include "v2_notify.hpp"
|
||||||
|
#include "globals.hpp"
|
||||||
|
|
||||||
using namespace V2Notify;
|
using namespace V2Notify;
|
||||||
|
|
||||||
|
@ -146,14 +147,15 @@ namespace V2Notify
|
||||||
}
|
}
|
||||||
else if (doc["price"].is<JsonObject>())
|
else if (doc["price"].is<JsonObject>())
|
||||||
{
|
{
|
||||||
|
|
||||||
// Iterate through the key-value pairs of the "price" object
|
// Iterate through the key-value pairs of the "price" object
|
||||||
for (JsonPair kv : doc["price"].as<JsonObject>())
|
for (JsonPair kv : doc["price"].as<JsonObject>())
|
||||||
{
|
{
|
||||||
const char *currency = kv.key().c_str();
|
const char *currency = kv.key().c_str();
|
||||||
uint newPrice = kv.value().as<uint>();
|
uint newPrice = kv.value().as<uint>();
|
||||||
|
|
||||||
processNewPrice(newPrice, getCurrencyChar(currency));
|
// Convert currency string to PriceNotify::Currency using data_handler's conversion
|
||||||
|
char currencyChar = getCurrencyChar(currency);
|
||||||
|
priceManager.processNewPrice(newPrice, static_cast<PriceNotify::Currency>(currencyChar));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ JsonDocument getStatusObject()
|
||||||
|
|
||||||
JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
|
JsonObject conStatus = root["connectionStatus"].to<JsonObject>();
|
||||||
|
|
||||||
conStatus["price"] = isPriceNotifyConnected();
|
conStatus["price"] = priceManager.isConnected();
|
||||||
conStatus["blocks"] = isBlockNotifyConnected();
|
conStatus["blocks"] = isBlockNotifyConnected();
|
||||||
conStatus["V2"] = V2Notify::isV2NotifyConnected();
|
conStatus["V2"] = V2Notify::isV2NotifyConnected();
|
||||||
conStatus["nostr"] = nostrConnected();
|
conStatus["nostr"] = nostrConnected();
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
#include "lib/block_notify.hpp"
|
#include "lib/block_notify.hpp"
|
||||||
#include "lib/led_handler.hpp"
|
#include "lib/led_handler.hpp"
|
||||||
#include "lib/price_notify.hpp"
|
|
||||||
#include "lib/screen_handler.hpp"
|
#include "lib/screen_handler.hpp"
|
||||||
#include "webserver/OneParamRewrite.hpp"
|
#include "webserver/OneParamRewrite.hpp"
|
||||||
#include "lib/mining_pool/pool_factory.hpp"
|
#include "lib/mining_pool/pool_factory.hpp"
|
||||||
|
|
Loading…
Add table
Reference in a new issue