Add HARD MONEY detail screen with sparklines and high/low data
- New SCREEN_HARD_MONEY_DETAIL accessible by tapping 'HARD MONEY' header - 3-column layout: Bitcoin | Gold | Silver with spot prices - Day/Month/Year high/low values (color-coded green/red) - Day high/low from intraday hourly data - Month high/low from last 22 trading days - Year high/low from 1-year daily data - Togglable sparklines: D(5m/5d)/W(1h/7d)/M(1d/1mo)/Y(1wk/1y)/A(1mo/max) - Default view is Monthly sparkline - Auto-refresh on period change
This commit is contained in:
parent
7d932adb20
commit
d0c8459a17
1 changed files with 676 additions and 54 deletions
638
src/main.cpp
638
src/main.cpp
|
|
@ -13,6 +13,7 @@
|
||||||
#include <WiFiClientSecure.h>
|
#include <WiFiClientSecure.h>
|
||||||
#include <HTTPClient.h>
|
#include <HTTPClient.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#define SCREEN_WIDTH 800
|
#define SCREEN_WIDTH 800
|
||||||
#define SCREEN_HEIGHT 480
|
#define SCREEN_HEIGHT 480
|
||||||
|
|
@ -159,6 +160,11 @@ const unsigned long WIFI_CONNECT_TIMEOUT = 15000;
|
||||||
bool wifiConnecting = false;
|
bool wifiConnecting = false;
|
||||||
unsigned long wifiConnectStartTime = 0;
|
unsigned long wifiConnectStartTime = 0;
|
||||||
|
|
||||||
|
bool timeSynced = false;
|
||||||
|
bool firstBoot = true;
|
||||||
|
const char* ntpServer = "pool.ntp.org";
|
||||||
|
bool displayFlipped = false;
|
||||||
|
|
||||||
#define HISTORY_DAYS 30
|
#define HISTORY_DAYS 30
|
||||||
double btcHistory[HISTORY_DAYS] = {0};
|
double btcHistory[HISTORY_DAYS] = {0};
|
||||||
double goldHistory[HISTORY_DAYS] = {0};
|
double goldHistory[HISTORY_DAYS] = {0};
|
||||||
|
|
@ -168,12 +174,31 @@ bool goldHistoryLoaded = false;
|
||||||
bool silverHistoryLoaded = false;
|
bool silverHistoryLoaded = false;
|
||||||
unsigned long lastHistoryRefresh = 0;
|
unsigned long lastHistoryRefresh = 0;
|
||||||
|
|
||||||
|
#define HM_HISTORY_MAX 100
|
||||||
|
double btcHmHistory[HM_HISTORY_MAX] = {0};
|
||||||
|
double goldHmHistory[HM_HISTORY_MAX] = {0};
|
||||||
|
double silverHmHistory[HM_HISTORY_MAX] = {0};
|
||||||
|
int btcHmCount = 0;
|
||||||
|
int goldHmCount = 0;
|
||||||
|
int silverHmCount = 0;
|
||||||
|
bool btcHmLoaded = false;
|
||||||
|
bool goldHmLoaded = false;
|
||||||
|
bool silverHmLoaded = false;
|
||||||
|
double btcHighDay = 0, btcLowDay = 0, btcHighMonth = 0, btcLowMonth = 0, btcHighYear = 0, btcLowYear = 0;
|
||||||
|
double goldHighDay = 0, goldLowDay = 0, goldHighMonth = 0, goldLowMonth = 0, goldHighYear = 0, goldLowYear = 0;
|
||||||
|
double silverHighDay = 0, silverLowDay = 0, silverHighMonth = 0, silverLowMonth = 0, silverHighYear = 0, silverLowYear = 0;
|
||||||
|
int hmSparklinePeriod = 2;
|
||||||
|
bool hmNeedsRefresh = false;
|
||||||
|
unsigned long hmLastFetch = 0;
|
||||||
|
const unsigned long HM_FETCH_INTERVAL = 60000;
|
||||||
|
|
||||||
enum ScreenState {
|
enum ScreenState {
|
||||||
SCREEN_DASHBOARD,
|
SCREEN_DASHBOARD,
|
||||||
SCREEN_CUSTOMIZE_STOCKS,
|
SCREEN_CUSTOMIZE_STOCKS,
|
||||||
SCREEN_CUSTOMIZE_INDICES,
|
SCREEN_CUSTOMIZE_INDICES,
|
||||||
SCREEN_WIFI_CONFIG,
|
SCREEN_WIFI_CONFIG,
|
||||||
SCREEN_WIFI_PASSWORD
|
SCREEN_WIFI_PASSWORD,
|
||||||
|
SCREEN_HARD_MONEY_DETAIL
|
||||||
};
|
};
|
||||||
ScreenState currentScreen = SCREEN_DASHBOARD;
|
ScreenState currentScreen = SCREEN_DASHBOARD;
|
||||||
|
|
||||||
|
|
@ -360,6 +385,223 @@ void fetchAllHistory() {
|
||||||
fetchHistory("SI=F", silverHistory, &silverHistoryLoaded);
|
fetchHistory("SI=F", silverHistory, &silverHistoryLoaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool fetchHmHistoryForSymbol(const char* symbol, double* history, int* count, int period) {
|
||||||
|
const char* interval;
|
||||||
|
const char* range;
|
||||||
|
|
||||||
|
switch (period) {
|
||||||
|
case 0: interval = "5m"; range = "5d"; break;
|
||||||
|
case 1: interval = "1h"; range = "7d"; break;
|
||||||
|
case 2: interval = "1d"; range = "1mo"; break;
|
||||||
|
case 3: interval = "1wk"; range = "1y"; break;
|
||||||
|
case 4: interval = "1mo"; range = "max"; break;
|
||||||
|
default: interval = "1d"; range = "1mo"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
|
||||||
|
HTTPClient http;
|
||||||
|
String url = "https://query1.finance.yahoo.com/v8/finance/chart/" + String(symbol) + "?interval=" + String(interval) + "&range=" + String(range);
|
||||||
|
|
||||||
|
if (!http.begin(client, url)) return false;
|
||||||
|
|
||||||
|
http.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
http.setTimeout(15000);
|
||||||
|
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode != HTTP_CODE_OK) {
|
||||||
|
http.end();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String payload = http.getString();
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
String arraySearch = "\"close\":[";
|
||||||
|
int arrayIdx = payload.indexOf(arraySearch);
|
||||||
|
if (arrayIdx == -1) return false;
|
||||||
|
|
||||||
|
int arrayStart = arrayIdx + arraySearch.length();
|
||||||
|
int arrayEnd = payload.indexOf("]", arrayStart);
|
||||||
|
if (arrayEnd == -1) return false;
|
||||||
|
|
||||||
|
String closeArray = payload.substring(arrayStart, arrayEnd);
|
||||||
|
|
||||||
|
*count = 0;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < closeArray.length() && *count < HM_HISTORY_MAX) {
|
||||||
|
while (pos < closeArray.length() && (closeArray[pos] == ' ' || closeArray[pos] == ',')) pos++;
|
||||||
|
if (pos >= closeArray.length()) break;
|
||||||
|
|
||||||
|
int valueStart = pos;
|
||||||
|
while (pos < closeArray.length() && closeArray[pos] != ',' && closeArray[pos] != ' ') pos++;
|
||||||
|
|
||||||
|
String valueStr = closeArray.substring(valueStart, pos);
|
||||||
|
|
||||||
|
if (!valueStr.equals("null") && valueStr.length() > 0) {
|
||||||
|
double value = valueStr.toDouble();
|
||||||
|
if (value > 0) {
|
||||||
|
history[*count] = value;
|
||||||
|
(*count)++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchHmHighLowForSymbol(const char* symbol, double* highDay, double* lowDay, double* highMonth, double* lowMonth, double* highYear, double* lowYear) {
|
||||||
|
if (WiFi.status() != WL_CONNECTED) return;
|
||||||
|
|
||||||
|
WiFiClientSecure client;
|
||||||
|
client.setInsecure();
|
||||||
|
HTTPClient http;
|
||||||
|
|
||||||
|
// First API call: hourly data for today's intraday high/low
|
||||||
|
String url = "https://query1.finance.yahoo.com/v8/finance/chart/" + String(symbol) + "?interval=1h&range=1d";
|
||||||
|
if (http.begin(client, url)) {
|
||||||
|
http.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
http.setTimeout(15000);
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode == HTTP_CODE_OK) {
|
||||||
|
String payload = http.getString();
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
String arraySearch = "\"close\":[";
|
||||||
|
int arrayIdx = payload.indexOf(arraySearch);
|
||||||
|
if (arrayIdx != -1) {
|
||||||
|
int arrayStart = arrayIdx + arraySearch.length();
|
||||||
|
int arrayEnd = payload.indexOf("]", arrayStart);
|
||||||
|
if (arrayEnd != -1) {
|
||||||
|
String closeArray = payload.substring(arrayStart, arrayEnd);
|
||||||
|
|
||||||
|
double minDay = 1e18, maxDay = 0;
|
||||||
|
int pos = 0;
|
||||||
|
while (pos < closeArray.length()) {
|
||||||
|
while (pos < closeArray.length() && (closeArray[pos] == ' ' || closeArray[pos] == ',')) pos++;
|
||||||
|
if (pos >= closeArray.length()) break;
|
||||||
|
int valueStart = pos;
|
||||||
|
while (pos < closeArray.length() && closeArray[pos] != ',' && closeArray[pos] != ' ') pos++;
|
||||||
|
String valueStr = closeArray.substring(valueStart, pos);
|
||||||
|
if (!valueStr.equals("null") && valueStr.length() > 0) {
|
||||||
|
double value = valueStr.toDouble();
|
||||||
|
if (value > 0) {
|
||||||
|
if (value < minDay) minDay = value;
|
||||||
|
if (value > maxDay) maxDay = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (maxDay > 0) {
|
||||||
|
*highDay = maxDay;
|
||||||
|
*lowDay = minDay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
http.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second API call: daily data for month and year high/low
|
||||||
|
url = "https://query1.finance.yahoo.com/v8/finance/chart/" + String(symbol) + "?interval=1d&range=1y";
|
||||||
|
if (!http.begin(client, url)) return;
|
||||||
|
|
||||||
|
http.setUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||||
|
http.setTimeout(15000);
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode != HTTP_CODE_OK) {
|
||||||
|
http.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String payload = http.getString();
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
String arraySearch = "\"close\":[";
|
||||||
|
int arrayIdx = payload.indexOf(arraySearch);
|
||||||
|
if (arrayIdx == -1) return;
|
||||||
|
|
||||||
|
int arrayStart = arrayIdx + arraySearch.length();
|
||||||
|
int arrayEnd = payload.indexOf("]", arrayStart);
|
||||||
|
if (arrayEnd == -1) return;
|
||||||
|
|
||||||
|
String closeArray = payload.substring(arrayStart, arrayEnd);
|
||||||
|
|
||||||
|
// First pass: count values and find year high/low
|
||||||
|
double minYear = 1e18, maxYear = 0;
|
||||||
|
int valueCount = 0;
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
while (pos < closeArray.length()) {
|
||||||
|
while (pos < closeArray.length() && (closeArray[pos] == ' ' || closeArray[pos] == ',')) pos++;
|
||||||
|
if (pos >= closeArray.length()) break;
|
||||||
|
int valueStart = pos;
|
||||||
|
while (pos < closeArray.length() && closeArray[pos] != ',' && closeArray[pos] != ' ') pos++;
|
||||||
|
String valueStr = closeArray.substring(valueStart, pos);
|
||||||
|
if (!valueStr.equals("null") && valueStr.length() > 0) {
|
||||||
|
double value = valueStr.toDouble();
|
||||||
|
if (value > 0) {
|
||||||
|
valueCount++;
|
||||||
|
if (value < minYear) minYear = value;
|
||||||
|
if (value > maxYear) maxYear = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueCount > 0) {
|
||||||
|
*highYear = maxYear;
|
||||||
|
*lowYear = minYear;
|
||||||
|
|
||||||
|
// Second pass: find month high/low (last 22 trading days)
|
||||||
|
int monthStart = valueCount > 22 ? valueCount - 22 : 0;
|
||||||
|
double minMonth = 1e18, maxMonth = 0;
|
||||||
|
int idx = 0;
|
||||||
|
pos = 0;
|
||||||
|
while (pos < closeArray.length()) {
|
||||||
|
while (pos < closeArray.length() && (closeArray[pos] == ' ' || closeArray[pos] == ',')) pos++;
|
||||||
|
if (pos >= closeArray.length()) break;
|
||||||
|
int valueStart = pos;
|
||||||
|
while (pos < closeArray.length() && closeArray[pos] != ',' && closeArray[pos] != ' ') pos++;
|
||||||
|
String valueStr = closeArray.substring(valueStart, pos);
|
||||||
|
if (!valueStr.equals("null") && valueStr.length() > 0) {
|
||||||
|
double value = valueStr.toDouble();
|
||||||
|
if (value > 0) {
|
||||||
|
if (idx >= monthStart) {
|
||||||
|
if (value < minMonth) minMonth = value;
|
||||||
|
if (value > maxMonth) maxMonth = value;
|
||||||
|
}
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*highMonth = maxMonth;
|
||||||
|
*lowMonth = minMonth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fetchAllHmData(int period) {
|
||||||
|
btcHmCount = goldHmCount = silverHmCount = 0;
|
||||||
|
btcHmLoaded = goldHmLoaded = silverHmLoaded = false;
|
||||||
|
|
||||||
|
fetchHmHistoryForSymbol("BTC-USD", btcHmHistory, &btcHmCount, period);
|
||||||
|
btcHmLoaded = btcHmCount > 0;
|
||||||
|
|
||||||
|
fetchHmHistoryForSymbol("GC=F", goldHmHistory, &goldHmCount, period);
|
||||||
|
goldHmLoaded = goldHmCount > 0;
|
||||||
|
|
||||||
|
fetchHmHistoryForSymbol("SI=F", silverHmHistory, &silverHmCount, period);
|
||||||
|
silverHmLoaded = silverHmCount > 0;
|
||||||
|
|
||||||
|
fetchHmHighLowForSymbol("BTC-USD", &btcHighDay, &btcLowDay, &btcHighMonth, &btcLowMonth, &btcHighYear, &btcLowYear);
|
||||||
|
fetchHmHighLowForSymbol("GC=F", &goldHighDay, &goldLowDay, &goldHighMonth, &goldLowMonth, &goldHighYear, &goldLowYear);
|
||||||
|
fetchHmHighLowForSymbol("SI=F", &silverHighDay, &silverLowDay, &silverHighMonth, &silverLowMonth, &silverHighYear, &silverLowYear);
|
||||||
|
|
||||||
|
hmLastFetch = millis();
|
||||||
|
}
|
||||||
|
|
||||||
void drawSparkline(int x, int y, int width, int height, double* history, bool loaded, uint16_t color) {
|
void drawSparkline(int x, int y, int width, int height, double* history, bool loaded, uint16_t color) {
|
||||||
if (!loaded) return;
|
if (!loaded) return;
|
||||||
|
|
||||||
|
|
@ -437,6 +679,88 @@ void saveConfig() {
|
||||||
preferences.end();
|
preferences.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int dayOfWeek(int year, int month, int day) {
|
||||||
|
if (month < 3) {
|
||||||
|
month += 12;
|
||||||
|
year--;
|
||||||
|
}
|
||||||
|
return (day + 13 * (month + 1) / 5 + year + year / 4 - year / 100 + year / 400) % 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUSDST(int year, int month, int day, int hour) {
|
||||||
|
int springDOW = dayOfWeek(year, 3, 8);
|
||||||
|
int springStart = 8 + ((14 - springDOW) % 7);
|
||||||
|
|
||||||
|
int fallDOW = dayOfWeek(year, 11, 1);
|
||||||
|
int fallEnd = 1 + ((14 - fallDOW) % 7);
|
||||||
|
|
||||||
|
if (month < 3 || month > 11) return false;
|
||||||
|
if (month > 3 && month < 11) return true;
|
||||||
|
|
||||||
|
if (month == 3) {
|
||||||
|
if (day < springStart) return false;
|
||||||
|
if (day > springStart) return true;
|
||||||
|
return hour >= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (month == 11) {
|
||||||
|
if (day < fallEnd) return true;
|
||||||
|
if (day > fallEnd) return false;
|
||||||
|
return hour < 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isUSMarketOpen() {
|
||||||
|
if (!timeSynced) return firstBoot;
|
||||||
|
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
struct tm* utc = gmtime(&now);
|
||||||
|
|
||||||
|
int utcHour = utc->tm_hour;
|
||||||
|
int utcMinute = utc->tm_min;
|
||||||
|
int year = utc->tm_year + 1900;
|
||||||
|
int month = utc->tm_mon + 1;
|
||||||
|
int day = utc->tm_mday;
|
||||||
|
int utcWday = utc->tm_wday;
|
||||||
|
|
||||||
|
bool dst = isUSDST(year, month, day, utcHour);
|
||||||
|
int etOffset = dst ? -4 : -5;
|
||||||
|
|
||||||
|
int etHour = utcHour + etOffset;
|
||||||
|
int etWday = utcWday;
|
||||||
|
|
||||||
|
if (etHour < 0) {
|
||||||
|
etHour += 24;
|
||||||
|
etWday = (etWday + 6) % 7;
|
||||||
|
} else if (etHour >= 24) {
|
||||||
|
etHour -= 24;
|
||||||
|
etWday = (etWday + 1) % 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (etWday == 0 || etWday == 6) return false;
|
||||||
|
|
||||||
|
if (etHour < 9 || etHour >= 16) return false;
|
||||||
|
if (etHour == 9 && utcMinute < 30) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void syncTime() {
|
||||||
|
configTime(0, 0, ntpServer);
|
||||||
|
|
||||||
|
int retries = 0;
|
||||||
|
while (time(nullptr) < 100000 && retries < 20) {
|
||||||
|
delay(500);
|
||||||
|
retries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (time(nullptr) >= 100000) {
|
||||||
|
timeSynced = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void updatePrices() {
|
void updatePrices() {
|
||||||
if (WiFi.status() != WL_CONNECTED) return;
|
if (WiFi.status() != WL_CONNECTED) return;
|
||||||
|
|
||||||
|
|
@ -444,6 +768,7 @@ void updatePrices() {
|
||||||
fetchPriceYahoo("GC=F", &goldPrice);
|
fetchPriceYahoo("GC=F", &goldPrice);
|
||||||
fetchPriceYahoo("SI=F", &silverPrice);
|
fetchPriceYahoo("SI=F", &silverPrice);
|
||||||
|
|
||||||
|
if (isUSMarketOpen()) {
|
||||||
for (int i = 0; i < MAX_STOCKS; i++) {
|
for (int i = 0; i < MAX_STOCKS; i++) {
|
||||||
if (strlen(stockTickers[i]) > 0) {
|
if (strlen(stockTickers[i]) > 0) {
|
||||||
fetchPriceFinnhub(stockTickers[i], &stockPrices[i]);
|
fetchPriceFinnhub(stockTickers[i], &stockPrices[i]);
|
||||||
|
|
@ -455,6 +780,11 @@ void updatePrices() {
|
||||||
fetchPriceYahoo(indexTickers[i], &indexPrices[i]);
|
fetchPriceYahoo(indexTickers[i], &indexPrices[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstBoot) {
|
||||||
|
firstBoot = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawKeyboard(int y) {
|
void drawKeyboard(int y) {
|
||||||
|
|
@ -714,6 +1044,42 @@ lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||||
lcd.drawString("BACK", 125, SCREEN_HEIGHT - 30);
|
lcd.drawString("BACK", 125, SCREEN_HEIGHT - 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void drawGearIcon(int cx, int cy, int radius, uint16_t color) {
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
float angle = i * 45.0 * DEG_TO_RAD;
|
||||||
|
float halfWidth = 0.35;
|
||||||
|
float cosA = cos(angle);
|
||||||
|
float sinA = sin(angle);
|
||||||
|
int x0 = cx + cosA * radius;
|
||||||
|
int y0 = cy + sinA * radius;
|
||||||
|
int x1 = cx + cosA * (radius + 6);
|
||||||
|
int y1 = cy + sinA * (radius + 6);
|
||||||
|
int dx = halfWidth * (-sinA) * radius;
|
||||||
|
int dy = halfWidth * cosA * radius;
|
||||||
|
lcd.fillTriangle(x0 - dx, y0 - dy, x1 - dx, y1 - dy, x1 + dx, y1 + dy, color);
|
||||||
|
lcd.fillTriangle(x0 - dx, y0 - dy, x1 + dx, y1 + dy, x0 + dx, y0 + dy, color);
|
||||||
|
}
|
||||||
|
lcd.fillCircle(cx, cy, radius, color);
|
||||||
|
lcd.fillCircle(cx, cy, radius - 3, TFT_ORANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drawFlipIcon(int cx, int cy, int radius, uint16_t color) {
|
||||||
|
lcd.setColor(color);
|
||||||
|
lcd.drawArc(cx, cy, radius, radius - 3, 60, 300);
|
||||||
|
float arrowAngle = 60.0 * DEG_TO_RAD;
|
||||||
|
int arrowX = cx + cos(arrowAngle) * radius;
|
||||||
|
int arrowY = cy - sin(arrowAngle) * radius;
|
||||||
|
float tangentAngle = arrowAngle - PI / 2;
|
||||||
|
int tipX = arrowX + cos(tangentAngle) * 6;
|
||||||
|
int tipY = arrowY - sin(tangentAngle) * 6;
|
||||||
|
lcd.fillTriangle(
|
||||||
|
arrowX + cos(tangentAngle) * 2 - sin(tangentAngle) * 4,
|
||||||
|
arrowY - sin(tangentAngle) * 2 - cos(tangentAngle) * 4,
|
||||||
|
arrowX + cos(tangentAngle) * 2 + sin(tangentAngle) * 4,
|
||||||
|
arrowY - sin(tangentAngle) * 2 + cos(tangentAngle) * 4,
|
||||||
|
tipX, tipY, color);
|
||||||
|
}
|
||||||
|
|
||||||
void drawDashboard() {
|
void drawDashboard() {
|
||||||
lcd.fillScreen(TFT_BLACK);
|
lcd.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
|
@ -724,6 +1090,7 @@ void drawDashboard() {
|
||||||
lcd.drawString("HARD MONEY", 20, 22);
|
lcd.drawString("HARD MONEY", 20, 22);
|
||||||
lcd.drawString("STOCKS", 280, 22);
|
lcd.drawString("STOCKS", 280, 22);
|
||||||
lcd.drawString("INDICES", 540, 22);
|
lcd.drawString("INDICES", 540, 22);
|
||||||
|
drawFlipIcon(SCREEN_WIDTH - 32, 22, 12, TFT_WHITE);
|
||||||
|
|
||||||
int col1X = 20;
|
int col1X = 20;
|
||||||
int col2X = 280;
|
int col2X = 280;
|
||||||
|
|
@ -777,8 +1144,13 @@ indexY += 65;
|
||||||
String wifiStatus;
|
String wifiStatus;
|
||||||
if (wifiConnecting) {
|
if (wifiConnecting) {
|
||||||
wifiStatus = "Connecting...";
|
wifiStatus = "Connecting...";
|
||||||
|
} else if (WiFi.status() == WL_CONNECTED) {
|
||||||
|
wifiStatus = WiFi.SSID();
|
||||||
|
if (wifiStatus.length() > 20) {
|
||||||
|
wifiStatus = wifiStatus.substring(0, 17) + "...";
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
wifiStatus = WiFi.status() == WL_CONNECTED ? "OK" : "OFFLINE";
|
wifiStatus = "OFFLINE";
|
||||||
}
|
}
|
||||||
lcd.drawString("WiFi: " + wifiStatus, 20, SCREEN_HEIGHT - 20);
|
lcd.drawString("WiFi: " + wifiStatus, 20, SCREEN_HEIGHT - 20);
|
||||||
|
|
||||||
|
|
@ -791,8 +1163,7 @@ indexY += 65;
|
||||||
lcd.setTextDatum(textdatum_t::middle_center);
|
lcd.setTextDatum(textdatum_t::middle_center);
|
||||||
lcd.drawString(String(timeStr), SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
lcd.drawString(String(timeStr), SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
||||||
|
|
||||||
lcd.fillSmoothRoundRect(SCREEN_WIDTH - 160, SCREEN_HEIGHT - 36, 140, 32, 6, TFT_DARKGRAY);
|
drawGearIcon(SCREEN_WIDTH - 32, SCREEN_HEIGHT - 20, 9, TFT_WHITE);
|
||||||
lcd.drawString("CUSTOMIZE", SCREEN_WIDTH - 90, SCREEN_HEIGHT - 20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawFullKeyboard(int y, bool showSpecials) {
|
void drawFullKeyboard(int y, bool showSpecials) {
|
||||||
|
|
@ -1277,8 +1648,215 @@ void showRefreshingMessage() {
|
||||||
lcd.setTextDatum(textdatum_t::middle_center);
|
lcd.setTextDatum(textdatum_t::middle_center);
|
||||||
lcd.drawString("REFRESHING...", SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
lcd.drawString("REFRESHING...", SCREEN_WIDTH / 2, SCREEN_HEIGHT - 20);
|
||||||
|
|
||||||
lcd.fillSmoothRoundRect(SCREEN_WIDTH - 160, SCREEN_HEIGHT - 36, 140, 32, 6, TFT_DARKGRAY);
|
drawGearIcon(SCREEN_WIDTH - 32, SCREEN_HEIGHT - 20, 9, TFT_WHITE);
|
||||||
lcd.drawString("CUSTOMIZE", SCREEN_WIDTH - 90, SCREEN_HEIGHT - 20);
|
}
|
||||||
|
|
||||||
|
void drawHardMoneyDetailScreen() {
|
||||||
|
lcd.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
lcd.fillSmoothRoundRect(0, 0, SCREEN_WIDTH, 45, 8, TFT_ORANGE);
|
||||||
|
lcd.setTextColor(TFT_WHITE, TFT_ORANGE);
|
||||||
|
lcd.setFont(&fonts::DejaVu24);
|
||||||
|
lcd.setTextDatum(textdatum_t::middle_center);
|
||||||
|
lcd.drawString("HARD MONEY", SCREEN_WIDTH / 2, 22);
|
||||||
|
|
||||||
|
int col1X = 50;
|
||||||
|
int col2X = 310;
|
||||||
|
int col3X = 570;
|
||||||
|
int colWidth = 180;
|
||||||
|
|
||||||
|
int headerY = 65;
|
||||||
|
int priceY = 90;
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_ORANGE, TFT_BLACK);
|
||||||
|
lcd.setFont(&fonts::Roboto_Thin_24);
|
||||||
|
lcd.setTextDatum(textdatum_t::middle_left);
|
||||||
|
lcd.drawString("BITCOIN", col1X, headerY);
|
||||||
|
lcd.drawString(formatPriceUS(btcPrice, 0), col1X, priceY);
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_GOLD, TFT_BLACK);
|
||||||
|
lcd.drawString("GOLD", col2X, headerY);
|
||||||
|
lcd.drawString(formatPriceUS(goldPrice, 2), col2X, priceY);
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_SILVER, TFT_BLACK);
|
||||||
|
lcd.drawString("SILVER", col3X, headerY);
|
||||||
|
lcd.drawString(formatPriceUS(silverPrice, 2), col3X, priceY);
|
||||||
|
|
||||||
|
int highLowY = priceY + 30;
|
||||||
|
int rowHeight = 22;
|
||||||
|
|
||||||
|
lcd.setFont(&fonts::DejaVu12);
|
||||||
|
lcd.setTextDatum(textdatum_t::middle_left);
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
lcd.drawString("Day High:", col1X, highLowY);
|
||||||
|
lcd.drawString(formatPriceUS(btcHighDay, 0, true), col1X + 65, highLowY);
|
||||||
|
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
lcd.drawString("Day High:", col2X, highLowY);
|
||||||
|
lcd.drawString(formatPriceUS(goldHighDay, 2, true), col2X + 65, highLowY);
|
||||||
|
lcd.drawString("Day High:", col3X, highLowY);
|
||||||
|
lcd.drawString(formatPriceUS(silverHighDay, 2, true), col3X + 65, highLowY);
|
||||||
|
|
||||||
|
lcd.setTextColor(0xF800, TFT_BLACK);
|
||||||
|
lcd.drawString("Day Low:", col1X, highLowY + rowHeight);
|
||||||
|
lcd.drawString(formatPriceUS(btcLowDay, 0, true), col1X + 65, highLowY + rowHeight);
|
||||||
|
lcd.drawString("Day Low:", col2X, highLowY + rowHeight);
|
||||||
|
lcd.drawString(formatPriceUS(goldLowDay, 2, true), col2X + 65, highLowY + rowHeight);
|
||||||
|
lcd.drawString("Day Low:", col3X, highLowY + rowHeight);
|
||||||
|
lcd.drawString(formatPriceUS(silverLowDay, 2, true), col3X + 65, highLowY + rowHeight);
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
lcd.drawString("Mo High:", col1X, highLowY + rowHeight * 2);
|
||||||
|
lcd.drawString(formatPriceUS(btcHighMonth, 0, true), col1X + 65, highLowY + rowHeight * 2);
|
||||||
|
lcd.drawString("Mo High:", col2X, highLowY + rowHeight * 2);
|
||||||
|
lcd.drawString(formatPriceUS(goldHighMonth, 2, true), col2X + 65, highLowY + rowHeight * 2);
|
||||||
|
lcd.drawString("Mo High:", col3X, highLowY + rowHeight * 2);
|
||||||
|
lcd.drawString(formatPriceUS(silverHighMonth, 2, true), col3X + 65, highLowY + rowHeight * 2);
|
||||||
|
|
||||||
|
lcd.setTextColor(0xF800, TFT_BLACK);
|
||||||
|
lcd.drawString("Mo Low:", col1X, highLowY + rowHeight * 3);
|
||||||
|
lcd.drawString(formatPriceUS(btcLowMonth, 0, true), col1X + 65, highLowY + rowHeight * 3);
|
||||||
|
lcd.drawString("Mo Low:", col2X, highLowY + rowHeight * 3);
|
||||||
|
lcd.drawString(formatPriceUS(goldLowMonth, 2, true), col2X + 65, highLowY + rowHeight * 3);
|
||||||
|
lcd.drawString("Mo Low:", col3X, highLowY + rowHeight * 3);
|
||||||
|
lcd.drawString(formatPriceUS(silverLowMonth, 2, true), col3X + 65, highLowY + rowHeight * 3);
|
||||||
|
|
||||||
|
lcd.setTextColor(TFT_GREEN, TFT_BLACK);
|
||||||
|
lcd.drawString("Yr High:", col1X, highLowY + rowHeight * 4);
|
||||||
|
lcd.drawString(formatPriceUS(btcHighYear, 0, true), col1X + 65, highLowY + rowHeight * 4);
|
||||||
|
lcd.drawString("Yr High:", col2X, highLowY + rowHeight * 4);
|
||||||
|
lcd.drawString(formatPriceUS(goldHighYear, 2, true), col2X + 65, highLowY + rowHeight * 4);
|
||||||
|
lcd.drawString("Yr High:", col3X, highLowY + rowHeight * 4);
|
||||||
|
lcd.drawString(formatPriceUS(silverHighYear, 2, true), col3X + 65, highLowY + rowHeight * 4);
|
||||||
|
|
||||||
|
lcd.setTextColor(0xF800, TFT_BLACK);
|
||||||
|
lcd.drawString("Yr Low:", col1X, highLowY + rowHeight * 5);
|
||||||
|
lcd.drawString(formatPriceUS(btcLowYear, 0, true), col1X + 65, highLowY + rowHeight * 5);
|
||||||
|
lcd.drawString("Yr Low:", col2X, highLowY + rowHeight * 5);
|
||||||
|
lcd.drawString(formatPriceUS(goldLowYear, 2, true), col2X + 65, highLowY + rowHeight * 5);
|
||||||
|
lcd.drawString("Yr Low:", col3X, highLowY + rowHeight * 5);
|
||||||
|
lcd.drawString(formatPriceUS(silverLowYear, 2, true), col3X + 65, highLowY + rowHeight * 5);
|
||||||
|
|
||||||
|
int sparklineY = highLowY + rowHeight * 6 + 15;
|
||||||
|
|
||||||
|
const char* periodLabels[] = {"D", "W", "M", "Y", "A"};
|
||||||
|
int btnWidth = 50;
|
||||||
|
int btnHeight = 30;
|
||||||
|
int btnGap = 10;
|
||||||
|
int totalBtnWidth = 5 * btnWidth + 4 * btnGap;
|
||||||
|
int btnStartX = (SCREEN_WIDTH - totalBtnWidth) / 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int btnX = btnStartX + i * (btnWidth + btnGap);
|
||||||
|
uint16_t bgColor = (hmSparklinePeriod == i) ? TFT_ORANGE : TFT_DARKGRAY;
|
||||||
|
lcd.fillSmoothRoundRect(btnX, sparklineY, btnWidth, btnHeight, 6, bgColor);
|
||||||
|
lcd.setTextColor(TFT_WHITE, bgColor);
|
||||||
|
lcd.setFont(&fonts::DejaVu18);
|
||||||
|
lcd.setTextDatum(textdatum_t::middle_center);
|
||||||
|
lcd.drawString(periodLabels[i], btnX + btnWidth / 2, sparklineY + btnHeight / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sparklineDrawY = sparklineY + btnHeight + 15;
|
||||||
|
int sparklineHeight = 80;
|
||||||
|
|
||||||
|
if (btcHmLoaded && btcHmCount > 1) {
|
||||||
|
double minVal = btcHmHistory[0];
|
||||||
|
double maxVal = btcHmHistory[0];
|
||||||
|
for (int i = 0; i < btcHmCount; i++) {
|
||||||
|
if (btcHmHistory[i] < minVal) minVal = btcHmHistory[i];
|
||||||
|
if (btcHmHistory[i] > maxVal) maxVal = btcHmHistory[i];
|
||||||
|
}
|
||||||
|
double range = maxVal - minVal;
|
||||||
|
if (range < 1) range = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < btcHmCount - 1; i++) {
|
||||||
|
int x1 = col1X + (i * colWidth) / (btcHmCount - 1);
|
||||||
|
int x2 = col1X + ((i + 1) * colWidth) / (btcHmCount - 1);
|
||||||
|
int y1 = sparklineDrawY + sparklineHeight - (int)((btcHmHistory[i] - minVal) * sparklineHeight / range);
|
||||||
|
int y2 = sparklineDrawY + sparklineHeight - (int)((btcHmHistory[i + 1] - minVal) * sparklineHeight / range);
|
||||||
|
lcd.drawLine(x1, y1, x2, y2, TFT_ORANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (goldHmLoaded && goldHmCount > 1) {
|
||||||
|
double minVal = goldHmHistory[0];
|
||||||
|
double maxVal = goldHmHistory[0];
|
||||||
|
for (int i = 0; i < goldHmCount; i++) {
|
||||||
|
if (goldHmHistory[i] < minVal) minVal = goldHmHistory[i];
|
||||||
|
if (goldHmHistory[i] > maxVal) maxVal = goldHmHistory[i];
|
||||||
|
}
|
||||||
|
double range = maxVal - minVal;
|
||||||
|
if (range < 1) range = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < goldHmCount - 1; i++) {
|
||||||
|
int x1 = col2X + (i * colWidth) / (goldHmCount - 1);
|
||||||
|
int x2 = col2X + ((i + 1) * colWidth) / (goldHmCount - 1);
|
||||||
|
int y1 = sparklineDrawY + sparklineHeight - (int)((goldHmHistory[i] - minVal) * sparklineHeight / range);
|
||||||
|
int y2 = sparklineDrawY + sparklineHeight - (int)((goldHmHistory[i + 1] - minVal) * sparklineHeight / range);
|
||||||
|
lcd.drawLine(x1, y1, x2, y2, TFT_GOLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (silverHmLoaded && silverHmCount > 1) {
|
||||||
|
double minVal = silverHmHistory[0];
|
||||||
|
double maxVal = silverHmHistory[0];
|
||||||
|
for (int i = 0; i < silverHmCount; i++) {
|
||||||
|
if (silverHmHistory[i] < minVal) minVal = silverHmHistory[i];
|
||||||
|
if (silverHmHistory[i] > maxVal) maxVal = silverHmHistory[i];
|
||||||
|
}
|
||||||
|
double range = maxVal - minVal;
|
||||||
|
if (range < 1) range = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < silverHmCount - 1; i++) {
|
||||||
|
int x1 = col3X + (i * colWidth) / (silverHmCount - 1);
|
||||||
|
int x2 = col3X + ((i + 1) * colWidth) / (silverHmCount - 1);
|
||||||
|
int y1 = sparklineDrawY + sparklineHeight - (int)((silverHmHistory[i] - minVal) * sparklineHeight / range);
|
||||||
|
int y2 = sparklineDrawY + sparklineHeight - (int)((silverHmHistory[i + 1] - minVal) * sparklineHeight / range);
|
||||||
|
lcd.drawLine(x1, y1, x2, y2, TFT_SILVER);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lcd.fillSmoothRoundRect(20, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY);
|
||||||
|
lcd.setTextColor(TFT_WHITE, TFT_GRAY);
|
||||||
|
lcd.setFont(&fonts::DejaVu18);
|
||||||
|
lcd.setTextDatum(textdatum_t::middle_center);
|
||||||
|
lcd.drawString("BACK", 95, SCREEN_HEIGHT - 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool handleHardMoneyTouch(int32_t x, int32_t y) {
|
||||||
|
if (x >= 20 && x < 170 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) {
|
||||||
|
currentScreen = SCREEN_DASHBOARD;
|
||||||
|
needsRefresh = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int btnWidth = 50;
|
||||||
|
int btnHeight = 30;
|
||||||
|
int btnGap = 10;
|
||||||
|
int totalBtnWidth = 5 * btnWidth + 4 * btnGap;
|
||||||
|
int btnStartX = (SCREEN_WIDTH - totalBtnWidth) / 2;
|
||||||
|
|
||||||
|
int headerY = 55;
|
||||||
|
int priceY = 80;
|
||||||
|
int highLowY = priceY + 30;
|
||||||
|
int rowHeight = 22;
|
||||||
|
int sparklineY = highLowY + rowHeight * 6 + 15;
|
||||||
|
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
int btnX = btnStartX + i * (btnWidth + btnGap);
|
||||||
|
if (x >= btnX && x < btnX + btnWidth && y >= sparklineY && y < sparklineY + btnHeight) {
|
||||||
|
if (hmSparklinePeriod != i) {
|
||||||
|
hmSparklinePeriod = i;
|
||||||
|
btcHmLoaded = false;
|
||||||
|
goldHmLoaded = false;
|
||||||
|
silverHmLoaded = false;
|
||||||
|
hmNeedsRefresh = true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void refreshDataAndShow() {
|
void refreshDataAndShow() {
|
||||||
|
|
@ -1290,7 +1868,24 @@ void refreshDataAndShow() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleDashboardTouch(int32_t x, int32_t y) {
|
bool handleDashboardTouch(int32_t x, int32_t y) {
|
||||||
if (x >= SCREEN_WIDTH - 160 && x < SCREEN_WIDTH - 20 && y >= SCREEN_HEIGHT - 36 && y < SCREEN_HEIGHT - 4) {
|
if (x >= SCREEN_WIDTH - 55 && x < SCREEN_WIDTH - 10 && y >= 5 && y < 40) {
|
||||||
|
displayFlipped = !displayFlipped;
|
||||||
|
preferences.begin("dashboard", false);
|
||||||
|
preferences.putBool("flipped", displayFlipped);
|
||||||
|
preferences.end();
|
||||||
|
lcd.setRotation(displayFlipped ? 2 : 0);
|
||||||
|
needsRefresh = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= 20 && x < 200 && y >= 0 && y < 45) {
|
||||||
|
currentScreen = SCREEN_HARD_MONEY_DETAIL;
|
||||||
|
hmSparklinePeriod = 2;
|
||||||
|
hmNeedsRefresh = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= SCREEN_WIDTH - 50 && x < SCREEN_WIDTH - 14 && y >= SCREEN_HEIGHT - 32 && y < SCREEN_HEIGHT - 8) {
|
||||||
currentScreen = SCREEN_CUSTOMIZE_STOCKS;
|
currentScreen = SCREEN_CUSTOMIZE_STOCKS;
|
||||||
selectedStockSlot = -1;
|
selectedStockSlot = -1;
|
||||||
keyboardPos = 0;
|
keyboardPos = 0;
|
||||||
|
|
@ -1322,7 +1917,12 @@ void setup() {
|
||||||
|
|
||||||
lcd.init();
|
lcd.init();
|
||||||
lcd.setBrightness(255);
|
lcd.setBrightness(255);
|
||||||
lcd.setRotation(0);
|
|
||||||
|
preferences.begin("dashboard", true);
|
||||||
|
displayFlipped = preferences.getBool("flipped", false);
|
||||||
|
preferences.end();
|
||||||
|
|
||||||
|
lcd.setRotation(displayFlipped ? 2 : 0);
|
||||||
|
|
||||||
lcd.fillScreen(TFT_WHITE);
|
lcd.fillScreen(TFT_WHITE);
|
||||||
delay(250);
|
delay(250);
|
||||||
|
|
@ -1420,6 +2020,9 @@ void loop() {
|
||||||
case SCREEN_WIFI_PASSWORD:
|
case SCREEN_WIFI_PASSWORD:
|
||||||
handleWifiPasswordTouch(x, y);
|
handleWifiPasswordTouch(x, y);
|
||||||
break;
|
break;
|
||||||
|
case SCREEN_HARD_MONEY_DETAIL:
|
||||||
|
handleHardMoneyTouch(x, y);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needsRefresh) {
|
if (!needsRefresh) {
|
||||||
|
|
@ -1441,6 +2044,9 @@ void loop() {
|
||||||
case SCREEN_WIFI_PASSWORD:
|
case SCREEN_WIFI_PASSWORD:
|
||||||
drawWifiPasswordScreen();
|
drawWifiPasswordScreen();
|
||||||
break;
|
break;
|
||||||
|
case SCREEN_HARD_MONEY_DETAIL:
|
||||||
|
drawHardMoneyDetailScreen();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1453,9 +2059,25 @@ void loop() {
|
||||||
drawFooterCountdown();
|
drawFooterCountdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentScreen == SCREEN_HARD_MONEY_DETAIL) {
|
||||||
|
if (hmNeedsRefresh || !btcHmLoaded || !goldHmLoaded || !silverHmLoaded) {
|
||||||
|
hmNeedsRefresh = false;
|
||||||
|
drawHardMoneyDetailScreen();
|
||||||
|
fetchAllHmData(hmSparklinePeriod);
|
||||||
|
drawHardMoneyDetailScreen();
|
||||||
|
}
|
||||||
|
if (millis() - hmLastFetch > HM_FETCH_INTERVAL) {
|
||||||
|
fetchAllHmData(hmSparklinePeriod);
|
||||||
|
drawHardMoneyDetailScreen();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wifiConnecting) {
|
if (wifiConnecting) {
|
||||||
if (WiFi.status() == WL_CONNECTED) {
|
if (WiFi.status() == WL_CONNECTED) {
|
||||||
wifiConnecting = false;
|
wifiConnecting = false;
|
||||||
|
if (!timeSynced) {
|
||||||
|
syncTime();
|
||||||
|
}
|
||||||
if (currentScreen == SCREEN_DASHBOARD) {
|
if (currentScreen == SCREEN_DASHBOARD) {
|
||||||
drawDashboard();
|
drawDashboard();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue