175 lines
No EOL
4.5 KiB
C++
175 lines
No EOL
4.5 KiB
C++
#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);
|
|
} |