Implement multi-currency support with MsgPack
This commit is contained in:
parent
a4ff5a2f75
commit
c276d32807
18 changed files with 528 additions and 541 deletions
2
data
2
data
|
@ -1 +1 @@
|
||||||
Subproject commit 34b09a2d1134d48d7733a3d11a9e6f3f15d080a9
|
Subproject commit 2fffb3ef0284b4262ca97a81eb979259186604e5
|
|
@ -32,25 +32,41 @@ std::string getCurrencyCode(char input)
|
||||||
switch (input)
|
switch (input)
|
||||||
{
|
{
|
||||||
case CURRENCY_EUR:
|
case CURRENCY_EUR:
|
||||||
return "EUR";
|
return CURRENCY_CODE_EUR;
|
||||||
break;
|
break;
|
||||||
case CURRENCY_GBP:
|
case CURRENCY_GBP:
|
||||||
return "GBP";
|
return CURRENCY_CODE_GBP;
|
||||||
break;
|
break;
|
||||||
case CURRENCY_JPY:
|
case CURRENCY_JPY:
|
||||||
return "YEN";
|
return CURRENCY_CODE_JPY;
|
||||||
break;
|
break;
|
||||||
case CURRENCY_AUD:
|
case CURRENCY_AUD:
|
||||||
return "AUD";
|
return CURRENCY_CODE_AUD;
|
||||||
break;
|
break;
|
||||||
case CURRENCY_CAD:
|
case CURRENCY_CAD:
|
||||||
return "CAD";
|
return CURRENCY_CODE_CAD;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return "USD";
|
return CURRENCY_CODE_USD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char getCurrencyChar(const std::string& input)
|
||||||
|
{
|
||||||
|
if (input == "EUR")
|
||||||
|
return CURRENCY_EUR;
|
||||||
|
else if (input == "GBP")
|
||||||
|
return CURRENCY_GBP;
|
||||||
|
else if (input == "JPY")
|
||||||
|
return CURRENCY_JPY;
|
||||||
|
else if (input == "AUD")
|
||||||
|
return CURRENCY_AUD;
|
||||||
|
else if (input == "CAD")
|
||||||
|
return CURRENCY_CAD;
|
||||||
|
else
|
||||||
|
return CURRENCY_USD; // Assuming USD is the default for unknown inputs
|
||||||
|
}
|
||||||
|
|
||||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat)
|
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currencySymbol, bool useSuffixFormat)
|
||||||
{
|
{
|
||||||
std::array<std::string, NUM_SCREENS> ret;
|
std::array<std::string, NUM_SCREENS> ret;
|
||||||
|
@ -205,14 +221,8 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
|
||||||
std::uint32_t firstIndex = 0;
|
std::uint32_t firstIndex = 0;
|
||||||
double supply = getSupplyAtBlock(blockHeight);
|
double supply = getSupplyAtBlock(blockHeight);
|
||||||
int64_t marketCap = static_cast<std::int64_t>(supply * double(price));
|
int64_t marketCap = static_cast<std::int64_t>(supply * double(price));
|
||||||
if (currencySymbol == '[')
|
|
||||||
{
|
ret[0] = getCurrencyCode(currencySymbol) + "/MCAP";
|
||||||
ret[0] = "EUR/MCAP";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret[0] = "USD/MCAP";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bigChars)
|
if (bigChars)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,6 +12,13 @@ const char CURRENCY_JPY = '^';
|
||||||
const char CURRENCY_AUD = '_';
|
const char CURRENCY_AUD = '_';
|
||||||
const char CURRENCY_CAD = '`';
|
const char CURRENCY_CAD = '`';
|
||||||
|
|
||||||
|
const std::string CURRENCY_CODE_USD = "USD";
|
||||||
|
const std::string CURRENCY_CODE_EUR = "EUR";
|
||||||
|
const std::string CURRENCY_CODE_GBP = "GBP";
|
||||||
|
const std::string CURRENCY_CODE_JPY = "JPY";
|
||||||
|
const std::string CURRENCY_CODE_AUD = "AUD";
|
||||||
|
const std::string CURRENCY_CODE_CAD = "CAD";
|
||||||
|
|
||||||
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false);
|
std::array<std::string, NUM_SCREENS> parsePriceData(std::uint32_t price, char currency, bool useSuffixFormat = false);
|
||||||
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol);
|
std::array<std::string, NUM_SCREENS> parseSatsPerCurrency(std::uint32_t price, char currencySymbol, bool withSatsSymbol);
|
||||||
std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight);
|
std::array<std::string, NUM_SCREENS> parseBlockHeight(std::uint32_t blockHeight);
|
||||||
|
@ -20,4 +27,5 @@ std::array<std::string, NUM_SCREENS> parseMarketCap(std::uint32_t blockHeight, s
|
||||||
std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees);
|
std::array<std::string, NUM_SCREENS> parseBlockFees(std::uint16_t blockFees);
|
||||||
|
|
||||||
char getCurrencySymbol(char input);
|
char getCurrencySymbol(char input);
|
||||||
std::string getCurrencyCode(char input);
|
std::string getCurrencyCode(char input);
|
||||||
|
char getCurrencyChar(const std::string& input);
|
|
@ -66,7 +66,6 @@ void setup()
|
||||||
|
|
||||||
setupWebserver();
|
setupWebserver();
|
||||||
|
|
||||||
// setupWifi();
|
|
||||||
syncTime();
|
syncTime();
|
||||||
finishSetup();
|
finishSetup();
|
||||||
|
|
||||||
|
@ -268,24 +267,43 @@ void setupPreferences()
|
||||||
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||||
setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
setBgColor(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));
|
setPrice(preferences.getUInt("lastPrice", INITIAL_LAST_PRICE), CURRENCY_USD);
|
||||||
|
|
||||||
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE))
|
||||||
|
setCurrentCurrency(preferences.getUChar("lastCurrency", CURRENCY_USD));
|
||||||
|
else
|
||||||
|
setCurrentCurrency(CURRENCY_USD);
|
||||||
|
|
||||||
|
|
||||||
addScreenMapping(SCREEN_BLOCK_HEIGHT, "Block Height");
|
addScreenMapping(SCREEN_BLOCK_HEIGHT, "Block Height");
|
||||||
addScreenMapping(SCREEN_MSCW_TIME, "Sats per dollar");
|
|
||||||
addScreenMapping(SCREEN_BTC_TICKER, "Ticker");
|
|
||||||
addScreenMapping(SCREEN_TIME, "Time");
|
addScreenMapping(SCREEN_TIME, "Time");
|
||||||
addScreenMapping(SCREEN_HALVING_COUNTDOWN, "Halving countdown");
|
addScreenMapping(SCREEN_HALVING_COUNTDOWN, "Halving countdown");
|
||||||
addScreenMapping(SCREEN_MARKET_CAP, "Market Cap");
|
|
||||||
addScreenMapping(SCREEN_BLOCK_FEE_RATE, "Block Fee Rate");
|
addScreenMapping(SCREEN_BLOCK_FEE_RATE, "Block Fee Rate");
|
||||||
|
|
||||||
|
addScreenMapping(SCREEN_SATS_PER_CURRENCY, "Sats per dollar");
|
||||||
|
addScreenMapping(SCREEN_BTC_TICKER, "Ticker");
|
||||||
|
addScreenMapping(SCREEN_MARKET_CAP, "Market Cap");
|
||||||
|
|
||||||
|
|
||||||
|
// addScreenMapping(SCREEN_SATS_PER_CURRENCY_USD, "Sats per USD");
|
||||||
|
// addScreenMapping(SCREEN_BTC_TICKER_USD, "Ticker USD");
|
||||||
|
// addScreenMapping(SCREEN_MARKET_CAP_USD, "Market Cap USD");
|
||||||
|
|
||||||
|
// addScreenMapping(SCREEN_SATS_PER_CURRENCY_EUR, "Sats per EUR");
|
||||||
|
// addScreenMapping(SCREEN_BTC_TICKER_EUR, "Ticker EUR");
|
||||||
|
// addScreenMapping(SCREEN_MARKET_CAP_EUR, "Market Cap EUR");
|
||||||
|
|
||||||
// screenNameMap[SCREEN_BLOCK_HEIGHT] = "Block Height";
|
// screenNameMap[SCREEN_BLOCK_HEIGHT] = "Block Height";
|
||||||
// screenNameMap[SCREEN_BLOCK_FEE_RATE] = "Block Fee Rate";
|
// screenNameMap[SCREEN_BLOCK_FEE_RATE] = "Block Fee Rate";
|
||||||
// screenNameMap[SCREEN_MSCW_TIME] = "Sats per dollar";
|
// screenNameMap[SCREEN_SATS_PER_CURRENCY] = "Sats per dollar";
|
||||||
// screenNameMap[SCREEN_BTC_TICKER] = "Ticker";
|
// screenNameMap[SCREEN_BTC_TICKER] = "Ticker";
|
||||||
// screenNameMap[SCREEN_TIME] = "Time";
|
// screenNameMap[SCREEN_TIME] = "Time";
|
||||||
// screenNameMap[SCREEN_HALVING_COUNTDOWN] = "Halving countdown";
|
// screenNameMap[SCREEN_HALVING_COUNTDOWN] = "Halving countdown";
|
||||||
// screenNameMap[SCREEN_MARKET_CAP] = "Market Cap";
|
// screenNameMap[SCREEN_MARKET_CAP] = "Market Cap";
|
||||||
|
|
||||||
|
//addCurrencyMappings(getActiveCurrencies());
|
||||||
|
|
||||||
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED))
|
if (preferences.getBool("bitaxeEnabled", DEFAULT_BITAXE_ENABLED))
|
||||||
{
|
{
|
||||||
addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate");
|
addScreenMapping(SCREEN_BITAXE_HASHRATE, "BitAxe Hashrate");
|
||||||
|
@ -293,16 +311,74 @@ void setupPreferences()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void addCurrencyMappings(const std::vector<std::string>& currencies)
|
||||||
|
// {
|
||||||
|
// for (const auto& currency : currencies)
|
||||||
|
// {
|
||||||
|
// int satsPerCurrencyScreen;
|
||||||
|
// int btcTickerScreen;
|
||||||
|
// int marketCapScreen;
|
||||||
|
|
||||||
|
// // Determine the corresponding screen IDs based on the currency code
|
||||||
|
// if (currency == "USD")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_USD;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_USD;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_USD;
|
||||||
|
// }
|
||||||
|
// else if (currency == "EUR")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_EUR;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_EUR;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_EUR;
|
||||||
|
// }
|
||||||
|
// else if (currency == "GBP")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_GBP;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_GBP;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_GBP;
|
||||||
|
// }
|
||||||
|
// else if (currency == "JPY")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_JPY;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_JPY;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_JPY;
|
||||||
|
// }
|
||||||
|
// else if (currency == "AUD")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_AUD;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_AUD;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_AUD;
|
||||||
|
// }
|
||||||
|
// else if (currency == "CAD")
|
||||||
|
// {
|
||||||
|
// satsPerCurrencyScreen = SCREEN_SATS_PER_CURRENCY_CAD;
|
||||||
|
// btcTickerScreen = SCREEN_BTC_TICKER_CAD;
|
||||||
|
// marketCapScreen = SCREEN_MARKET_CAP_CAD;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// continue; // Unknown currency, skip it
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // Create the string locally to ensure it persists
|
||||||
|
// std::string satsPerCurrencyString = "Sats per " + currency;
|
||||||
|
// std::string btcTickerString = "Ticker " + currency;
|
||||||
|
// std::string marketCapString = "Market Cap " + currency;
|
||||||
|
|
||||||
|
// // Pass the c_str() to the function
|
||||||
|
// addScreenMapping(satsPerCurrencyScreen, satsPerCurrencyString.c_str());
|
||||||
|
// addScreenMapping(btcTickerScreen, btcTickerString.c_str());
|
||||||
|
// addScreenMapping(marketCapScreen, marketCapString.c_str());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
void setupWebsocketClients(void *pvParameters)
|
void setupWebsocketClients(void *pvParameters)
|
||||||
{
|
{
|
||||||
setupBlockNotify();
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE)) {
|
||||||
|
setupV2Notify();
|
||||||
if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE))
|
} else {
|
||||||
{
|
setupBlockNotify();
|
||||||
setupPriceFetchTask();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setupPriceNotify();
|
setupPriceNotify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,218 +529,6 @@ void setupHardware()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef IMPROV_ENABLED
|
|
||||||
void improvGetAvailableWifiNetworks()
|
|
||||||
{
|
|
||||||
int networkNum = WiFi.scanNetworks();
|
|
||||||
|
|
||||||
for (int id = 0; id < networkNum; ++id)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
|
||||||
improv::GET_WIFI_NETWORKS,
|
|
||||||
{WiFi.SSID(id), String(WiFi.RSSI(id)),
|
|
||||||
(WiFi.encryptionType(id) == WIFI_AUTH_OPEN ? "NO" : "YES")},
|
|
||||||
false);
|
|
||||||
improv_send_response(data);
|
|
||||||
}
|
|
||||||
// final response
|
|
||||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
|
||||||
improv::GET_WIFI_NETWORKS, std::vector<std::string>{}, false);
|
|
||||||
improv_send_response(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool improv_connectWifi(std::string ssid, std::string password)
|
|
||||||
{
|
|
||||||
uint8_t count = 0;
|
|
||||||
|
|
||||||
WiFi.begin(ssid.c_str(), password.c_str());
|
|
||||||
|
|
||||||
while (WiFi.status() != WL_CONNECTED)
|
|
||||||
{
|
|
||||||
blinkDelay(500, 2);
|
|
||||||
|
|
||||||
if (count > MAX_ATTEMPTS_WIFI_CONNECTION)
|
|
||||||
{
|
|
||||||
WiFi.disconnect();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onImprovErrorCallback(improv::Error err)
|
|
||||||
{
|
|
||||||
blinkDelayColor(100, 1, 255, 0, 0);
|
|
||||||
// pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
|
||||||
// pixels.setPixelColor(1, pixels.Color(255, 0, 0));
|
|
||||||
// pixels.setPixelColor(2, pixels.Color(255, 0, 0));
|
|
||||||
// pixels.setPixelColor(3, pixels.Color(255, 0, 0));
|
|
||||||
// pixels.show();
|
|
||||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
|
|
||||||
// pixels.clear();
|
|
||||||
// pixels.show();
|
|
||||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> getLocalUrl()
|
|
||||||
{
|
|
||||||
return {// URL where user can finish onboarding or use device
|
|
||||||
// Recommended to use website hosted by device
|
|
||||||
String("http://" + WiFi.localIP().toString()).c_str()};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
|
||||||
{
|
|
||||||
switch (cmd.command)
|
|
||||||
{
|
|
||||||
case improv::Command::GET_CURRENT_STATE:
|
|
||||||
{
|
|
||||||
if ((WiFi.status() == WL_CONNECTED))
|
|
||||||
{
|
|
||||||
improv_set_state(improv::State::STATE_PROVISIONED);
|
|
||||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
|
||||||
improv::GET_CURRENT_STATE, getLocalUrl(), false);
|
|
||||||
improv_send_response(data);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
improv_set_state(improv::State::STATE_AUTHORIZED);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case improv::Command::WIFI_SETTINGS:
|
|
||||||
{
|
|
||||||
if (cmd.ssid.length() == 0)
|
|
||||||
{
|
|
||||||
improv_set_error(improv::Error::ERROR_INVALID_RPC);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
improv_set_state(improv::STATE_PROVISIONING);
|
|
||||||
queueLedEffect(LED_EFFECT_WIFI_CONNECTING);
|
|
||||||
|
|
||||||
if (improv_connectWifi(cmd.ssid, cmd.password))
|
|
||||||
{
|
|
||||||
queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
|
|
||||||
|
|
||||||
// std::array<String, NUM_SCREENS> epdContent = {"S", "U", "C", "C",
|
|
||||||
// "E", "S", "S"}; setEpdContent(epdContent);
|
|
||||||
|
|
||||||
preferences.putBool("wifiConfigured", true);
|
|
||||||
|
|
||||||
improv_set_state(improv::STATE_PROVISIONED);
|
|
||||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
|
||||||
improv::WIFI_SETTINGS, getLocalUrl(), false);
|
|
||||||
improv_send_response(data);
|
|
||||||
|
|
||||||
delay(2500);
|
|
||||||
ESP.restart();
|
|
||||||
setupWebserver();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
|
|
||||||
|
|
||||||
improv_set_state(improv::STATE_STOPPED);
|
|
||||||
improv_set_error(improv::Error::ERROR_UNABLE_TO_CONNECT);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case improv::Command::GET_DEVICE_INFO:
|
|
||||||
{
|
|
||||||
std::vector<std::string> infos = {// Firmware name
|
|
||||||
"BTClock",
|
|
||||||
// Firmware version
|
|
||||||
"1.0.0",
|
|
||||||
// Hardware chip/variant
|
|
||||||
"ESP32S3",
|
|
||||||
// Device name
|
|
||||||
"BTClock"};
|
|
||||||
std::vector<uint8_t> data =
|
|
||||||
improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false);
|
|
||||||
improv_send_response(data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case improv::Command::GET_WIFI_NETWORKS:
|
|
||||||
{
|
|
||||||
improvGetAvailableWifiNetworks();
|
|
||||||
// std::array<String, NUM_SCREENS> epdContent = {"W", "E", "B", "W", "I",
|
|
||||||
// "F", "I"}; setEpdContent(epdContent);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
improv_set_error(improv::ERROR_UNKNOWN_RPC);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void improv_set_state(improv::State state)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
|
|
||||||
data.resize(11);
|
|
||||||
data[6] = improv::IMPROV_SERIAL_VERSION;
|
|
||||||
data[7] = improv::TYPE_CURRENT_STATE;
|
|
||||||
data[8] = 1;
|
|
||||||
data[9] = state;
|
|
||||||
|
|
||||||
uint8_t checksum = 0x00;
|
|
||||||
for (uint8_t d : data)
|
|
||||||
checksum += d;
|
|
||||||
data[10] = checksum;
|
|
||||||
|
|
||||||
Serial.write(data.data(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void improv_send_response(std::vector<uint8_t> &response)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
|
|
||||||
data.resize(9);
|
|
||||||
data[6] = improv::IMPROV_SERIAL_VERSION;
|
|
||||||
data[7] = improv::TYPE_RPC_RESPONSE;
|
|
||||||
data[8] = response.size();
|
|
||||||
data.insert(data.end(), response.begin(), response.end());
|
|
||||||
|
|
||||||
uint8_t checksum = 0x00;
|
|
||||||
for (uint8_t d : data)
|
|
||||||
checksum += d;
|
|
||||||
data.push_back(checksum);
|
|
||||||
|
|
||||||
Serial.write(data.data(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void improv_set_error(improv::Error error)
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> data = {'I', 'M', 'P', 'R', 'O', 'V'};
|
|
||||||
data.resize(11);
|
|
||||||
data[6] = improv::IMPROV_SERIAL_VERSION;
|
|
||||||
data[7] = improv::TYPE_ERROR_STATE;
|
|
||||||
data[8] = 1;
|
|
||||||
data[9] = error;
|
|
||||||
|
|
||||||
uint8_t checksum = 0x00;
|
|
||||||
for (uint8_t d : data)
|
|
||||||
checksum += d;
|
|
||||||
data[10] = checksum;
|
|
||||||
|
|
||||||
Serial.write(data.data(), data.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||||
{
|
{
|
||||||
static bool first_connect = true;
|
static bool first_connect = true;
|
||||||
|
@ -842,3 +706,37 @@ int findScreenIndexByValue(int value)
|
||||||
}
|
}
|
||||||
return -1; // Return -1 if value is not found
|
return -1; // Return -1 if value is not found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> getAvailableCurrencies()
|
||||||
|
{
|
||||||
|
return {CURRENCY_CODE_USD, CURRENCY_CODE_EUR, CURRENCY_CODE_GBP, CURRENCY_CODE_JPY, CURRENCY_CODE_AUD, CURRENCY_CODE_CAD};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> getActiveCurrencies()
|
||||||
|
{
|
||||||
|
std::vector<std::string> result;
|
||||||
|
|
||||||
|
// Convert Arduino String to std::string
|
||||||
|
std::string stdString = preferences.getString("actCurrencies", DEFAULT_ACTIVE_CURRENCIES).c_str();
|
||||||
|
|
||||||
|
// Use a stringstream to split the string
|
||||||
|
std::stringstream ss(stdString);
|
||||||
|
std::string item;
|
||||||
|
|
||||||
|
// Split the string by comma and add each part to the vector
|
||||||
|
while (std::getline(ss, item, ','))
|
||||||
|
{
|
||||||
|
result.push_back(item);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isActiveCurrency(std::string ¤cy)
|
||||||
|
{
|
||||||
|
std::vector<std::string> ac = getActiveCurrencies();
|
||||||
|
if (std::find(ac.begin(), ac.end(), currency) != ac.end())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -19,6 +19,8 @@
|
||||||
#include "lib/nostr_notify.hpp"
|
#include "lib/nostr_notify.hpp"
|
||||||
#include "lib/bitaxe_fetch.hpp"
|
#include "lib/bitaxe_fetch.hpp"
|
||||||
|
|
||||||
|
#include "lib/v2_notify.hpp"
|
||||||
|
|
||||||
#include "lib/price_notify.hpp"
|
#include "lib/price_notify.hpp"
|
||||||
#include "lib/screen_handler.hpp"
|
#include "lib/screen_handler.hpp"
|
||||||
#include "lib/shared.hpp"
|
#include "lib/shared.hpp"
|
||||||
|
@ -64,6 +66,11 @@ std::vector<std::string> getLocalUrl();
|
||||||
// void improv_set_state(improv::State state);
|
// void improv_set_state(improv::State state);
|
||||||
// void improv_send_response(std::vector<uint8_t> &response);
|
// void improv_send_response(std::vector<uint8_t> &response);
|
||||||
// void improv_set_error(improv::Error error);
|
// 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);
|
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info);
|
||||||
String getHwRev();
|
String getHwRev();
|
||||||
|
@ -71,4 +78,7 @@ bool isWhiteVersion();
|
||||||
String getFsRev();
|
String getFsRev();
|
||||||
|
|
||||||
void addScreenMapping(int value, const char* name);
|
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);
|
int findScreenIndexByValue(int value);
|
|
@ -58,4 +58,6 @@
|
||||||
|
|
||||||
#define DEFAULT_HTTP_AUTH_ENABLED false
|
#define DEFAULT_HTTP_AUTH_ENABLED false
|
||||||
#define DEFAULT_HTTP_AUTH_USERNAME "btclock"
|
#define DEFAULT_HTTP_AUTH_USERNAME "btclock"
|
||||||
#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi"
|
#define DEFAULT_HTTP_AUTH_PASSWORD "satoshi"
|
||||||
|
|
||||||
|
#define DEFAULT_ACTIVE_CURRENCIES "USD,EUR,JPY"
|
|
@ -168,7 +168,7 @@ void handleNostrEventCallback(const String &subId, nostr::SignedNostrEvent *even
|
||||||
{
|
{
|
||||||
if (typeValue.equals("priceUsd"))
|
if (typeValue.equals("priceUsd"))
|
||||||
{
|
{
|
||||||
processNewPrice(obj["content"].as<uint>());
|
processNewPrice(obj["content"].as<uint>(), CURRENCY_USD);
|
||||||
}
|
}
|
||||||
else if (typeValue.equals("blockHeight"))
|
else if (typeValue.equals("blockHeight"))
|
||||||
{
|
{
|
||||||
|
|
|
@ -29,9 +29,9 @@ void taskPriceFetch(void *pvParameters) {
|
||||||
// usdPrice = doc["bitcoin"]["usd"];
|
// usdPrice = doc["bitcoin"]["usd"];
|
||||||
eurPrice = doc["bitcoin"]["eur"].as<uint>();
|
eurPrice = doc["bitcoin"]["eur"].as<uint>();
|
||||||
|
|
||||||
setPrice(eurPrice);
|
setPrice(eurPrice, CURRENCY_EUR);
|
||||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
|
|
@ -5,36 +5,6 @@ const char *wsOwnServerV2 = "wss://ws-staging.btclock.dev/api/v2/ws";
|
||||||
|
|
||||||
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
const char *wsServerPrice = "wss://ws.coincap.io/prices?assets=bitcoin";
|
||||||
|
|
||||||
// const char* coinCapWsCert = R"(-----BEGIN CERTIFICATE-----
|
|
||||||
// MIIFMjCCBNmgAwIBAgIQBtgXvFyc28MsvQ1HjCnXJTAKBggqhkjOPQQDAjBKMQsw
|
|
||||||
// CQYDVQQGEwJVUzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEgMB4GA1UEAxMX
|
|
||||||
// Q2xvdWRmbGFyZSBJbmMgRUNDIENBLTMwHhcNMjMwNTEwMDAwMDAwWhcNMjQwNTA5
|
|
||||||
// MjM1OTU5WjB1MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQG
|
|
||||||
// A1UEBxMNU2FuIEZyYW5jaXNjbzEZMBcGA1UEChMQQ2xvdWRmbGFyZSwgSW5jLjEe
|
|
||||||
// MBwGA1UEAxMVc25pLmNsb3VkZmxhcmVzc2wuY29tMFkwEwYHKoZIzj0CAQYIKoZI
|
|
||||||
// zj0DAQcDQgAEpvFIXzQKHuqTo+IE6c6sB4p0PMXK1KsseEGf2UN/CNRhG5hO7lr8
|
|
||||||
// JtXrPZkawWBysZxOsEoetkPrDHMugCLfXKOCA3QwggNwMB8GA1UdIwQYMBaAFKXO
|
|
||||||
// N+rrsHUOlGeItEX62SQQh5YfMB0GA1UdDgQWBBShsZDJohaR1a5E0Qj7yblZjKDC
|
|
||||||
// gDA6BgNVHREEMzAxggwqLmNvaW5jYXAuaW+CCmNvaW5jYXAuaW+CFXNuaS5jbG91
|
|
||||||
// ZGZsYXJlc3NsLmNvbTAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0lBBYwFAYIKwYBBQUH
|
|
||||||
// AwEGCCsGAQUFBwMCMHsGA1UdHwR0MHIwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2lj
|
|
||||||
// ZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwN6A1oDOGMWh0dHA6Ly9j
|
|
||||||
// cmw0LmRpZ2ljZXJ0LmNvbS9DbG91ZGZsYXJlSW5jRUNDQ0EtMy5jcmwwPgYDVR0g
|
|
||||||
// BDcwNTAzBgZngQwBAgIwKTAnBggrBgEFBQcCARYbaHR0cDovL3d3dy5kaWdpY2Vy
|
|
||||||
// dC5jb20vQ1BTMHYGCCsGAQUFBwEBBGowaDAkBggrBgEFBQcwAYYYaHR0cDovL29j
|
|
||||||
// c3AuZGlnaWNlcnQuY29tMEAGCCsGAQUFBzAChjRodHRwOi8vY2FjZXJ0cy5kaWdp
|
|
||||||
// Y2VydC5jb20vQ2xvdWRmbGFyZUluY0VDQ0NBLTMuY3J0MAwGA1UdEwEB/wQCMAAw
|
|
||||||
// ggF+BgorBgEEAdZ5AgQCBIIBbgSCAWoBaAB1AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8
|
|
||||||
// vOzew1FIWUZxH7WbAAABiAPnoRAAAAQDAEYwRAIgAP2W09OozuhmKeKKMsaVBcae
|
|
||||||
// o+nPHF1WUWk0i387YYYCIDIM1Wll7/4O3GNx2/Fx9bC6pi69Uya4pLxsCfW3fZMe
|
|
||||||
// AHYASLDja9qmRzQP5WoC+p0w6xxSActW3SyB2bu/qznYhHMAAAGIA+eg+QAABAMA
|
|
||||||
// RzBFAiEAuNpSqrbx47gYBgBMz5M6q0CnV/WMJqWQOxYFKrwfwVACIH3nCs4bKToT
|
|
||||||
// e+MiBrqSDaekixk4kPFEQESO9qHCkWY5AHcA2ra/az+1tiKfm8K7XGvocJFxbLtR
|
|
||||||
// hIU0vaQ9MEjX+6sAAAGIA+eg1gAABAMASDBGAiEAolCFl2IfbOHUPAOxoi4BLclS
|
|
||||||
// v9FVXb7LwIvTuCfyrEQCIQDcvehwhV9XGopKGl17F2LYYKI7hvlO3RmpPZQJt1da
|
|
||||||
// MDAKBggqhkjOPQQDAgNHADBEAiAXRWZ/JVMsfpSFFTHQHUSqRnQ/7cCOWx+9svIy
|
|
||||||
// mYnFZQIgHMEG0Cm7O4cn5KUzKOsTwwK+2U15s/jPUQi2n2IDTEM=
|
|
||||||
// -----END CERTIFICATE-----)";
|
|
||||||
|
|
||||||
// WebsocketsClient client;
|
// WebsocketsClient client;
|
||||||
esp_websocket_client_handle_t clientPrice = NULL;
|
esp_websocket_client_handle_t clientPrice = NULL;
|
||||||
|
@ -42,6 +12,8 @@ esp_websocket_client_config_t config;
|
||||||
uint currentPrice = 50000;
|
uint currentPrice = 50000;
|
||||||
unsigned long int lastPriceUpdate;
|
unsigned long int lastPriceUpdate;
|
||||||
bool priceNotifyInit = false;
|
bool priceNotifyInit = false;
|
||||||
|
std::map<char, std::uint64_t> currencyMap;
|
||||||
|
std::map<char, unsigned long int> lastUpdateMap;
|
||||||
|
|
||||||
void setupPriceNotify()
|
void setupPriceNotify()
|
||||||
{
|
{
|
||||||
|
@ -100,48 +72,59 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data)
|
||||||
{
|
{
|
||||||
if (currentPrice != doc["bitcoin"].as<long>())
|
if (currentPrice != doc["bitcoin"].as<long>())
|
||||||
{
|
{
|
||||||
processNewPrice(doc["bitcoin"].as<long>());
|
processNewPrice(doc["bitcoin"].as<long>(), CURRENCY_USD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void processNewPrice(uint newPrice)
|
void processNewPrice(uint newPrice, char currency)
|
||||||
{
|
{
|
||||||
uint minSecPriceUpd = preferences.getUInt(
|
uint minSecPriceUpd = preferences.getUInt(
|
||||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||||
uint currentTime = esp_timer_get_time() / 1000000;
|
uint currentTime = esp_timer_get_time() / 1000000;
|
||||||
|
|
||||||
if (lastPriceUpdate == 0 ||
|
if (lastUpdateMap.find(currency) == lastUpdateMap.end()||
|
||||||
(currentTime - lastPriceUpdate) > minSecPriceUpd)
|
(currentTime - lastUpdateMap[currency]) > minSecPriceUpd)
|
||||||
{
|
{
|
||||||
// const unsigned long oldPrice = currentPrice;
|
// const unsigned long oldPrice = currentPrice;
|
||||||
currentPrice = newPrice;
|
currencyMap[currency] = newPrice;
|
||||||
if (lastPriceUpdate == 0 ||
|
// if (lastUpdateMap[currency] == 0 ||
|
||||||
(currentTime - lastPriceUpdate) > 120)
|
// (currentTime - lastUpdateMap[currency]) > 120)
|
||||||
{
|
// {
|
||||||
preferences.putUInt("lastPrice", currentPrice);
|
// preferences.putUInt("lastPrice", currentPrice);
|
||||||
}
|
// }
|
||||||
lastPriceUpdate = currentTime;
|
lastUpdateMap[currency] = currentTime;
|
||||||
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
||||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
getCurrentScreen() == SCREEN_SATS_PER_CURRENCY ||
|
||||||
getCurrentScreen() == SCREEN_MARKET_CAP))
|
getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||||
{
|
{
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, currency};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint getLastPriceUpdate()
|
uint getLastPriceUpdate(char currency)
|
||||||
{
|
{
|
||||||
return lastPriceUpdate;
|
if (lastUpdateMap.find(currency) == lastUpdateMap.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lastUpdateMap[currency];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint getPrice() { return currentPrice; }
|
uint getPrice(char currency) {
|
||||||
|
if (currencyMap.find(currency) == currencyMap.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return currencyMap[currency];
|
||||||
|
}
|
||||||
|
|
||||||
void setPrice(uint newPrice) { currentPrice = newPrice; }
|
void setPrice(uint newPrice, char currency) {
|
||||||
|
currencyMap[currency] = newPrice;
|
||||||
|
}
|
||||||
|
|
||||||
bool isPriceNotifyConnected()
|
bool isPriceNotifyConnected()
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,14 +14,15 @@ void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base,
|
||||||
int32_t event_id, void *event_data);
|
int32_t event_id, void *event_data);
|
||||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data);
|
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data);
|
||||||
|
|
||||||
uint getPrice();
|
uint getPrice(char currency);
|
||||||
void setPrice(uint newPrice);
|
void setPrice(uint newPrice, char currency);
|
||||||
|
|
||||||
void processNewPrice(uint newPrice);
|
//void processNewPrice(uint newPrice);
|
||||||
|
void processNewPrice(uint newPrice, char currency);
|
||||||
|
|
||||||
bool isPriceNotifyConnected();
|
bool isPriceNotifyConnected();
|
||||||
void stopPriceNotify();
|
void stopPriceNotify();
|
||||||
void restartPriceNotify();
|
void restartPriceNotify();
|
||||||
|
|
||||||
bool getPriceNotifyInit();
|
bool getPriceNotifyInit();
|
||||||
uint getLastPriceUpdate();
|
uint getLastPriceUpdate(char currency);
|
|
@ -16,6 +16,7 @@ std::string priceString;
|
||||||
QueueHandle_t workQueue = NULL;
|
QueueHandle_t workQueue = NULL;
|
||||||
|
|
||||||
uint currentScreen;
|
uint currentScreen;
|
||||||
|
uint currentCurrency = CURRENCY_USD;
|
||||||
|
|
||||||
void workerTask(void *pvParameters) {
|
void workerTask(void *pvParameters) {
|
||||||
WorkItem receivedItem;
|
WorkItem receivedItem;
|
||||||
|
@ -40,18 +41,19 @@ void workerTask(void *pvParameters) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TASK_PRICE_UPDATE: {
|
case TASK_PRICE_UPDATE: {
|
||||||
uint price = getPrice();
|
uint currency = getCurrentCurrency();
|
||||||
u_char priceSymbol = '$';
|
uint price = getPrice(currency);
|
||||||
if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) {
|
// u_char priceSymbol = '$';
|
||||||
priceSymbol = '[';
|
// if (preferences.getBool("fetchEurPrice", DEFAULT_FETCH_EUR_PRICE)) {
|
||||||
}
|
// priceSymbol = '[';
|
||||||
|
// }
|
||||||
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
|
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
|
||||||
taskEpdContent = parsePriceData(price, priceSymbol, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE));
|
taskEpdContent = parsePriceData(price, currency, preferences.getBool("suffixPrice", DEFAULT_SUFFIX_PRICE));
|
||||||
} else if (getCurrentScreen() == SCREEN_MSCW_TIME) {
|
} else if (getCurrentScreen() == SCREEN_SATS_PER_CURRENCY) {
|
||||||
taskEpdContent = parseSatsPerCurrency(price, priceSymbol, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
taskEpdContent = parseSatsPerCurrency(price, currency, preferences.getBool("useSatsSymbol", DEFAULT_USE_SATS_SYMBOL));
|
||||||
} else {
|
} else {
|
||||||
taskEpdContent =
|
taskEpdContent =
|
||||||
parseMarketCap(getBlockHeight(), price, priceSymbol,
|
parseMarketCap(getBlockHeight(), price, currency,
|
||||||
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
preferences.getBool("mcapBigChar", DEFAULT_MCAP_BIG_CHAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +154,7 @@ void setupTasks() {
|
||||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||||
&workerTaskHandle);
|
&workerTaskHandle);
|
||||||
|
|
||||||
xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY,
|
xTaskCreate(taskScreenRotate, "rotateScreen", 4096, NULL, tskIDLE_PRIORITY,
|
||||||
&taskScreenRotateTaskHandle);
|
&taskScreenRotateTaskHandle);
|
||||||
|
|
||||||
waitUntilNoneBusy();
|
waitUntilNoneBusy();
|
||||||
|
@ -242,7 +244,7 @@ void setCurrentScreen(uint newScreen) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SCREEN_MARKET_CAP:
|
case SCREEN_MARKET_CAP:
|
||||||
case SCREEN_MSCW_TIME:
|
case SCREEN_SATS_PER_CURRENCY:
|
||||||
case SCREEN_BTC_TICKER: {
|
case SCREEN_BTC_TICKER: {
|
||||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||||
|
@ -270,10 +272,36 @@ void setCurrentScreen(uint newScreen) {
|
||||||
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
if (eventSourceTaskHandle != NULL) xTaskNotifyGive(eventSourceTaskHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isCurrencySpecific(uint screen) {
|
||||||
|
switch (screen) {
|
||||||
|
case SCREEN_BTC_TICKER:
|
||||||
|
case SCREEN_SATS_PER_CURRENCY:
|
||||||
|
case SCREEN_MARKET_CAP:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void nextScreen() {
|
void nextScreen() {
|
||||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||||
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
||||||
|
|
||||||
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
||||||
|
std::vector<std::string> ac = getActiveCurrencies();
|
||||||
|
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
||||||
|
if (getCurrencyCode(getCurrentCurrency()) != ac.back()) {
|
||||||
|
auto it = std::find(ac.begin(), ac.end(), curCode);
|
||||||
|
if (it != ac.end()) {
|
||||||
|
size_t index = std::distance(ac.begin(), it);
|
||||||
|
setCurrentCurrency(getCurrencyChar(ac.at(index+1)));
|
||||||
|
setCurrentScreen(getCurrentScreen());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCurrentCurrency(getCurrencyChar(ac.front()));
|
||||||
|
}
|
||||||
|
|
||||||
int newCurrentScreen;
|
int newCurrentScreen;
|
||||||
|
|
||||||
if (currentIndex < screenMappings.size() - 1) {
|
if (currentIndex < screenMappings.size() - 1) {
|
||||||
|
@ -302,6 +330,23 @@ void previousScreen() {
|
||||||
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
int currentIndex = findScreenIndexByValue(getCurrentScreen());
|
||||||
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
std::vector<ScreenMapping> screenMappings = getScreenNameMap();
|
||||||
|
|
||||||
|
if (preferences.getBool("ownDataSource", DEFAULT_OWN_DATA_SOURCE) && isCurrencySpecific(getCurrentScreen())) {
|
||||||
|
std::vector<std::string> ac = getActiveCurrencies();
|
||||||
|
std::string curCode = getCurrencyCode(getCurrentCurrency());
|
||||||
|
if (getCurrencyCode(getCurrentCurrency()) != ac.front()) {
|
||||||
|
auto it = std::find(ac.begin(), ac.end(), curCode);
|
||||||
|
if (it != ac.end()) {
|
||||||
|
size_t index = std::distance(ac.begin(), it);
|
||||||
|
setCurrentCurrency(getCurrencyChar(ac.at(index-1)));
|
||||||
|
setCurrentScreen(getCurrentScreen());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setCurrentCurrency(getCurrencyChar(ac.back()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int newCurrentScreen;
|
int newCurrentScreen;
|
||||||
|
|
||||||
if (currentIndex > 0) {
|
if (currentIndex > 0) {
|
||||||
|
@ -352,4 +397,13 @@ void showSystemStatusScreen() {
|
||||||
(int)round(ESP.getHeapSize() / 1024);
|
(int)round(ESP.getHeapSize() / 1024);
|
||||||
setCurrentScreen(SCREEN_CUSTOM);
|
setCurrentScreen(SCREEN_CUSTOM);
|
||||||
setEpdContent(sysStatusEpdContent);
|
setEpdContent(sysStatusEpdContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setCurrentCurrency(char currency) {
|
||||||
|
currentCurrency = currency;
|
||||||
|
preferences.putUChar("lastCurrency", currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint getCurrentCurrency() {
|
||||||
|
return currentCurrency;
|
||||||
}
|
}
|
|
@ -60,3 +60,6 @@ void setTimerActive(bool status);
|
||||||
void toggleTimerActive();
|
void toggleTimerActive();
|
||||||
|
|
||||||
void setupTasks();
|
void setupTasks();
|
||||||
|
void setCurrentCurrency(char currency);
|
||||||
|
|
||||||
|
uint getCurrentCurrency();
|
|
@ -29,12 +29,29 @@ extern std::mutex mcpMutex;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const PROGMEM int SCREEN_BLOCK_HEIGHT = 0;
|
const PROGMEM int SCREEN_BLOCK_HEIGHT = 0;
|
||||||
const PROGMEM int SCREEN_MSCW_TIME = 1;
|
|
||||||
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_BLOCK_FEE_RATE = 6;
|
const PROGMEM int SCREEN_BLOCK_FEE_RATE = 6;
|
||||||
|
|
||||||
|
const PROGMEM int SCREEN_SATS_PER_CURRENCY = 10;
|
||||||
|
|
||||||
|
const PROGMEM int SCREEN_BTC_TICKER = 20;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_USD = 20;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_EUR = 21;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_GBP = 22;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_JPY = 23;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_AUD = 24;
|
||||||
|
// const PROGMEM int SCREEN_BTC_TICKER_CAD = 25;
|
||||||
|
|
||||||
|
const PROGMEM int SCREEN_MARKET_CAP = 30;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_USD = 30;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_EUR = 31;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_GBP = 32;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_JPY = 33;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_AUD = 34;
|
||||||
|
// const PROGMEM int SCREEN_MARKET_CAP_CAD = 35;
|
||||||
|
|
||||||
const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
|
const PROGMEM int SCREEN_BITAXE_HASHRATE = 80;
|
||||||
const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
|
const PROGMEM int SCREEN_BITAXE_BESTDIFF = 81;
|
||||||
|
|
||||||
|
@ -42,7 +59,7 @@ const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||||
const int SCREEN_COUNT = 7;
|
const int SCREEN_COUNT = 7;
|
||||||
const PROGMEM int screens[SCREEN_COUNT] = {
|
const PROGMEM int screens[SCREEN_COUNT] = {
|
||||||
SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER,
|
SCREEN_BLOCK_HEIGHT, SCREEN_SATS_PER_CURRENCY, SCREEN_BTC_TICKER,
|
||||||
SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP,
|
SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP,
|
||||||
SCREEN_BLOCK_FEE_RATE};
|
SCREEN_BLOCK_FEE_RATE};
|
||||||
const int usPerSecond = 1000000;
|
const int usPerSecond = 1000000;
|
||||||
|
|
142
src/lib/v2_notify.cpp
Normal file
142
src/lib/v2_notify.cpp
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
#include "v2_notify.hpp"
|
||||||
|
|
||||||
|
WebSocketsClient webSocket;
|
||||||
|
TaskHandle_t v2NotifyTaskHandle;
|
||||||
|
|
||||||
|
void setupV2Notify()
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
webSocket.beginSSL(hostname, 443, "/api/v2/ws");
|
||||||
|
webSocket.onEvent(onWebsocketV2Event);
|
||||||
|
webSocket.setReconnectInterval(5000);
|
||||||
|
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);
|
||||||
|
|
||||||
|
JsonDocument response;
|
||||||
|
|
||||||
|
response["type"] = "subscribe";
|
||||||
|
response["eventType"] = "blockfee";
|
||||||
|
size_t responseLength = measureMsgPack(response);
|
||||||
|
uint8_t* buffer = new uint8_t[responseLength];
|
||||||
|
serializeMsgPack(response, buffer, responseLength);
|
||||||
|
webSocket.sendBIN(buffer, responseLength);
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
buffer = new uint8_t[responseLength];
|
||||||
|
|
||||||
|
response["type"] = "subscribe";
|
||||||
|
response["eventType"] = "blockheight";
|
||||||
|
responseLength = measureMsgPack(response);
|
||||||
|
buffer = new uint8_t[responseLength];
|
||||||
|
serializeMsgPack(response, buffer, responseLength);
|
||||||
|
webSocket.sendBIN(buffer, responseLength);
|
||||||
|
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
buffer = new uint8_t[responseLength];
|
||||||
|
|
||||||
|
response["type"] = "subscribe";
|
||||||
|
response["eventType"] = "price";
|
||||||
|
|
||||||
|
JsonArray currenciesArray = response["currencies"].to<JsonArray>();
|
||||||
|
|
||||||
|
for (const auto &str : getActiveCurrencies())
|
||||||
|
{
|
||||||
|
currenciesArray.add(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// response["currencies"] = currenciesArray;
|
||||||
|
responseLength = measureMsgPack(response);
|
||||||
|
buffer = new uint8_t[responseLength];
|
||||||
|
serializeMsgPack(response, buffer, responseLength);
|
||||||
|
webSocket.sendBIN(buffer, responseLength);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WStype_TEXT:
|
||||||
|
Serial.printf("[WSc] get text: %s\n", payload);
|
||||||
|
|
||||||
|
// send message to server
|
||||||
|
// webSocket.sendTXT("message here");
|
||||||
|
break;
|
||||||
|
case WStype_BIN:
|
||||||
|
{
|
||||||
|
JsonDocument doc;
|
||||||
|
DeserializationError error = deserializeMsgPack(doc, payload, length);
|
||||||
|
|
||||||
|
handleV2Message(doc);
|
||||||
|
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 handleV2Message(JsonDocument doc) {
|
||||||
|
if (doc.containsKey("blockheight"))
|
||||||
|
{
|
||||||
|
uint newBlockHeight = doc["blockheight"].as<uint>();
|
||||||
|
|
||||||
|
if (newBlockHeight == getBlockHeight()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processNewBlock(newBlockHeight);
|
||||||
|
}
|
||||||
|
else if (doc.containsKey("blockfee"))
|
||||||
|
{
|
||||||
|
uint medianFee = doc["blockfee"].as<uint>();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
for(;;) {
|
||||||
|
webSocket.loop();
|
||||||
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupV2NotifyTask() {
|
||||||
|
xTaskCreate(taskV2Notify, "v2Notify", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||||
|
&v2NotifyTaskHandle);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isV2NotifyConnected()
|
||||||
|
{
|
||||||
|
return webSocket.isConnected();
|
||||||
|
}
|
24
src/lib/v2_notify.hpp
Normal file
24
src/lib/v2_notify.hpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <esp_websocket_client.h>
|
||||||
|
#include "block_notify.hpp"
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "lib/screen_handler.hpp"
|
||||||
|
|
||||||
|
extern TaskHandle_t v2NotifyTaskHandle;
|
||||||
|
|
||||||
|
void setupV2NotifyTask();
|
||||||
|
void taskV2Notify(void *pvParameters);
|
||||||
|
|
||||||
|
void setupV2Notify();
|
||||||
|
void onWebsocketV2Event(WStype_t type, uint8_t * payload, size_t length);
|
||||||
|
void handleV2Message(JsonDocument doc);
|
||||||
|
|
||||||
|
bool isV2NotifyConnected();
|
||||||
|
// void stopV2Notify();
|
||||||
|
// void restartV2Notify();
|
||||||
|
// bool getPriceNotifyInit();
|
||||||
|
// uint getLastPriceUpdate();
|
|
@ -41,9 +41,10 @@ void setupWebserver()
|
||||||
server.on("/api/action/timer_restart", HTTP_GET, onApiActionTimerRestart);
|
server.on("/api/action/timer_restart", HTTP_GET, onApiActionTimerRestart);
|
||||||
|
|
||||||
server.on("/api/settings", HTTP_GET, onApiSettingsGet);
|
server.on("/api/settings", HTTP_GET, onApiSettingsGet);
|
||||||
server.on("/api/settings", HTTP_POST, onApiSettingsPost);
|
|
||||||
|
|
||||||
server.on("/api/show/screen", HTTP_GET, onApiShowScreen);
|
server.on("/api/show/screen", HTTP_GET, onApiShowScreen);
|
||||||
|
server.on("/api/show/currency", HTTP_GET, onApiShowCurrency);
|
||||||
|
|
||||||
server.on("/api/show/text", HTTP_GET, onApiShowText);
|
server.on("/api/show/text", HTTP_GET, onApiShowText);
|
||||||
|
|
||||||
server.on("/api/screen/next", HTTP_GET, onApiScreenNext);
|
server.on("/api/screen/next", HTTP_GET, onApiScreenNext);
|
||||||
|
@ -88,6 +89,8 @@ void setupWebserver()
|
||||||
}
|
}
|
||||||
|
|
||||||
server.on("/api/restart", HTTP_GET, onApiRestart);
|
server.on("/api/restart", HTTP_GET, onApiRestart);
|
||||||
|
server.addRewrite(
|
||||||
|
new OneParamRewrite("/api/show/currency/{c}", "/api/show/currency?c={c}"));
|
||||||
server.addRewrite(new OneParamRewrite("/api/lights/color/{color}",
|
server.addRewrite(new OneParamRewrite("/api/lights/color/{color}",
|
||||||
"/api/lights/color?c={color}"));
|
"/api/lights/color?c={color}"));
|
||||||
server.addRewrite(
|
server.addRewrite(
|
||||||
|
@ -241,10 +244,12 @@ JsonDocument getStatusObject()
|
||||||
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["nostr"] = nostrConnected();
|
conStatus["nostr"] = nostrConnected();
|
||||||
|
|
||||||
root["rssi"] = WiFi.RSSI();
|
root["rssi"] = WiFi.RSSI();
|
||||||
|
root["currency"] = getCurrencyCode(getCurrentCurrency());
|
||||||
#ifdef HAS_FRONTLIGHT
|
#ifdef HAS_FRONTLIGHT
|
||||||
std::vector<uint16_t> statuses = frontlightGetStatus();
|
std::vector<uint16_t> statuses = frontlightGetStatus();
|
||||||
uint16_t arr[NUM_SCREENS];
|
uint16_t arr[NUM_SCREENS];
|
||||||
|
@ -548,6 +553,23 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (settings.containsKey("actCurrencies"))
|
||||||
|
{
|
||||||
|
String actCurrencies;
|
||||||
|
|
||||||
|
for (JsonVariant cur : settings["actCurrencies"].as<JsonArray>())
|
||||||
|
{
|
||||||
|
if (!actCurrencies.isEmpty())
|
||||||
|
{
|
||||||
|
actCurrencies += ",";
|
||||||
|
}
|
||||||
|
actCurrencies += cur.as<String>();
|
||||||
|
}
|
||||||
|
|
||||||
|
preferences.putString("actCurrencies", actCurrencies.c_str());
|
||||||
|
Serial.printf("Set actCurrencies: %s\n", actCurrencies);
|
||||||
|
}
|
||||||
|
|
||||||
if (settings.containsKey("txPower"))
|
if (settings.containsKey("txPower"))
|
||||||
{
|
{
|
||||||
int txPower = settings["txPower"].as<int>();
|
int txPower = settings["txPower"].as<int>();
|
||||||
|
@ -696,6 +718,18 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
#endif
|
#endif
|
||||||
JsonArray screens = root["screens"].to<JsonArray>();
|
JsonArray screens = root["screens"].to<JsonArray>();
|
||||||
|
|
||||||
|
JsonArray actCurrencies = root["actCurrencies"].to<JsonArray>();
|
||||||
|
for (const auto &str : getActiveCurrencies())
|
||||||
|
{
|
||||||
|
actCurrencies.add(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonArray availableCurrencies = root["availableCurrencies"].to<JsonArray>();
|
||||||
|
for (const auto &str : getAvailableCurrencies())
|
||||||
|
{
|
||||||
|
availableCurrencies.add(str);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<ScreenMapping> screenNameMap = getScreenNameMap();
|
std::vector<ScreenMapping> screenNameMap = getScreenNameMap();
|
||||||
|
|
||||||
for (int i = 0; i < screenNameMap.size(); i++)
|
for (int i = 0; i < screenNameMap.size(); i++)
|
||||||
|
@ -703,7 +737,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||||
JsonObject o = screens.add<JsonObject>();
|
JsonObject o = screens.add<JsonObject>();
|
||||||
String key = "screen" + String(screenNameMap.at(i).value) + "Visible";
|
String key = "screen" + String(screenNameMap.at(i).value) + "Visible";
|
||||||
o["id"] = screenNameMap.at(i).value;
|
o["id"] = screenNameMap.at(i).value;
|
||||||
o["name"] = screenNameMap.at(i).name;
|
o["name"] = String(screenNameMap.at(i).name);
|
||||||
o["enabled"] = preferences.getBool(key.c_str(), true);
|
o["enabled"] = preferences.getBool(key.c_str(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,230 +774,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
|
||||||
return settingsChanged;
|
return settingsChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onApiSettingsPost(AsyncWebServerRequest *request)
|
|
||||||
{
|
|
||||||
// bool settingsChanged = false;
|
|
||||||
|
|
||||||
// settingsChanged = processEpdColorSettings(request);
|
|
||||||
|
|
||||||
// int headers = request->headers();
|
|
||||||
// int i;
|
|
||||||
// for (i = 0; i < headers; i++)
|
|
||||||
// {
|
|
||||||
// AsyncWebHeader *h = request->getHeader(i);
|
|
||||||
// Serial.printf("HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// int params = request->params();
|
|
||||||
// for (int i = 0; i < params; i++)
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *p = request->getParam(i);
|
|
||||||
// if (p->isFile())
|
|
||||||
// { // p->isPost() is also true
|
|
||||||
// Serial.printf("FILE[%s]: %s, size: %u\n", p->name().c_str(),
|
|
||||||
// p->value().c_str(), p->size());
|
|
||||||
// }
|
|
||||||
// else if (p->isPost())
|
|
||||||
// {
|
|
||||||
// Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("fetchEurPrice", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *fetchEurPrice = request->getParam("fetchEurPrice", true);
|
|
||||||
|
|
||||||
// preferences.putBool("fetchEurPrice", fetchEurPrice->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("fetchEurPrice", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("ledTestOnPower", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *ledTestOnPower =
|
|
||||||
// request->getParam("ledTestOnPower", true);
|
|
||||||
|
|
||||||
// preferences.putBool("ledTestOnPower", ledTestOnPower->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("ledTestOnPower", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("ledFlashOnUpd", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *ledFlashOnUpdate =
|
|
||||||
// request->getParam("ledFlashOnUpd", true);
|
|
||||||
|
|
||||||
// preferences.putBool("ledFlashOnUpd", ledFlashOnUpdate->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("ledFlashOnUpd", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("mdnsEnabled", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *mdnsEnabled = request->getParam("mdnsEnabled", true);
|
|
||||||
|
|
||||||
// preferences.putBool("mdnsEnabled", mdnsEnabled->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("mdnsEnabled", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("otaEnabled", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *otaEnabled = request->getParam("otaEnabled", true);
|
|
||||||
|
|
||||||
// preferences.putBool("otaEnabled", otaEnabled->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("otaEnabled", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("stealFocus", false))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *stealFocusOnBlock =
|
|
||||||
// request->getParam("stealFocus", false);
|
|
||||||
|
|
||||||
// preferences.putBool("stealFocus", stealFocusOnBlock->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("stealFocus", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("mcapBigChar", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *mcapBigChar = request->getParam("mcapBigChar", true);
|
|
||||||
|
|
||||||
// preferences.putBool("mcapBigChar", mcapBigChar->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// preferences.putBool("mcapBigChar", 0);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("mempoolInstance", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *mempoolInstance =
|
|
||||||
// request->getParam("mempoolInstance", true);
|
|
||||||
|
|
||||||
// preferences.putString("mempoolInstance", mempoolInstance->value().c_str());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("hostnamePrefix", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *hostnamePrefix =
|
|
||||||
// request->getParam("hostnamePrefix", true);
|
|
||||||
|
|
||||||
// preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("ledBrightness", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);
|
|
||||||
|
|
||||||
// preferences.putUInt("ledBrightness", ledBrightness->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("fullRefreshMin", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *fullRefreshMin =
|
|
||||||
// request->getParam("fullRefreshMin", true);
|
|
||||||
|
|
||||||
// preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("wpTimeout", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true);
|
|
||||||
|
|
||||||
// preferences.putUInt("wpTimeout", wpTimeout->value().toInt());
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// std::vector<std::string> screenNameMap = getScreenNameMap();
|
|
||||||
|
|
||||||
// if (request->hasParam("screens"))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *screenParam = request->getParam("screens", true);
|
|
||||||
|
|
||||||
// Serial.printf(screenParam->value().c_str());
|
|
||||||
// }
|
|
||||||
|
|
||||||
// for (int i = 0; i < screenNameMap.size(); i++)
|
|
||||||
// {
|
|
||||||
// String key = "screen[" + String(i) + "]";
|
|
||||||
// String prefKey = "screen" + String(i) + "Visible";
|
|
||||||
// bool visible = false;
|
|
||||||
// if (request->hasParam(key, true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *screenParam = request->getParam(key, true);
|
|
||||||
// visible = screenParam->value().toInt();
|
|
||||||
// }
|
|
||||||
|
|
||||||
// preferences.putBool(prefKey.c_str(), visible);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("tzOffset", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *p = request->getParam("tzOffset", true);
|
|
||||||
// int tzOffsetSeconds = p->value().toInt() * 60;
|
|
||||||
// preferences.putInt("gmtOffset", tzOffsetSeconds);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("minSecPriceUpd", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *p = request->getParam("minSecPriceUpd", true);
|
|
||||||
// int minSecPriceUpd = p->value().toInt();
|
|
||||||
// preferences.putUInt("minSecPriceUpd", minSecPriceUpd);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (request->hasParam("timePerScreen", true))
|
|
||||||
// {
|
|
||||||
// const AsyncWebParameter *p = request->getParam("timePerScreen", true);
|
|
||||||
// uint timerSeconds = p->value().toInt() * 60;
|
|
||||||
// preferences.putUInt("timerSeconds", timerSeconds);
|
|
||||||
// settingsChanged = true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// request->send(200);
|
|
||||||
// if (settingsChanged)
|
|
||||||
// {
|
|
||||||
// queueLedEffect(LED_FLASH_SUCCESS);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
void onApiSystemStatus(AsyncWebServerRequest *request)
|
void onApiSystemStatus(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
AsyncResponseStream *response =
|
AsyncResponseStream *response =
|
||||||
|
@ -1209,6 +1019,30 @@ void eventSourceTask(void *pvParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onApiShowCurrency(AsyncWebServerRequest *request)
|
||||||
|
{
|
||||||
|
if (request->hasParam("c"))
|
||||||
|
{
|
||||||
|
const AsyncWebParameter *p = request->getParam("c");
|
||||||
|
std::string currency = p->value().c_str();
|
||||||
|
|
||||||
|
if (!isActiveCurrency(currency))
|
||||||
|
{
|
||||||
|
request->send(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char curChar = getCurrencyChar(currency);
|
||||||
|
|
||||||
|
setCurrentCurrency(curChar);
|
||||||
|
setCurrentScreen(getCurrentScreen());
|
||||||
|
|
||||||
|
request->send(200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
request->send(404);
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAS_FRONTLIGHT
|
#ifdef HAS_FRONTLIGHT
|
||||||
void onApiFrontlightOn(AsyncWebServerRequest *request)
|
void onApiFrontlightOn(AsyncWebServerRequest *request)
|
||||||
{
|
{
|
||||||
|
|
|
@ -30,6 +30,8 @@ void onApiScreenNext(AsyncWebServerRequest *request);
|
||||||
void onApiScreenPrevious(AsyncWebServerRequest *request);
|
void onApiScreenPrevious(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
void onApiShowScreen(AsyncWebServerRequest *request);
|
void onApiShowScreen(AsyncWebServerRequest *request);
|
||||||
|
void onApiShowCurrency(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
void onApiShowText(AsyncWebServerRequest *request);
|
void onApiShowText(AsyncWebServerRequest *request);
|
||||||
void onApiIdentify(AsyncWebServerRequest *request);
|
void onApiIdentify(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
|
@ -38,7 +40,6 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json);
|
||||||
void onApiActionPause(AsyncWebServerRequest *request);
|
void onApiActionPause(AsyncWebServerRequest *request);
|
||||||
void onApiActionTimerRestart(AsyncWebServerRequest *request);
|
void onApiActionTimerRestart(AsyncWebServerRequest *request);
|
||||||
void onApiSettingsGet(AsyncWebServerRequest *request);
|
void onApiSettingsGet(AsyncWebServerRequest *request);
|
||||||
void onApiSettingsPost(AsyncWebServerRequest *request);
|
|
||||||
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json);
|
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json);
|
||||||
void onApiFullRefresh(AsyncWebServerRequest *request);
|
void onApiFullRefresh(AsyncWebServerRequest *request);
|
||||||
|
|
||||||
|
|
|
@ -134,7 +134,7 @@ extern "C" void app_main()
|
||||||
}
|
}
|
||||||
|
|
||||||
// if more than 5 price updates are missed, there is probably something wrong, reconnect
|
// if more than 5 price updates are missed, there is probably something wrong, reconnect
|
||||||
if ((getLastPriceUpdate() - currentUptime) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5))
|
if ((getLastPriceUpdate(CURRENCY_USD) - currentUptime) > (preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE) * 5))
|
||||||
{
|
{
|
||||||
Serial.println(F("Detected 5 missed price updates... restarting price handler."));
|
Serial.println(F("Detected 5 missed price updates... restarting price handler."));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue