Fix UI error, use paged updates for EPDs

This commit is contained in:
Djuri Baars 2023-11-08 20:29:06 +01:00
parent 902b35d11e
commit 0541a7759f
13 changed files with 225 additions and 100 deletions

View file

@ -59,11 +59,11 @@
</div> </div>
<hr> <hr>
<div> <div>
<div class="progress" role="progressbar" aria-label="Memory usage" aria-valuenow="{{ memUsage }}" aria-valuemin="0" aria-valuemax="100"> <div class="progress" role="progressbar" aria-label="Memory free" aria-valuenow="{{ memFreePercent }}" aria-valuemin="0" aria-valuemax="100">
<div class="progress-bar progress-bar-striped" style="width: {{ memUsage }}%">{{ memUsage }}%</div> <div class="progress-bar progress-bar-striped" style="width: {{ memFreePercent }}%">{{ memFreePercent }}%</div>
</div> </div>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div>Memory usage</div> <div>Memory free</div>
<div>{{ memFree }} / {{ memTotal }} KiB</div> <div>{{ memFree }} / {{ memTotal }} KiB</div>
</div> </div>
</div> </div>

View file

@ -25,7 +25,7 @@ let processStatusData = (jsonData) => {
var context = { var context = {
timerRunning: jsonData.timerRunning, timerRunning: jsonData.timerRunning,
memUsage: Math.round(jsonData.espFreeHeap / jsonData.espHeapSize * 100), memFreePercent: Math.round(jsonData.espFreeHeap / jsonData.espHeapSize * 100),
memFree: Math.round(jsonData.espFreeHeap / 1024), memFree: Math.round(jsonData.espFreeHeap / 1024),
memTotal: Math.round(jsonData.espHeapSize / 1024), memTotal: Math.round(jsonData.espHeapSize / 1024),
uptime: toTime(jsonData.espUptime), uptime: toTime(jsonData.espUptime),

View file

@ -16,12 +16,11 @@ void setupBlockNotify()
if (dnsErr != 1) { if (dnsErr != 1) {
Serial.print(mempoolInstance); Serial.print(mempoolInstance);
Serial.println("mempool DNS could not be resolved"); Serial.println(F("mempool DNS could not be resolved"));
WiFi.reconnect(); WiFi.reconnect();
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
} }
} }
Serial.println("mempool DNS can be resolved");
// Get current block height through regular API // Get current block height through regular API
HTTPClient *http = new HTTPClient(); HTTPClient *http = new HTTPClient();
@ -41,8 +40,6 @@ void setupBlockNotify()
.uri = "wss://mempool.bitcoin.nl/api/v1/ws", .uri = "wss://mempool.bitcoin.nl/api/v1/ws",
}; };
Serial.printf("Connecting to %s\r\n", config.uri);
blockNotifyClient = esp_websocket_client_init(&config); blockNotifyClient = esp_websocket_client_init(&config);
esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, blockNotifyClient); esp_websocket_register_events(blockNotifyClient, WEBSOCKET_EVENT_ANY, onWebsocketEvent, blockNotifyClient);
esp_websocket_client_start(blockNotifyClient); esp_websocket_client_start(blockNotifyClient);
@ -51,17 +48,15 @@ void setupBlockNotify()
void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{ {
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
String init; const char sub[38] = "{\"action\": \"want\", \"data\":[\"blocks\"]}";
String sub;
switch (event_id) switch (event_id)
{ {
case WEBSOCKET_EVENT_CONNECTED: case WEBSOCKET_EVENT_CONNECTED:
Serial.println("Connected to Mempool.space WebSocket"); Serial.println(F("Connected to Mempool.space WebSocket"));
sub = "{\"action\": \"want\", \"data\":[\"blocks\"]}"; if (esp_websocket_client_send_text(blockNotifyClient, sub, 38, portMAX_DELAY) == -1)
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(), sub.length(), portMAX_DELAY) == -1)
{ {
Serial.println("Mempool.space WS Block Subscribe Error"); Serial.println(F("Mempool.space WS Block Subscribe Error"));
} }
break; break;
@ -70,10 +65,10 @@ void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_i
// Handle the received WebSocket message (block notifications) here // Handle the received WebSocket message (block notifications) here
break; break;
case WEBSOCKET_EVENT_ERROR: case WEBSOCKET_EVENT_ERROR:
Serial.println("Mempool.space WS Connnection error"); Serial.println(F("Mempool.space WS Connnection error"));
break; break;
case WEBSOCKET_EVENT_DISCONNECTED: case WEBSOCKET_EVENT_DISCONNECTED:
Serial.println("Mempool.space WS Connnection Closed"); Serial.println(F("Mempool.space WS Connnection Closed"));
break; break;
} }
} }
@ -83,19 +78,17 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
SpiRamJsonDocument doc(event_data->data_len); SpiRamJsonDocument doc(event_data->data_len);
deserializeJson(doc, (char *)event_data->data_ptr); deserializeJson(doc, (char *)event_data->data_ptr);
// serializeJsonPretty(doc, Serial);
if (doc.containsKey("block")) if (doc.containsKey("block"))
{ {
JsonObject block = doc["block"]; JsonObject block = doc["block"];
currentBlockHeight = block["height"].as<long>(); currentBlockHeight = block["height"].as<long>();
Serial.print("New block found: ");
Serial.println(block["height"].as<long>());
if (blockUpdateTaskHandle != nullptr) { if (blockUpdateTaskHandle != nullptr) {
xTaskNotifyGive(blockUpdateTaskHandle); xTaskNotifyGive(blockUpdateTaskHandle);
if (preferences.getBool("ledFlashOnUpd", false)) { if (preferences.getBool("ledFlashOnUpd", false)) {
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
queueLedEffect(LED_FLASH_BLOCK_NOTIFY); queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
} }

View file

@ -6,7 +6,7 @@
Preferences preferences; Preferences preferences;
Adafruit_MCP23X17 mcp; Adafruit_MCP23X17 mcp;
std::map<int, std::string> screenNameMap; std::vector<std::string> screenNameMap(SCREEN_COUNT);
void setup() void setup()
{ {
@ -90,11 +90,11 @@ 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));
screenNameMap = {{SCREEN_BLOCK_HEIGHT, "Block Height"}, screenNameMap[SCREEN_BLOCK_HEIGHT] = "Block Height";
{SCREEN_MSCW_TIME, "Sats per dollar"}, screenNameMap[SCREEN_MSCW_TIME] = "Sats per dollar";
{SCREEN_BTC_TICKER, "Ticker"}, screenNameMap[SCREEN_BTC_TICKER] = "Ticker";
{SCREEN_TIME, "Time"}, screenNameMap[SCREEN_TIME] = "Time";
{SCREEN_HALVING_COUNTDOWN, "Halving countdown"}}; screenNameMap[SCREEN_HALVING_COUNTDOWN] = "Halving countdown";
} }
void setupWebsocketClients() void setupWebsocketClients()
@ -105,8 +105,8 @@ void setupWebsocketClients()
void setupTimers() void setupTimers()
{ {
xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 4096, NULL, 1, NULL); xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL, 1, NULL);
xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 4096, NULL, 1, NULL); xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL, 1, NULL);
} }
void finishSetup() void finishSetup()
@ -120,7 +120,7 @@ void finishSetup()
} }
std::map<int, std::string> getScreenNameMap() { std::vector<std::string> getScreenNameMap() {
return screenNameMap; return screenNameMap;
} }

View file

@ -44,7 +44,7 @@ void setupHardware();
void tryImprovSetup(); void tryImprovSetup();
void setupTimers(); void setupTimers();
void finishSetup(); void finishSetup();
std::map<int, std::string> getScreenNameMap(); std::vector<std::string> getScreenNameMap();
std::vector<std::string> getLocalUrl(); std::vector<std::string> getLocalUrl();
bool improv_connectWifi(std::string ssid, std::string password); bool improv_connectWifi(std::string ssid, std::string password);

View file

@ -53,6 +53,8 @@ std::array<String, NUM_SCREENS> currentEpdContent;
std::array<String, NUM_SCREENS> epdContent; std::array<String, NUM_SCREENS> epdContent;
uint32_t lastFullRefresh[NUM_SCREENS]; uint32_t lastFullRefresh[NUM_SCREENS];
TaskHandle_t tasks[NUM_SCREENS]; TaskHandle_t tasks[NUM_SCREENS];
TaskHandle_t epdTaskHandle = NULL;
SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS]; SemaphoreHandle_t epdUpdateSemaphore[NUM_SCREENS];
int fgColor = GxEPD_WHITE; int fgColor = GxEPD_WHITE;
@ -76,9 +78,11 @@ void setupDisplays()
int *taskParam = new int; int *taskParam = new int;
*taskParam = i; *taskParam = i;
xTaskCreate(updateDisplay, "EpdUpd" + char(i), 4096, taskParam, tskIDLE_PRIORITY, &tasks[i]); // create task xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 4096, taskParam, tskIDLE_PRIORITY, &tasks[i]); // create task
} }
xTaskCreate(taskEpd, "epd_task", 2048, NULL, tskIDLE_PRIORITY, &epdTaskHandle);
epdContent = {"B", epdContent = {"B",
"T", "T",
"C", "C",
@ -86,18 +90,20 @@ void setupDisplays()
"O", "O",
"C", "C",
"K"}; "K"};
for (uint i = 0; i < NUM_SCREENS; i++)
{
xTaskNotifyGive(tasks[i]);
}
xTaskCreate(taskEpd, "epd_task", 2048, NULL, tskIDLE_PRIORITY, NULL); setEpdContent(epdContent);
// for (uint i = 0; i < NUM_SCREENS; i++)
// {
// xTaskNotifyGive(tasks[i]);
// }
} }
void taskEpd(void *pvParameters) void taskEpd(void *pvParameters)
{ {
while (1) while (1)
{ {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
bool updatedThisCycle = false; bool updatedThisCycle = false;
for (uint i = 0; i < NUM_SCREENS; i++) for (uint i = 0; i < NUM_SCREENS; i++)
@ -127,13 +133,17 @@ void taskEpd(void *pvParameters)
} }
#endif #endif
vTaskDelay(pdMS_TO_TICKS(1000)); // vTaskDelay(pdMS_TO_TICKS(1000));
} }
} }
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent) void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
{ {
epdContent = newEpdContent; epdContent = newEpdContent;
if (epdTaskHandle != NULL)
xTaskNotifyGive(epdTaskHandle);
if (eventSourceTaskHandle != NULL)
xTaskNotifyGive(eventSourceTaskHandle);
} }
extern "C" void updateDisplay(void *pvParameters) noexcept extern "C" void updateDisplay(void *pvParameters) noexcept
@ -151,9 +161,11 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
displays[epdIndex].init(0, false); // Little longer reset duration because of MCP displays[epdIndex].init(0, false); // Little longer reset duration because of MCP
uint count = 0; uint count = 0;
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) { while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10)
{
vTaskDelay(pdMS_TO_TICKS(100)); vTaskDelay(pdMS_TO_TICKS(100));
if (count >= 9) { if (count >= 9)
{
displays[epdIndex].init(0, false); displays[epdIndex].init(0, false);
} }
count++; count++;
@ -167,35 +179,48 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
updatePartial = false; updatePartial = false;
lastFullRefresh[epdIndex] = millis(); lastFullRefresh[epdIndex] = millis();
} }
// if (updatePartial)
// {
// displays[epdIndex].setPartialWindow(0, 0, displays[i].width(), display[i].height());
// }
if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) if (strstr(epdContent[epdIndex].c_str(), "/") != NULL)
{ {
String top = epdContent[epdIndex].substring(0, epdContent[epdIndex].indexOf("/")); String top = epdContent[epdIndex].substring(0, epdContent[epdIndex].indexOf("/"));
String bottom = epdContent[epdIndex].substring(epdContent[epdIndex].indexOf("/") + 1); String bottom = epdContent[epdIndex].substring(epdContent[epdIndex].indexOf("/") + 1);
splitText(epdIndex, top, bottom, updatePartial); splitTextPaged(epdIndex, top, bottom, updatePartial);
} }
else else
{ {
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); // displays[epdIndex].drawPaged([&epdIndex, &updatePartial](const void *data)
// { showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG); },
// 0);
showDigitPaged(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
} }
char tries = 0; // char tries = 0;
while (tries < 3) // while (tries < 3)
{ // {
if (displays[epdIndex].displayWithReturn(updatePartial)) // if (displays[epdIndex].displayWithReturn(updatePartial))
{ // {
displays[epdIndex].hibernate(); // displays[epdIndex].hibernate();
currentEpdContent[epdIndex] = epdContent[epdIndex]; currentEpdContent[epdIndex] = epdContent[epdIndex];
break; // break;
} // }
vTaskDelay(pdMS_TO_TICKS(100)); // vTaskDelay(pdMS_TO_TICKS(100));
tries++; // tries++;
} // }
} }
xSemaphoreGive(epdUpdateSemaphore[epdIndex]); xSemaphoreGive(epdUpdateSemaphore[epdIndex]);
} }
} }
void updateDisplayAlt(int epdIndex)
{
}
void splitText(const uint dispNum, String top, String bottom, bool partial) void splitText(const uint dispNum, String top, String bottom, bool partial)
{ {
displays[dispNum].setRotation(2); displays[dispNum].setRotation(2);
@ -232,6 +257,55 @@ void splitText(const uint dispNum, String top, String bottom, bool partial)
displays[dispNum].print(bottom); displays[dispNum].print(bottom);
} }
void splitTextPaged(const uint dispNum, String top, String bottom, bool partial)
{
displays[dispNum].setRotation(2);
displays[dispNum].setFont(&FONT_SMALL);
displays[dispNum].setTextColor(getFgColor());
// Top text
int16_t ttbx, ttby;
uint16_t ttbw, ttbh;
displays[dispNum].getTextBounds(top, 0, 0, &ttbx, &ttby, &ttbw, &ttbh);
uint16_t tx = ((displays[dispNum].width() - ttbw) / 2) - ttbx;
uint16_t ty = ((displays[dispNum].height() - ttbh) / 2) - ttby - ttbh / 2 - 12;
// Bottom text
int16_t tbbx, tbby;
uint16_t tbbw, tbbh;
displays[dispNum].getTextBounds(bottom, 0, 0, &tbbx, &tbby, &tbbw, &tbbh);
uint16_t bx = ((displays[dispNum].width() - tbbw) / 2) - tbbx;
uint16_t by = ((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
// Make separator as wide as the shortest text.
uint16_t lineWidth, lineX;
if (tbbw < ttbh)
lineWidth = tbbw;
else
lineWidth = ttbw;
lineX = round((displays[dispNum].width() - lineWidth) / 2);
if (partial)
{
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height());
}
else
{
displays[dispNum].setFullWindow();
}
displays[dispNum].firstPage();
do
{
displays[dispNum].fillScreen(getBgColor());
displays[dispNum].setCursor(tx, ty);
displays[dispNum].print(top);
displays[dispNum].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3, lineWidth, 6, 3, getFgColor());
displays[dispNum].setCursor(bx, by);
displays[dispNum].print(bottom);
} while (displays[dispNum].nextPage());
}
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font) void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
{ {
String str(chr); String str(chr);
@ -249,6 +323,36 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
displays[dispNum].print(str); displays[dispNum].print(str);
} }
void showDigitPaged(const uint dispNum, char chr, bool partial, const GFXfont *font)
{
String str(chr);
displays[dispNum].setRotation(2);
displays[dispNum].setFont(font);
displays[dispNum].setTextColor(getFgColor());
int16_t tbx, tby;
uint16_t tbw, tbh;
displays[dispNum].getTextBounds(str, 0, 0, &tbx, &tby, &tbw, &tbh);
// center the bounding box by transposition of the origin:
uint16_t x = ((displays[dispNum].width() - tbw) / 2) - tbx;
uint16_t y = ((displays[dispNum].height() - tbh) / 2) - tby;
if (partial)
{
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height());
}
else
{
displays[dispNum].setFullWindow();
}
displays[dispNum].firstPage();
do
{
displays[dispNum].fillScreen(getBgColor());
displays[dispNum].setCursor(x, y);
displays[dispNum].print(str);
} while (displays[dispNum].nextPage());
}
int getBgColor() int getBgColor()
{ {
return bgColor; return bgColor;

View file

@ -11,8 +11,13 @@ void setupDisplays();
void taskEpd(void *pvParameters); void taskEpd(void *pvParameters);
void splitText(const uint dispNum, String top, String bottom, bool partial); void splitText(const uint dispNum, String top, String bottom, bool partial);
void splitTextPaged(const uint dispNum, String top, String bottom, bool partial);
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font); void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
void showDigitPaged(const uint dispNum, char chr, bool partial, const GFXfont *font);
extern "C" void updateDisplay(void *pvParameters) noexcept; extern "C" void updateDisplay(void *pvParameters) noexcept;
void updateDisplayAlt(int epdIndex);
int getBgColor(); int getBgColor();
int getFgColor(); int getFgColor();

View file

@ -52,6 +52,7 @@ void ledTask(void *parameter)
delay(100); delay(100);
} }
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
delay(900); delay(900);
@ -60,7 +61,7 @@ void ledTask(void *parameter)
break; break;
case LED_EFFECT_START_TIMER: case LED_EFFECT_START_TIMER:
pixels.clear(); pixels.clear();
pixels.setPixelColor(NEOPIXEL_COUNT, pixels.Color(0, 255, 0)); pixels.setPixelColor(NEOPIXEL_COUNT, pixels.Color(255, 0, 0));
pixels.show(); pixels.show();
delay(900); delay(900);
@ -113,9 +114,9 @@ void setupLeds()
void setupLedTask() void setupLedTask()
{ {
ledTaskQueue = xQueueCreate(10, sizeof(unsigned long)); ledTaskQueue = xQueueCreate(10, sizeof(char));
xTaskCreate(ledTask, "LedTask", 4096, NULL, tskIDLE_PRIORITY, &ledTaskHandle); xTaskCreate(ledTask, "LedTask", 2048, NULL, tskIDLE_PRIORITY, &ledTaskHandle);
} }
void blinkDelay(int d, int times) void blinkDelay(int d, int times)
@ -221,6 +222,6 @@ bool queueLedEffect(uint effect)
return false; return false;
} }
unsigned long flashType = effect; char flashType = effect;
xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY); xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY);
} }

View file

@ -20,21 +20,20 @@ void setupPriceNotify()
void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{ {
esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data; esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;
String init;
String sub;
switch (event_id) switch (event_id)
{ {
case WEBSOCKET_EVENT_CONNECTED: case WEBSOCKET_EVENT_CONNECTED:
Serial.println("Connected to CoinCap.io WebSocket"); Serial.println(F("Connected to CoinCap.io WebSocket"));
break; break;
case WEBSOCKET_EVENT_DATA: case WEBSOCKET_EVENT_DATA:
onWebsocketPriceMessage(data); onWebsocketPriceMessage(data);
break; break;
case WEBSOCKET_EVENT_ERROR: case WEBSOCKET_EVENT_ERROR:
Serial.println("Connnection error"); Serial.println(F("Price WS Connnection error"));
break; break;
case WEBSOCKET_EVENT_DISCONNECTED: case WEBSOCKET_EVENT_DISCONNECTED:
Serial.println("Connnection Closed"); Serial.println(F("Price WS Connnection Closed"));
break; break;
} }
} }

View file

@ -61,7 +61,7 @@ void taskScreenRotate(void *pvParameters)
{ {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
int nextScreen = (currentScreen+ 1) % 5; int nextScreen = (currentScreen + 1) % 5;
String key = "screen" + String(nextScreen) + "Visible"; String key = "screen" + String(nextScreen) + "Visible";
while (!preferences.getBool(key.c_str(), true)) while (!preferences.getBool(key.c_str(), true))
@ -115,7 +115,8 @@ void taskBlockUpdate(void *pvParameters)
taskEpdContent[(NUM_SCREENS - 1)] = "TO/GO"; taskEpdContent[(NUM_SCREENS - 1)] = "TO/GO";
} }
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || getCurrentScreen() == SCREEN_BLOCK_HEIGHT) { if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || getCurrentScreen() == SCREEN_BLOCK_HEIGHT)
{
setEpdContent(taskEpdContent); setEpdContent(taskEpdContent);
} }
} }
@ -217,7 +218,8 @@ void setupScreenRotateTimer(void *pvParameters)
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer); esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
if (preferences.getBool("timerActive", true)) { if (preferences.getBool("timerActive", true))
{
esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond); esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond);
} }
@ -248,9 +250,13 @@ void setTimerActive(bool status)
queueLedEffect(LED_EFFECT_PAUSE_TIMER); queueLedEffect(LED_EFFECT_PAUSE_TIMER);
preferences.putBool("timerActive", false); preferences.putBool("timerActive", false);
} }
if (eventSourceTaskHandle != NULL)
xTaskNotifyGive(eventSourceTaskHandle);
} }
void toggleTimerActive() { void toggleTimerActive()
{
setTimerActive(!isTimerActive()); setTimerActive(!isTimerActive());
} }
@ -282,6 +288,9 @@ void setCurrentScreen(uint newScreen)
xTaskNotifyGive(priceUpdateTaskHandle); xTaskNotifyGive(priceUpdateTaskHandle);
break; break;
} }
if (eventSourceTaskHandle != NULL)
xTaskNotifyGive(eventSourceTaskHandle);
} }
void nextScreen() void nextScreen()
@ -329,9 +338,9 @@ void showSystemStatusScreen()
ipAddr = ipAddr.substring(ipAddrPos); ipAddr = ipAddr.substring(ipAddrPos);
subNet = subNet.substring(subnetPos); subNet = subNet.substring(subnetPos);
} }
sysStatusEpdContent[NUM_SCREENS-2] = "RAM/Status"; sysStatusEpdContent[NUM_SCREENS - 2] = "RAM/Status";
sysStatusEpdContent[NUM_SCREENS-1] = String((int)round(ESP.getFreeHeap()/1024)) + "/" + (int)round(ESP.getHeapSize()/1024); sysStatusEpdContent[NUM_SCREENS - 1] = String((int)round(ESP.getFreeHeap() / 1024)) + "/" + (int)round(ESP.getHeapSize() / 1024);
setCurrentScreen(SCREEN_CUSTOM); setCurrentScreen(SCREEN_CUSTOM);
setEpdContent(sysStatusEpdContent); setEpdContent(sysStatusEpdContent);
} }

View file

@ -2,6 +2,7 @@
AsyncWebServer server(80); AsyncWebServer server(80);
AsyncEventSource events("/events"); AsyncEventSource events("/events");
TaskHandle_t eventSourceTaskHandle;
void setupWebserver() void setupWebserver()
{ {
@ -19,7 +20,7 @@ void setupWebserver()
} }
// send event with message "hello!", id current millis // send event with message "hello!", id current millis
// and set reconnect delay to 1 second // and set reconnect delay to 1 second
eventSourceLoop(); eventSourceUpdate();
}); });
server.addHandler(&events); server.addHandler(&events);
@ -66,6 +67,8 @@ void setupWebserver()
} }
} }
MDNS.addService("http", "tcp", 80); MDNS.addService("http", "tcp", 80);
xTaskCreate(eventSourceTask, "eventSourceTask", 4096, NULL, tskIDLE_PRIORITY, &eventSourceTaskHandle);
} }
StaticJsonDocument<768> getStatusObject() StaticJsonDocument<768> getStatusObject()
@ -76,12 +79,12 @@ StaticJsonDocument<768> getStatusObject()
root["numScreens"] = NUM_SCREENS; root["numScreens"] = NUM_SCREENS;
root["timerRunning"] = isTimerActive(); root["timerRunning"] = isTimerActive();
root["espUptime"] = esp_timer_get_time() / 1000000; root["espUptime"] = esp_timer_get_time() / 1000000;
root["currentPrice"] = getPrice(); // root["currentPrice"] = getPrice();
root["currentBlockHeight"] = getBlockHeight(); // root["currentBlockHeight"] = getBlockHeight();
root["espFreeHeap"] = ESP.getFreeHeap(); root["espFreeHeap"] = ESP.getFreeHeap();
root["espHeapSize"] = ESP.getHeapSize(); root["espHeapSize"] = ESP.getHeapSize();
root["espFreePsram"] = ESP.getFreePsram(); // root["espFreePsram"] = ESP.getFreePsram();
root["espPsramSize"] = ESP.getPsramSize(); // root["espPsramSize"] = ESP.getPsramSize();
JsonObject conStatus = root.createNestedObject("connectionStatus"); JsonObject conStatus = root.createNestedObject("connectionStatus");
conStatus["price"] = isPriceNotifyConnected(); conStatus["price"] = isPriceNotifyConnected();
@ -90,7 +93,7 @@ StaticJsonDocument<768> getStatusObject()
return root; return root;
} }
void eventSourceLoop() void eventSourceUpdate()
{ {
if (!events.count()) return; if (!events.count()) return;
StaticJsonDocument<768> root = getStatusObject(); StaticJsonDocument<768> root = getStatusObject();
@ -101,8 +104,6 @@ void eventSourceLoop()
copyArray(epdContent, data); copyArray(epdContent, data);
size_t bufSize = measureJson(root);
char buffer[bufSize];
String bufString; String bufString;
serializeJson(root, bufString); serializeJson(root, bufString);
@ -229,7 +230,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
#endif #endif
JsonArray screens = root.createNestedArray("screens"); JsonArray screens = root.createNestedArray("screens");
std::map<int, std::string> screenNameMap = getScreenNameMap(); std::vector<std::string> screenNameMap = getScreenNameMap();
for (int i = 0; i < screenNameMap.size(); i++) for (int i = 0; i < screenNameMap.size(); i++)
{ {
@ -274,7 +275,6 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
void onApiSettingsPost(AsyncWebServerRequest *request) void onApiSettingsPost(AsyncWebServerRequest *request)
{ {
int params = request->params();
bool settingsChanged = false; bool settingsChanged = false;
settingsChanged = processEpdColorSettings(request); settingsChanged = processEpdColorSettings(request);
@ -300,8 +300,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *mempoolInstance = request->getParam("mempoolInstance", true); AsyncWebParameter *mempoolInstance = request->getParam("mempoolInstance", true);
preferences.putString("mempoolInstance", mempoolInstance->value().c_str()); preferences.putString("mempoolInstance", mempoolInstance->value().c_str());
Serial.print("Setting mempool instance to "); Serial.printf("Setting mempool instance to %s\r\n", mempoolInstance->value().c_str());
Serial.println(mempoolInstance->value().c_str());
settingsChanged = true; settingsChanged = true;
} }
@ -310,8 +309,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true); AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);
preferences.putUInt("ledBrightness", ledBrightness->value().toInt()); preferences.putUInt("ledBrightness", ledBrightness->value().toInt());
Serial.print("Setting brightness to "); Serial.printf("Setting brightness to %d\r\n", ledBrightness->value().toInt());
Serial.println(ledBrightness->value().c_str());
settingsChanged = true; settingsChanged = true;
} }
@ -320,8 +318,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *fullRefreshMin = request->getParam("fullRefreshMin", true); AsyncWebParameter *fullRefreshMin = request->getParam("fullRefreshMin", true);
preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt()); preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt());
Serial.print("Set full refresh minutes to "); Serial.printf("Set full refresh minutes to %d\r\n",fullRefreshMin->value().toInt());
Serial.println(fullRefreshMin->value().c_str());
settingsChanged = true; settingsChanged = true;
} }
@ -330,12 +327,11 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true); AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true);
preferences.putUInt("wpTimeout", wpTimeout->value().toInt()); preferences.putUInt("wpTimeout", wpTimeout->value().toInt());
Serial.print("Set WiFi portal timeout seconds to "); Serial.printf("Set WiFi portal timeout seconds to %d\r\n", wpTimeout->value().toInt());
Serial.println(wpTimeout->value().c_str());
settingsChanged = true; settingsChanged = true;
} }
std::map<int, std::string> screenNameMap = getScreenNameMap(); std::vector<std::string> screenNameMap = getScreenNameMap();
for (int i = 0; i < screenNameMap.size(); i++) for (int i = 0; i < screenNameMap.size(); i++)
{ {
@ -347,8 +343,7 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *screenParam = request->getParam(key, true); AsyncWebParameter *screenParam = request->getParam(key, true);
visible = screenParam->value().toInt(); visible = screenParam->value().toInt();
} }
Serial.print("Setting screen " + String(i) + " to "); Serial.printf("Setting screen %d to %d\r\n", i, visible);
Serial.println(visible);
preferences.putBool(prefKey.c_str(), visible); preferences.putBool(prefKey.c_str(), visible);
} }
@ -358,18 +353,16 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
AsyncWebParameter *p = request->getParam("tzOffset", true); AsyncWebParameter *p = request->getParam("tzOffset", true);
int tzOffsetSeconds = p->value().toInt() * 60; int tzOffsetSeconds = p->value().toInt() * 60;
preferences.putInt("gmtOffset", tzOffsetSeconds); preferences.putInt("gmtOffset", tzOffsetSeconds);
Serial.print("Setting tz offset to "); Serial.printf("Setting tz offset to %d\r\n", tzOffsetSeconds);
Serial.println(tzOffsetSeconds);
settingsChanged = true; settingsChanged = true;
} }
if (request->hasParam("minSecPriceUpd", true)) if (request->hasParam("minSecPriceUpd", true))
{ {
AsyncWebParameter *p = request->getParam("minSecPriceUpd", true); AsyncWebParameter *p = request->getParam("minSecPriceUpd", true);
int minSecPriceUpd = p->value().toInt() * 60; int minSecPriceUpd = p->value().toInt();
preferences.putInt("minSecPriceUpd", minSecPriceUpd); preferences.putUInt("minSecPriceUpd", minSecPriceUpd);
Serial.print("Setting minSecPriceUpd "); Serial.printf("Setting minSecPriceUpd to %d\r\n", minSecPriceUpd);
Serial.println(minSecPriceUpd);
settingsChanged = true; settingsChanged = true;
} }
@ -465,3 +458,11 @@ void onNotFound(AsyncWebServerRequest *request)
request->send(404); request->send(404);
} }
}; };
void eventSourceTask(void *pvParameters) {
for (;;)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
eventSourceUpdate();
}
}

View file

@ -12,6 +12,8 @@
#include "webserver/OneParamRewrite.hpp" #include "webserver/OneParamRewrite.hpp"
extern TaskHandle_t eventSourceTaskHandle;
void setupWebserver(); void setupWebserver();
bool processEpdColorSettings(AsyncWebServerRequest *request); bool processEpdColorSettings(AsyncWebServerRequest *request);
@ -36,4 +38,5 @@ void onIndex(AsyncWebServerRequest *request);
void onNotFound(AsyncWebServerRequest *request); void onNotFound(AsyncWebServerRequest *request);
StaticJsonDocument<768> getStatusObject(); StaticJsonDocument<768> getStatusObject();
void eventSourceLoop(); void eventSourceUpdate();
void eventSourceTask(void *pvParameters);

View file

@ -1,6 +1,8 @@
#include "Arduino.h" #include "Arduino.h"
#include "lib/config.hpp" #include "lib/config.hpp"
//char ptrTaskList[400];
extern "C" void app_main() extern "C" void app_main()
{ {
initArduino(); initArduino();
@ -10,7 +12,15 @@ extern "C" void app_main()
while (true) while (true)
{ {
eventSourceLoop(); // vTaskList(ptrTaskList);
vTaskDelay(pdMS_TO_TICKS(2500)); // Serial.println(F("**********************************"));
// Serial.println(F("Task State Prio Stack Num"));
// Serial.println(F("**********************************"));
// Serial.print(ptrTaskList);
// Serial.println(F("**********************************"));
if (eventSourceTaskHandle != NULL)
xTaskNotifyGive(eventSourceTaskHandle);
vTaskDelay(pdMS_TO_TICKS(5000));
} }
} }