mirror of
https://github.com/btclock/btclock_v3.git
synced 2024-11-19 04:20:01 +01:00
Use clang to make codestyle consistent
This commit is contained in:
parent
239415c7aa
commit
4aab02a040
@ -1,3 +1,6 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t Antonio_SemiBold20pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x66, 0x66, 0x66,
|
||||
0x66, 0x66, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7B, 0xDE, 0xF7,
|
||||
@ -476,7 +479,6 @@ const GFXglyph Antonio_SemiBold20pt7bGlyphs[] PROGMEM = {
|
||||
|
||||
const GFXfont Antonio_SemiBold20pt7b PROGMEM = {
|
||||
(uint8_t *)Antonio_SemiBold20pt7bBitmaps,
|
||||
(GFXglyph *)Antonio_SemiBold20pt7bGlyphs,
|
||||
0x20, 0x7E, 51 };
|
||||
(GFXglyph *)Antonio_SemiBold20pt7bGlyphs, 0x20, 0x7E, 51};
|
||||
|
||||
// Approx. 5193 bytes
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t Antonio_SemiBold30pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xE7,
|
||||
0xCF, 0x9F, 0x3E, 0x7C, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3E, 0x7C, 0xF9,
|
||||
@ -948,7 +951,6 @@ const GFXglyph Antonio_SemiBold30pt7bGlyphs[] PROGMEM = {
|
||||
|
||||
const GFXfont Antonio_SemiBold30pt7b PROGMEM = {
|
||||
(uint8_t *)Antonio_SemiBold30pt7bBitmaps,
|
||||
(GFXglyph *)Antonio_SemiBold30pt7bGlyphs,
|
||||
0x20, 0x7E, 76 };
|
||||
(GFXglyph *)Antonio_SemiBold30pt7bGlyphs, 0x20, 0x7E, 76};
|
||||
|
||||
// Approx. 10860 bytes
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t Antonio_SemiBold40pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF9, 0xFE, 0x7F,
|
||||
0x9F, 0xE7, 0xF9, 0xFE, 0x7F, 0x9F, 0xE7, 0xF9, 0xFE, 0x7F, 0x9F, 0xE7,
|
||||
@ -1624,7 +1627,6 @@ const GFXglyph Antonio_SemiBold40pt7bGlyphs[] PROGMEM = {
|
||||
|
||||
const GFXfont Antonio_SemiBold40pt7b PROGMEM = {
|
||||
(uint8_t *)Antonio_SemiBold40pt7bBitmaps,
|
||||
(GFXglyph *)Antonio_SemiBold40pt7bGlyphs,
|
||||
0x20, 0x7E, 101 };
|
||||
(GFXglyph *)Antonio_SemiBold40pt7bGlyphs, 0x20, 0x7E, 101};
|
||||
|
||||
// Approx. 18961 bytes
|
||||
|
@ -1,3 +1,6 @@
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
const uint8_t Antonio_SemiBold90pt7bBitmaps[] PROGMEM = {
|
||||
0x00, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF,
|
||||
0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0x7F,
|
||||
@ -5087,11 +5090,11 @@ const GFXglyph Antonio_SemiBold90pt7bGlyphs[] PROGMEM = {
|
||||
{53398, 108, 151, 116, 4, 106}, // 0x57 'W'
|
||||
{55437, 64, 151, 72, 4, 106}, // 0x58 'X'
|
||||
{56645, 71, 151, 73, 1, 106}, // 0x59 'Y'
|
||||
{ 57986, 52, 151, 61, 6, 106 }, { 58968, 70, 155, 84, 5, 104 } }; // 0x5A 'Z'
|
||||
{57986, 52, 151, 61, 6, 106},
|
||||
{58968, 70, 155, 84, 5, 104}}; // 0x5A 'Z'
|
||||
|
||||
const GFXfont Antonio_SemiBold90pt7b PROGMEM = {
|
||||
(uint8_t *)Antonio_SemiBold90pt7bBitmaps,
|
||||
(GFXglyph *)Antonio_SemiBold90pt7bGlyphs,
|
||||
0x20, 0x5B, 228 };
|
||||
(GFXglyph *)Antonio_SemiBold90pt7bGlyphs, 0x20, 0x5B, 228};
|
||||
|
||||
// Approx. 60745 bytes
|
||||
|
@ -48,21 +48,19 @@ uint currentBlockHeight = 816000;
|
||||
// ew==
|
||||
// -----END CERTIFICATE-----)";
|
||||
|
||||
void setupBlockNotify()
|
||||
{
|
||||
void setupBlockNotify() {
|
||||
// currentBlockHeight = preferences.getUInt("blockHeight", 816000);
|
||||
|
||||
IPAddress result;
|
||||
|
||||
int dnsErr = -1;
|
||||
String mempoolInstance = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
String mempoolInstance =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
|
||||
while (dnsErr != 1)
|
||||
{
|
||||
while (dnsErr != 1) {
|
||||
dnsErr = WiFi.hostByName(mempoolInstance.c_str(), result);
|
||||
|
||||
if (dnsErr != 1)
|
||||
{
|
||||
if (dnsErr != 1) {
|
||||
Serial.print(mempoolInstance);
|
||||
Serial.println(F("mempool DNS could not be resolved"));
|
||||
WiFi.reconnect();
|
||||
@ -75,19 +73,18 @@ void setupBlockNotify()
|
||||
http->begin("https://" + mempoolInstance + "/api/blocks/tip/height");
|
||||
int httpCode = http->GET();
|
||||
|
||||
if (httpCode > 0 && httpCode == HTTP_CODE_OK)
|
||||
{
|
||||
if (httpCode > 0 && httpCode == HTTP_CODE_OK) {
|
||||
String blockHeightStr = http->getString();
|
||||
currentBlockHeight = blockHeightStr.toInt();
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
if (workQueue != nullptr) {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
// std::strcpy(wsServer, String("wss://" + mempoolInstance + "/api/v1/ws").c_str());
|
||||
// std::strcpy(wsServer, String("wss://" + mempoolInstance +
|
||||
// "/api/v1/ws").c_str());
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.uri = "wss://mempool.space/api/v1/ws",
|
||||
@ -97,22 +94,22 @@ void setupBlockNotify()
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
const String sub = "{\"action\": \"want\", \"data\":[\"blocks\"]}";
|
||||
switch (event_id)
|
||||
{
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
Serial.println(F("Connected to Mempool.space WebSocket"));
|
||||
|
||||
Serial.println(sub);
|
||||
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(), sub.length(), portMAX_DELAY) == -1)
|
||||
{
|
||||
if (esp_websocket_client_send_text(blockNotifyClient, sub.c_str(),
|
||||
sub.length(), portMAX_DELAY) == -1) {
|
||||
Serial.println(F("Mempool.space WS Block Subscribe Error"));
|
||||
}
|
||||
|
||||
@ -129,14 +126,12 @@ void onWebsocketEvent(void *handler_args, esp_event_base_t base, int32_t event_i
|
||||
}
|
||||
}
|
||||
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
||||
{
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *event_data) {
|
||||
SpiRamJsonDocument doc(event_data->data_len);
|
||||
|
||||
deserializeJson(doc, (char *)event_data->data_ptr);
|
||||
|
||||
if (doc.containsKey("block"))
|
||||
{
|
||||
if (doc.containsKey("block")) {
|
||||
JsonObject block = doc["block"];
|
||||
|
||||
currentBlockHeight = block["height"].as<uint>();
|
||||
@ -144,14 +139,13 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
||||
Serial.printf("New block found: %d\r\n", block["height"].as<uint>());
|
||||
preferences.putUInt("blockHeight", currentBlockHeight);
|
||||
|
||||
if (workQueue != nullptr)
|
||||
{
|
||||
if (workQueue != nullptr) {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
|
||||
if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT && preferences.getBool("stealFocus", true))
|
||||
{
|
||||
if (getCurrentScreen() != SCREEN_BLOCK_HEIGHT &&
|
||||
preferences.getBool("stealFocus", true)) {
|
||||
uint64_t timerPeriod = 0;
|
||||
if (isTimerActive()) {
|
||||
// store timer periode before making inactive to prevent artifacts
|
||||
@ -160,12 +154,13 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
||||
}
|
||||
setCurrentScreen(SCREEN_BLOCK_HEIGHT);
|
||||
if (timerPeriod > 0) {
|
||||
esp_timer_start_periodic(screenRotateTimer, timerPeriod * usPerSecond);
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
timerPeriod * usPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT && preferences.getBool("ledFlashOnUpd", false))
|
||||
{
|
||||
if (getCurrentScreen() == SCREEN_BLOCK_HEIGHT &&
|
||||
preferences.getBool("ledFlashOnUpd", false)) {
|
||||
vTaskDelay(pdMS_TO_TICKS(250)); // Wait until screens are updated
|
||||
queueLedEffect(LED_FLASH_BLOCK_NOTIFY);
|
||||
}
|
||||
@ -175,25 +170,19 @@ void onWebsocketMessage(esp_websocket_event_data_t *event_data)
|
||||
doc.clear();
|
||||
}
|
||||
|
||||
uint getBlockHeight()
|
||||
{
|
||||
return currentBlockHeight;
|
||||
}
|
||||
uint getBlockHeight() { return currentBlockHeight; }
|
||||
|
||||
void setBlockHeight(uint newBlockHeight)
|
||||
{
|
||||
void setBlockHeight(uint newBlockHeight) {
|
||||
currentBlockHeight = newBlockHeight;
|
||||
}
|
||||
|
||||
bool isBlockNotifyConnected()
|
||||
{
|
||||
bool isBlockNotifyConnected() {
|
||||
if (blockNotifyClient == NULL)
|
||||
return false;
|
||||
return esp_websocket_client_is_connected(blockNotifyClient);
|
||||
}
|
||||
|
||||
void stopBlockNotify()
|
||||
{
|
||||
void stopBlockNotify() {
|
||||
esp_websocket_client_stop(blockNotifyClient);
|
||||
esp_websocket_client_destroy(blockNotifyClient);
|
||||
}
|
@ -1,21 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include "shared.hpp"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_websocket_client.h"
|
||||
#include "screen_handler.hpp"
|
||||
#include "led_handler.hpp"
|
||||
#include <HTTPClient.h>
|
||||
#include <cstring>
|
||||
#include <esp_timer.h>
|
||||
#include <esp_websocket_client.h>
|
||||
#include <string>
|
||||
|
||||
// using namespace websockets;
|
||||
|
||||
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);
|
||||
void onWebsocketMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
void setBlockHeight(uint newBlockHeight);
|
||||
|
@ -4,24 +4,19 @@ TaskHandle_t buttonTaskHandle = NULL;
|
||||
const TickType_t debounceDelay = pdMS_TO_TICKS(50);
|
||||
TickType_t lastDebounceTime = 0;
|
||||
|
||||
void buttonTask(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
void buttonTask(void *parameter) {
|
||||
while (1) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
std::lock_guard<std::mutex> lock(mcpMutex);
|
||||
|
||||
TickType_t currentTime = xTaskGetTickCount();
|
||||
if ((currentTime - lastDebounceTime) >= debounceDelay)
|
||||
{
|
||||
if ((currentTime - lastDebounceTime) >= debounceDelay) {
|
||||
lastDebounceTime = currentTime;
|
||||
|
||||
if (!digitalRead(MCP_INT_PIN))
|
||||
{
|
||||
if (!digitalRead(MCP_INT_PIN)) {
|
||||
uint pin = mcp1.getLastInterruptPin();
|
||||
|
||||
switch (pin)
|
||||
{
|
||||
switch (pin) {
|
||||
case 3:
|
||||
toggleTimerActive();
|
||||
break;
|
||||
@ -37,31 +32,26 @@ void buttonTask(void *parameter)
|
||||
}
|
||||
}
|
||||
mcp1.clearInterrupts();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
}
|
||||
// Very ugly, but for some reason this is necessary
|
||||
while (!digitalRead(MCP_INT_PIN))
|
||||
{
|
||||
while (!digitalRead(MCP_INT_PIN)) {
|
||||
mcp1.clearInterrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR handleButtonInterrupt()
|
||||
{
|
||||
void IRAM_ATTR handleButtonInterrupt() {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xTaskNotifyFromISR(buttonTaskHandle, 0, eNoAction, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
||||
{
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void setupButtonTask()
|
||||
{
|
||||
xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, tskIDLE_PRIORITY, &buttonTaskHandle); // Create the FreeRTOS task
|
||||
void setupButtonTask() {
|
||||
xTaskCreate(buttonTask, "ButtonTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&buttonTaskHandle); // Create the FreeRTOS task
|
||||
// Use interrupt instead of task
|
||||
attachInterrupt(MCP_INT_PIN, handleButtonInterrupt, CHANGE);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include <Arduino.h>
|
||||
#include "shared.hpp"
|
||||
#include "screen_handler.hpp"
|
||||
|
||||
extern TaskHandle_t buttonTaskHandle;
|
||||
|
||||
|
@ -10,19 +10,16 @@ Adafruit_MCP23X17 mcp2;
|
||||
std::vector<std::string> screenNameMap(SCREEN_COUNT);
|
||||
std::mutex mcpMutex;
|
||||
|
||||
void setup()
|
||||
{
|
||||
void setup() {
|
||||
setupPreferences();
|
||||
setupHardware();
|
||||
setupDisplays();
|
||||
if (preferences.getBool("ledTestOnPower", true))
|
||||
{
|
||||
if (preferences.getBool("ledTestOnPower", true)) {
|
||||
queueLedEffect(LED_POWER_TEST);
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
if (mcp1.digitalRead(3) == LOW)
|
||||
{
|
||||
if (mcp1.digitalRead(3) == LOW) {
|
||||
preferences.putBool("wifiConfigured", false);
|
||||
preferences.remove("txPower");
|
||||
|
||||
@ -42,7 +39,8 @@ void setup()
|
||||
setupTasks();
|
||||
setupTimers();
|
||||
|
||||
xTaskCreate(setupWebsocketClients, "setupWebsocketClients", 4096, NULL, tskIDLE_PRIORITY, NULL);
|
||||
xTaskCreate(setupWebsocketClients, "setupWebsocketClients", 4096, NULL,
|
||||
tskIDLE_PRIORITY, NULL);
|
||||
|
||||
setupButtonTask();
|
||||
setupOTA();
|
||||
@ -51,13 +49,10 @@ void setup()
|
||||
forceFullRefresh();
|
||||
}
|
||||
|
||||
void tryImprovSetup()
|
||||
{
|
||||
void tryImprovSetup() {
|
||||
WiFi.onEvent(WiFiEvent);
|
||||
|
||||
|
||||
if (!preferences.getBool("wifiConfigured", false))
|
||||
{
|
||||
if (!preferences.getBool("wifiConfigured", false)) {
|
||||
setFgColor(GxEPD_BLACK);
|
||||
setBgColor(GxEPD_WHITE);
|
||||
queueLedEffect(LED_EFFECT_WIFI_WAIT_FOR_CONFIG);
|
||||
@ -76,42 +71,59 @@ void tryImprovSetup()
|
||||
|
||||
byte mac[6];
|
||||
WiFi.macAddress(mac);
|
||||
String softAP_SSID = String("BTClock" + String(mac[5], 16) + String(mac[1], 16));
|
||||
String softAP_SSID =
|
||||
String("BTClock" + String(mac[5], 16) + String(mac[1], 16));
|
||||
WiFi.setHostname(softAP_SSID.c_str());
|
||||
String softAP_password = base64::encode(String(mac[2], 16) + String(mac[4], 16) + String(mac[5], 16) + String(mac[1], 16)).substring(2, 10);
|
||||
String softAP_password =
|
||||
base64::encode(String(mac[2], 16) + String(mac[4], 16) +
|
||||
String(mac[5], 16) + String(mac[1], 16))
|
||||
.substring(2, 10);
|
||||
|
||||
// wm.setConfigPortalTimeout(preferences.getUInt("wpTimeout", 600));
|
||||
wm.setWiFiAutoReconnect(false);
|
||||
wm.setDebugOutput(false);
|
||||
wm.setConfigPortalBlocking(true);
|
||||
|
||||
wm.setAPCallback([&](WiFiManager *wifiManager)
|
||||
{
|
||||
|
||||
wm.setAPCallback([&](WiFiManager *wifiManager) {
|
||||
// Serial.printf("Entered config mode:ip=%s, ssid='%s', pass='%s'\n",
|
||||
// WiFi.softAPIP().toString().c_str(),
|
||||
// wifiManager->getConfigPortalSSID().c_str(),
|
||||
// softAP_password.c_str());
|
||||
// delay(6000);
|
||||
|
||||
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() + ";T:WPA;P:" + softAP_password.c_str() + ";;";
|
||||
const String explainText = "*SSID: *\r\n" + wifiManager->getConfigPortalSSID() + "\r\n\r\n*Password:*\r\n" + softAP_password;
|
||||
std::array<String, NUM_SCREENS> epdContent = {"Welcome!", "Bienvenidos!", "To setup\r\nscan QR or\r\nconnect\r\nmanually", "Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente", explainText, " ", qrText};
|
||||
setEpdContent(epdContent); });
|
||||
const String qrText = "qrWIFI:S:" + wifiManager->getConfigPortalSSID() +
|
||||
";T:WPA;P:" + softAP_password.c_str() + ";;";
|
||||
const String explainText = "*SSID: *\r\n" +
|
||||
wifiManager->getConfigPortalSSID() +
|
||||
"\r\n\r\n*Password:*\r\n" + softAP_password;
|
||||
std::array<String, NUM_SCREENS> epdContent = {
|
||||
"Welcome!",
|
||||
"Bienvenidos!",
|
||||
"To setup\r\nscan QR or\r\nconnect\r\nmanually",
|
||||
"Para\r\nconfigurar\r\nescanear QR\r\no conectar\r\nmanualmente",
|
||||
explainText,
|
||||
" ",
|
||||
qrText};
|
||||
setEpdContent(epdContent);
|
||||
});
|
||||
|
||||
wm.setSaveConfigCallback([]()
|
||||
{
|
||||
wm.setSaveConfigCallback([]() {
|
||||
preferences.putBool("wifiConfigured", true);
|
||||
|
||||
delay(1000);
|
||||
// just restart after succes
|
||||
ESP.restart(); });
|
||||
ESP.restart();
|
||||
});
|
||||
|
||||
bool ac = wm.autoConnect(softAP_SSID.c_str(), softAP_password.c_str());
|
||||
|
||||
// waitUntilNoneBusy();
|
||||
//std::array<String, NUM_SCREENS> epdContent = {"Welcome!", "Bienvenidos!", "Use\r\nweb-interface\r\nto configure", "Use\r\nla interfaz web\r\npara configurar", "Or restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config", "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo botón\r\r\npara iniciar\r\nQR-config", ""};
|
||||
//setEpdContent(epdContent);
|
||||
// std::array<String, NUM_SCREENS> epdContent = {"Welcome!",
|
||||
// "Bienvenidos!", "Use\r\nweb-interface\r\nto configure", "Use\r\nla
|
||||
// interfaz web\r\npara configurar", "Or
|
||||
// restart\r\nwhile\r\nholding\r\n2nd button\r\r\nto start\r\n QR-config",
|
||||
// "O reinicie\r\nmientras\r\n mantiene presionado\r\nel segundo
|
||||
// botón\r\r\npara iniciar\r\nQR-config", ""}; setEpdContent(epdContent);
|
||||
// esp_task_wdt_init(30, false);
|
||||
// uint count = 0;
|
||||
// while (WiFi.status() != WL_CONNECTED)
|
||||
@ -120,7 +132,8 @@ void tryImprovSetup()
|
||||
// {
|
||||
// uint8_t b = Serial.read();
|
||||
|
||||
// if (parse_improv_serial_byte(x_position, b, x_buffer, onImprovCommandCallback, onImprovErrorCallback))
|
||||
// if (parse_improv_serial_byte(x_position, b, x_buffer,
|
||||
// onImprovCommandCallback, onImprovErrorCallback))
|
||||
// {
|
||||
// x_buffer[x_position++] = b;
|
||||
// }
|
||||
@ -138,46 +151,42 @@ void tryImprovSetup()
|
||||
// }
|
||||
// esp_task_wdt_deinit();
|
||||
// esp_task_wdt_reset();
|
||||
|
||||
}
|
||||
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
setBgColor(preferences.getUInt("bgColor", DEFAULT_BG_COLOR));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
WiFi.setAutoConnect(true);
|
||||
WiFi.setAutoReconnect(true);
|
||||
WiFi.begin();
|
||||
if (preferences.getInt("txPower", 0)) {
|
||||
if(WiFi.setTxPower(static_cast<wifi_power_t>(preferences.getInt("txPower", 0)))) {
|
||||
Serial.printf("WiFi max tx power set to %d\n", preferences.getInt("txPower", 0));
|
||||
if (WiFi.setTxPower(
|
||||
static_cast<wifi_power_t>(preferences.getInt("txPower", 0)))) {
|
||||
Serial.printf("WiFi max tx power set to %d\n",
|
||||
preferences.getInt("txPower", 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (WiFi.status() != WL_CONNECTED)
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
vTaskDelay(pdMS_TO_TICKS(400));
|
||||
}
|
||||
}
|
||||
// queueLedEffect(LED_EFFECT_WIFI_CONNECT_SUCCESS);
|
||||
}
|
||||
|
||||
void setupTime()
|
||||
{
|
||||
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, NTP_SERVER);
|
||||
void setupTime() {
|
||||
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0,
|
||||
NTP_SERVER);
|
||||
struct tm timeinfo;
|
||||
|
||||
while (!getLocalTime(&timeinfo))
|
||||
{
|
||||
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0, NTP_SERVER);
|
||||
while (!getLocalTime(&timeinfo)) {
|
||||
configTime(preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS), 0,
|
||||
NTP_SERVER);
|
||||
delay(500);
|
||||
Serial.println(F("Retry set time"));
|
||||
}
|
||||
}
|
||||
|
||||
void setupPreferences()
|
||||
{
|
||||
void setupPreferences() {
|
||||
preferences.begin("btclock", false);
|
||||
|
||||
setFgColor(preferences.getUInt("fgColor", DEFAULT_FG_COLOR));
|
||||
@ -193,49 +202,37 @@ void setupPreferences()
|
||||
screenNameMap[SCREEN_MARKET_CAP] = "Market Cap";
|
||||
}
|
||||
|
||||
void setupWebsocketClients(void *pvParameters)
|
||||
{
|
||||
void setupWebsocketClients(void *pvParameters) {
|
||||
setupBlockNotify();
|
||||
|
||||
if (preferences.getBool("fetchEurPrice", false))
|
||||
{
|
||||
if (preferences.getBool("fetchEurPrice", false)) {
|
||||
setupPriceFetchTask();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
setupPriceNotify();
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void setupTimers()
|
||||
{
|
||||
xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
void setupTimers() {
|
||||
xTaskCreate(setupTimeUpdateTimer, "setupTimeUpdateTimer", 2048, NULL,
|
||||
tskIDLE_PRIORITY, NULL);
|
||||
xTaskCreate(setupScreenRotateTimer, "setupScreenRotateTimer", 2048, NULL,
|
||||
tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
void finishSetup()
|
||||
{
|
||||
void finishSetup() {
|
||||
|
||||
if (preferences.getBool("ledStatus", false))
|
||||
{
|
||||
if (preferences.getBool("ledStatus", false)) {
|
||||
restoreLedState();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
clearLeds();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> getScreenNameMap()
|
||||
{
|
||||
return screenNameMap;
|
||||
}
|
||||
std::vector<std::string> getScreenNameMap() { return screenNameMap; }
|
||||
|
||||
|
||||
void setupMcp()
|
||||
{
|
||||
void setupMcp() {
|
||||
#ifdef IS_BTCLOCK_S3
|
||||
const int mcp1AddrPins[] = {MCP1_A0_PIN, MCP1_A1_PIN, MCP1_A2_PIN};
|
||||
const int mcp1AddrValues[] = {LOW, LOW, LOW};
|
||||
@ -260,10 +257,8 @@ void setupMcp()
|
||||
#endif
|
||||
}
|
||||
|
||||
void setupHardware()
|
||||
{
|
||||
if (!LittleFS.begin(true))
|
||||
{
|
||||
void setupHardware() {
|
||||
if (!LittleFS.begin(true)) {
|
||||
Serial.println(F("An Error has occurred while mounting LittleFS"));
|
||||
}
|
||||
|
||||
@ -274,9 +269,7 @@ void setupHardware()
|
||||
setupLeds();
|
||||
|
||||
WiFi.setHostname(getMyHostname().c_str());
|
||||
;
|
||||
if (!psramInit())
|
||||
{
|
||||
if (!psramInit()) {
|
||||
Serial.println(F("PSRAM not available"));
|
||||
}
|
||||
|
||||
@ -284,34 +277,28 @@ void setupHardware()
|
||||
|
||||
Wire.begin(I2C_SDA_PIN, I2C_SCK_PIN, 400000);
|
||||
|
||||
if (!mcp1.begin_I2C(0x20))
|
||||
{
|
||||
if (!mcp1.begin_I2C(0x20)) {
|
||||
Serial.println(F("Error MCP23017"));
|
||||
|
||||
// while (1)
|
||||
// ;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
pinMode(MCP_INT_PIN, INPUT_PULLUP);
|
||||
mcp1.setupInterrupts(false, false, LOW);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
mcp1.pinMode(i, INPUT_PULLUP);
|
||||
mcp1.setupInterruptPin(i, LOW);
|
||||
}
|
||||
#ifndef IS_BTCLOCK_S3
|
||||
for (int i = 8; i <= 14; i++)
|
||||
{
|
||||
for (int i = 8; i <= 14; i++) {
|
||||
mcp1.pinMode(i, OUTPUT);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef IS_BTCLOCK_S3
|
||||
if (!mcp2.begin_I2C(0x21))
|
||||
{
|
||||
if (!mcp2.begin_I2C(0x21)) {
|
||||
Serial.println(F("Error MCP23017"));
|
||||
|
||||
// while (1)
|
||||
@ -320,34 +307,32 @@ void setupHardware()
|
||||
#endif
|
||||
}
|
||||
|
||||
void improvGetAvailableWifiNetworks()
|
||||
{
|
||||
void improvGetAvailableWifiNetworks() {
|
||||
int networkNum = WiFi.scanNetworks();
|
||||
|
||||
for (int id = 0; id < networkNum; ++id)
|
||||
{
|
||||
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::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);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
blinkDelay(500, 2);
|
||||
|
||||
if (count > MAX_ATTEMPTS_WIFI_CONNECTION)
|
||||
{
|
||||
if (count > MAX_ATTEMPTS_WIFI_CONNECTION) {
|
||||
WiFi.disconnect();
|
||||
return false;
|
||||
}
|
||||
@ -357,8 +342,7 @@ bool improv_connectWifi(std::string ssid, std::string password)
|
||||
return true;
|
||||
}
|
||||
|
||||
void onImprovErrorCallback(improv::Error err)
|
||||
{
|
||||
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));
|
||||
@ -372,39 +356,29 @@ void onImprovErrorCallback(improv::Error err)
|
||||
// vTaskDelay(pdMS_TO_TICKS(100));
|
||||
}
|
||||
|
||||
std::vector<std::string> getLocalUrl()
|
||||
{
|
||||
return {
|
||||
// URL where user can finish onboarding or use device
|
||||
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))
|
||||
{
|
||||
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);
|
||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
||||
improv::GET_CURRENT_STATE, getLocalUrl(), false);
|
||||
improv_send_response(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
improv_set_state(improv::State::STATE_AUTHORIZED);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case improv::Command::WIFI_SETTINGS:
|
||||
{
|
||||
if (cmd.ssid.length() == 0)
|
||||
{
|
||||
case improv::Command::WIFI_SETTINGS: {
|
||||
if (cmd.ssid.length() == 0) {
|
||||
improv_set_error(improv::Error::ERROR_INVALID_RPC);
|
||||
break;
|
||||
}
|
||||
@ -412,26 +386,23 @@ bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
||||
improv_set_state(improv::STATE_PROVISIONING);
|
||||
queueLedEffect(LED_EFFECT_WIFI_CONNECTING);
|
||||
|
||||
if (improv_connectWifi(cmd.ssid, cmd.password))
|
||||
{
|
||||
|
||||
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);
|
||||
// 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);
|
||||
std::vector<uint8_t> data = improv::build_rpc_response(
|
||||
improv::WIFI_SETTINGS, getLocalUrl(), false);
|
||||
improv_send_response(data);
|
||||
|
||||
delay(2500);
|
||||
ESP.restart();
|
||||
setupWebserver();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
|
||||
|
||||
improv_set_state(improv::STATE_STOPPED);
|
||||
@ -441,10 +412,8 @@ bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
||||
break;
|
||||
}
|
||||
|
||||
case improv::Command::GET_DEVICE_INFO:
|
||||
{
|
||||
std::vector<std::string> infos = {
|
||||
// Firmware name
|
||||
case improv::Command::GET_DEVICE_INFO: {
|
||||
std::vector<std::string> infos = {// Firmware name
|
||||
"BTClock",
|
||||
// Firmware version
|
||||
"1.0.0",
|
||||
@ -452,21 +421,20 @@ bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
||||
"ESP32S3",
|
||||
// Device name
|
||||
"BTClock"};
|
||||
std::vector<uint8_t> data = improv::build_rpc_response(improv::GET_DEVICE_INFO, infos, false);
|
||||
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:
|
||||
{
|
||||
case improv::Command::GET_WIFI_NETWORKS: {
|
||||
improvGetAvailableWifiNetworks();
|
||||
// std::array<String, NUM_SCREENS> epdContent = {"W", "E", "B", "W", "I", "F", "I"};
|
||||
// setEpdContent(epdContent);
|
||||
// std::array<String, NUM_SCREENS> epdContent = {"W", "E", "B", "W", "I",
|
||||
// "F", "I"}; setEpdContent(epdContent);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
improv_set_error(improv::ERROR_UNKNOWN_RPC);
|
||||
return false;
|
||||
}
|
||||
@ -475,9 +443,7 @@ bool onImprovCommandCallback(improv::ImprovCommand cmd)
|
||||
return true;
|
||||
}
|
||||
|
||||
void improv_set_state(improv::State state)
|
||||
{
|
||||
|
||||
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;
|
||||
@ -493,8 +459,7 @@ void improv_set_state(improv::State state)
|
||||
Serial.write(data.data(), data.size());
|
||||
}
|
||||
|
||||
void improv_send_response(std::vector<uint8_t> &response)
|
||||
{
|
||||
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;
|
||||
@ -510,8 +475,7 @@ void improv_send_response(std::vector<uint8_t> &response)
|
||||
Serial.write(data.data(), data.size());
|
||||
}
|
||||
|
||||
void improv_set_error(improv::Error error)
|
||||
{
|
||||
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;
|
||||
@ -527,14 +491,12 @@ void improv_set_error(improv::Error error)
|
||||
Serial.write(data.data(), data.size());
|
||||
}
|
||||
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
{
|
||||
void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
|
||||
static bool first_connect = true;
|
||||
|
||||
Serial.printf("[WiFi-event] event: %d\n", event);
|
||||
|
||||
switch (event)
|
||||
{
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_READY:
|
||||
Serial.println("WiFi interface ready");
|
||||
break;
|
||||
@ -550,22 +512,21 @@ void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info)
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
Serial.println("Connected to access point");
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
{
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED: {
|
||||
if (!first_connect) {
|
||||
Serial.println("Disconnected from WiFi access point");
|
||||
queueLedEffect(LED_EFFECT_WIFI_CONNECT_ERROR);
|
||||
uint8_t reason = info.wifi_sta_disconnected.reason;
|
||||
if (reason)
|
||||
Serial.printf("Disconnect reason: %s, ", WiFi.disconnectReasonName((wifi_err_reason_t)reason));
|
||||
Serial.printf("Disconnect reason: %s, ",
|
||||
WiFi.disconnectReasonName((wifi_err_reason_t)reason));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARDUINO_EVENT_WIFI_STA_AUTHMODE_CHANGE:
|
||||
Serial.println("Authentication mode of access point has changed");
|
||||
break;
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
{
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP: {
|
||||
Serial.print("Obtained IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
if (!first_connect)
|
||||
@ -613,7 +574,7 @@ String getMyHostname() {
|
||||
esp_efuse_mac_get_default(mac);
|
||||
char hostname[15];
|
||||
String hostnamePrefix = preferences.getString("hostnamePrefix", "btclock");
|
||||
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x",
|
||||
hostnamePrefix, mac[3], mac[4], mac[5]);
|
||||
snprintf(hostname, sizeof(hostname), "%s-%02x%02x%02x", hostnamePrefix,
|
||||
mac[3], mac[4], mac[5]);
|
||||
return hostname;
|
||||
}
|
@ -1,26 +1,23 @@
|
||||
#pragma once;
|
||||
#include <WiFiManager.h>
|
||||
#include "base64.h"
|
||||
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <Preferences.h>
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "shared.hpp"
|
||||
#include "epd.hpp"
|
||||
#include "improv.hpp"
|
||||
#include "esp_task_wdt.h"
|
||||
|
||||
#include <Preferences.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <base64.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include <map>
|
||||
|
||||
#include "ota.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/webserver.hpp"
|
||||
#include "lib/block_notify.hpp"
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/button_handler.hpp"
|
||||
#include "lib/epd.hpp"
|
||||
#include "lib/improv.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/ota.hpp"
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/webserver.hpp"
|
||||
|
||||
#define NTP_SERVER "pool.ntp.org"
|
||||
#define DEFAULT_MEMPOOL_INSTANCE "mempool.space"
|
||||
|
271
src/lib/epd.cpp
271
src/lib/epd.cpp
@ -16,21 +16,12 @@ Native_Pin EPD_CS[NUM_SCREENS] = {
|
||||
#endif
|
||||
};
|
||||
Native_Pin EPD_BUSY[NUM_SCREENS] = {
|
||||
Native_Pin(3),
|
||||
Native_Pin(5),
|
||||
Native_Pin(7),
|
||||
Native_Pin(9),
|
||||
Native_Pin(37),
|
||||
Native_Pin(18),
|
||||
Native_Pin(16),
|
||||
Native_Pin(3), Native_Pin(5), Native_Pin(7), Native_Pin(9),
|
||||
Native_Pin(37), Native_Pin(18), Native_Pin(16),
|
||||
};
|
||||
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp1, 8),
|
||||
MCP23X17_Pin(mcp1, 9),
|
||||
MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11),
|
||||
MCP23X17_Pin(mcp1, 12),
|
||||
MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14),
|
||||
};
|
||||
|
||||
@ -39,36 +30,20 @@ Native_Pin EPD_DC = Native_Pin(14);
|
||||
Native_Pin EPD_DC = Native_Pin(38);
|
||||
|
||||
MCP23X17_Pin EPD_BUSY[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp1, 8),
|
||||
MCP23X17_Pin(mcp1, 9),
|
||||
MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11),
|
||||
MCP23X17_Pin(mcp1, 12),
|
||||
MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14),
|
||||
MCP23X17_Pin(mcp1, 4),
|
||||
MCP23X17_Pin(mcp1, 8), MCP23X17_Pin(mcp1, 9), MCP23X17_Pin(mcp1, 10),
|
||||
MCP23X17_Pin(mcp1, 11), MCP23X17_Pin(mcp1, 12), MCP23X17_Pin(mcp1, 13),
|
||||
MCP23X17_Pin(mcp1, 14), MCP23X17_Pin(mcp1, 4),
|
||||
};
|
||||
|
||||
MCP23X17_Pin EPD_CS[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp2, 8),
|
||||
MCP23X17_Pin(mcp2, 10),
|
||||
MCP23X17_Pin(mcp2, 12),
|
||||
MCP23X17_Pin(mcp2, 14),
|
||||
MCP23X17_Pin(mcp2, 0),
|
||||
MCP23X17_Pin(mcp2, 2),
|
||||
MCP23X17_Pin(mcp2, 4),
|
||||
MCP23X17_Pin(mcp2, 6)
|
||||
};
|
||||
MCP23X17_Pin(mcp2, 8), MCP23X17_Pin(mcp2, 10), MCP23X17_Pin(mcp2, 12),
|
||||
MCP23X17_Pin(mcp2, 14), MCP23X17_Pin(mcp2, 0), MCP23X17_Pin(mcp2, 2),
|
||||
MCP23X17_Pin(mcp2, 4), MCP23X17_Pin(mcp2, 6)};
|
||||
|
||||
MCP23X17_Pin EPD_RESET_MPD[NUM_SCREENS] = {
|
||||
MCP23X17_Pin(mcp2, 9),
|
||||
MCP23X17_Pin(mcp2, 11),
|
||||
MCP23X17_Pin(mcp2, 13),
|
||||
MCP23X17_Pin(mcp2, 15),
|
||||
MCP23X17_Pin(mcp2, 1),
|
||||
MCP23X17_Pin(mcp2, 3),
|
||||
MCP23X17_Pin(mcp2, 5),
|
||||
MCP23X17_Pin(mcp2, 7),
|
||||
MCP23X17_Pin(mcp2, 9), MCP23X17_Pin(mcp2, 11), MCP23X17_Pin(mcp2, 13),
|
||||
MCP23X17_Pin(mcp2, 15), MCP23X17_Pin(mcp2, 1), MCP23X17_Pin(mcp2, 3),
|
||||
MCP23X17_Pin(mcp2, 5), MCP23X17_Pin(mcp2, 7),
|
||||
};
|
||||
|
||||
#endif
|
||||
@ -108,37 +83,32 @@ std::mutex epdMutex[NUM_SCREENS];
|
||||
|
||||
uint8_t qrcode[800];
|
||||
|
||||
void forceFullRefresh()
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
void forceFullRefresh() {
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
lastFullRefresh[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void refreshFromMemory()
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
void refreshFromMemory() {
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
int *taskParam = new int;
|
||||
*taskParam = i;
|
||||
|
||||
xTaskCreate([](void *pvParameters)
|
||||
{
|
||||
xTaskCreate(
|
||||
[](void *pvParameters) {
|
||||
const int epdIndex = *(int *)pvParameters;
|
||||
delete (int *)pvParameters;
|
||||
displays[epdIndex].refresh(false);
|
||||
vTaskDelete(NULL); },
|
||||
vTaskDelete(NULL);
|
||||
},
|
||||
"PrepareUpd", 4096, taskParam, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
void setupDisplays()
|
||||
{
|
||||
void setupDisplays() {
|
||||
std::lock_guard<std::mutex> lockMcp(mcpMutex);
|
||||
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
displays[i].init(0, true, 30);
|
||||
}
|
||||
|
||||
@ -146,30 +116,23 @@ void setupDisplays()
|
||||
|
||||
xTaskCreate(prepareDisplayUpdateTask, "PrepareUpd", 4096, NULL, 11, NULL);
|
||||
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
// epdUpdateSemaphore[i] = xSemaphoreCreateBinary();
|
||||
// xSemaphoreGive(epdUpdateSemaphore[i]);
|
||||
|
||||
int *taskParam = new int;
|
||||
*taskParam = i;
|
||||
|
||||
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam, 11, &tasks[i]); // create task
|
||||
xTaskCreate(updateDisplay, ("EpdUpd" + String(i)).c_str(), 2048, taskParam,
|
||||
11, &tasks[i]); // create task
|
||||
}
|
||||
|
||||
epdContent = {"B",
|
||||
"T",
|
||||
"C",
|
||||
"L",
|
||||
"O",
|
||||
"C",
|
||||
"K"};
|
||||
epdContent = {"B", "T", "C", "L", "O", "C", "K"};
|
||||
|
||||
setEpdContent(epdContent);
|
||||
}
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent)
|
||||
{
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent) {
|
||||
setEpdContent(newEpdContent, false);
|
||||
}
|
||||
|
||||
@ -183,16 +146,14 @@ void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent) {
|
||||
return setEpdContent(conv);
|
||||
}
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent, bool forceUpdate)
|
||||
{
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
|
||||
bool forceUpdate) {
|
||||
std::lock_guard<std::mutex> lock(epdUpdateMutex);
|
||||
|
||||
waitUntilNoneBusy();
|
||||
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate)
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
if (newEpdContent[i].compareTo(currentEpdContent[i]) != 0 || forceUpdate) {
|
||||
epdContent[i] = newEpdContent[i];
|
||||
UpdateDisplayTaskItem dispUpdate = {i};
|
||||
xQueueSend(updateQueue, &dispUpdate, portMAX_DELAY);
|
||||
@ -200,45 +161,37 @@ void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent, bool forceUpda
|
||||
}
|
||||
}
|
||||
|
||||
void prepareDisplayUpdateTask(void *pvParameters)
|
||||
{
|
||||
void prepareDisplayUpdateTask(void *pvParameters) {
|
||||
UpdateDisplayTaskItem receivedItem;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
// Wait for a work item to be available in the queue
|
||||
if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY))
|
||||
{
|
||||
if (xQueueReceive(updateQueue, &receivedItem, portMAX_DELAY)) {
|
||||
uint epdIndex = receivedItem.dispNum;
|
||||
std::lock_guard<std::mutex> lock(epdMutex[epdIndex]);
|
||||
// displays[epdIndex].init(0, false); // Little longer reset duration because of MCP
|
||||
// displays[epdIndex].init(0, false); // Little longer reset duration
|
||||
// because of MCP
|
||||
|
||||
bool updatePartial = true;
|
||||
|
||||
if (strstr(epdContent[epdIndex].c_str(), "/") != NULL)
|
||||
{
|
||||
String top = epdContent[epdIndex].substring(0, epdContent[epdIndex].indexOf("/"));
|
||||
String bottom = epdContent[epdIndex].substring(epdContent[epdIndex].indexOf("/") + 1);
|
||||
if (strstr(epdContent[epdIndex].c_str(), "/") != NULL) {
|
||||
String top = epdContent[epdIndex].substring(
|
||||
0, epdContent[epdIndex].indexOf("/"));
|
||||
String bottom = epdContent[epdIndex].substring(
|
||||
epdContent[epdIndex].indexOf("/") + 1);
|
||||
splitText(epdIndex, top, bottom, updatePartial);
|
||||
}
|
||||
else if (epdContent[epdIndex].startsWith(F("qr")))
|
||||
{
|
||||
} else if (epdContent[epdIndex].startsWith(F("qr"))) {
|
||||
renderQr(epdIndex, epdContent[epdIndex], updatePartial);
|
||||
}
|
||||
else if (epdContent[epdIndex].length() > 5)
|
||||
{
|
||||
} else if (epdContent[epdIndex].length() > 5) {
|
||||
renderText(epdIndex, epdContent[epdIndex], updatePartial);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
|
||||
if (epdContent[epdIndex].length() > 1)
|
||||
{
|
||||
showChars(epdIndex, epdContent[epdIndex], updatePartial, &FONT_MEDIUM);
|
||||
}
|
||||
else
|
||||
{
|
||||
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial, &FONT_BIG);
|
||||
if (epdContent[epdIndex].length() > 1) {
|
||||
showChars(epdIndex, epdContent[epdIndex], updatePartial,
|
||||
&FONT_MEDIUM);
|
||||
} else {
|
||||
showDigit(epdIndex, epdContent[epdIndex].c_str()[0], updatePartial,
|
||||
&FONT_BIG);
|
||||
}
|
||||
}
|
||||
|
||||
@ -247,13 +200,11 @@ void prepareDisplayUpdateTask(void *pvParameters)
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||
{
|
||||
extern "C" void updateDisplay(void *pvParameters) noexcept {
|
||||
const int epdIndex = *(int *)pvParameters;
|
||||
delete (int *)pvParameters;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
// Wait for the task notification
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
@ -265,8 +216,7 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||
displays[epdIndex].init(0, false, 40);
|
||||
}
|
||||
uint count = 0;
|
||||
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10)
|
||||
{
|
||||
while (EPD_BUSY[epdIndex].digitalRead() == HIGH || count < 10) {
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
count++;
|
||||
}
|
||||
@ -274,16 +224,17 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||
bool updatePartial = true;
|
||||
|
||||
// Full Refresh every x minutes
|
||||
if (!lastFullRefresh[epdIndex] || (millis() - lastFullRefresh[epdIndex]) > (preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH) * 60 * 1000))
|
||||
{
|
||||
if (!lastFullRefresh[epdIndex] ||
|
||||
(millis() - lastFullRefresh[epdIndex]) >
|
||||
(preferences.getUInt("fullRefreshMin",
|
||||
DEFAULT_MINUTES_FULL_REFRESH) *
|
||||
60 * 1000)) {
|
||||
updatePartial = false;
|
||||
}
|
||||
|
||||
char tries = 0;
|
||||
while (tries < 3)
|
||||
{
|
||||
if (displays[epdIndex].displayWithReturn(updatePartial))
|
||||
{
|
||||
while (tries < 3) {
|
||||
if (displays[epdIndex].displayWithReturn(updatePartial)) {
|
||||
displays[epdIndex].powerOff();
|
||||
currentEpdContent[epdIndex] = epdContent[epdIndex];
|
||||
if (!updatePartial)
|
||||
@ -301,8 +252,8 @@ extern "C" void updateDisplay(void *pvParameters) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom, bool partial)
|
||||
{
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||
bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(&FONT_SMALL);
|
||||
displays[dispNum].setTextColor(getFgColor());
|
||||
@ -312,14 +263,16 @@ void splitText(const uint dispNum, const String &top, const String &bottom, bool
|
||||
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;
|
||||
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;
|
||||
uint16_t by =
|
||||
((displays[dispNum].height() - tbbh) / 2) - tbby + tbbh / 2 + 12;
|
||||
|
||||
// Make separator as wide as the shortest text.
|
||||
uint16_t lineWidth, lineX;
|
||||
@ -332,13 +285,14 @@ void splitText(const uint dispNum, const String &top, const String &bottom, bool
|
||||
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].fillRoundRect(lineX, displays[dispNum].height() / 2 - 3,
|
||||
lineWidth, 6, 3, getFgColor());
|
||||
displays[dispNum].setCursor(bx, by);
|
||||
displays[dispNum].print(bottom);
|
||||
}
|
||||
|
||||
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);
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
@ -354,8 +308,8 @@ void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font)
|
||||
displays[dispNum].print(str);
|
||||
}
|
||||
|
||||
void showChars(const uint dispNum, const String &chars, bool partial, const GFXfont *font)
|
||||
{
|
||||
void showChars(const uint dispNum, const String &chars, bool partial,
|
||||
const GFXfont *font) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setFont(font);
|
||||
displays[dispNum].setTextColor(getFgColor());
|
||||
@ -370,34 +324,21 @@ void showChars(const uint dispNum, const String &chars, bool partial, const GFXf
|
||||
displays[dispNum].print(chars);
|
||||
}
|
||||
|
||||
int getBgColor()
|
||||
{
|
||||
return bgColor;
|
||||
}
|
||||
int getBgColor() { return bgColor; }
|
||||
|
||||
int getFgColor()
|
||||
{
|
||||
return fgColor;
|
||||
}
|
||||
int getFgColor() { return fgColor; }
|
||||
|
||||
void setBgColor(int color)
|
||||
{
|
||||
bgColor = color;
|
||||
}
|
||||
void setBgColor(int color) { bgColor = color; }
|
||||
|
||||
void setFgColor(int color)
|
||||
{
|
||||
fgColor = color;
|
||||
}
|
||||
void setFgColor(int color) { fgColor = color; }
|
||||
|
||||
std::array<String, NUM_SCREENS> getCurrentEpdContent()
|
||||
{
|
||||
std::array<String, NUM_SCREENS> getCurrentEpdContent() {
|
||||
return currentEpdContent;
|
||||
}
|
||||
void renderText(const uint dispNum, const String &text, bool partial)
|
||||
{
|
||||
void renderText(const uint dispNum, const String &text, bool partial) {
|
||||
displays[dispNum].setRotation(2);
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height());
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
displays[dispNum].setTextColor(GxEPD_BLACK);
|
||||
displays[dispNum].setCursor(0, 50);
|
||||
@ -407,67 +348,61 @@ void renderText(const uint dispNum, const String &text, bool partial)
|
||||
|
||||
std::string line;
|
||||
|
||||
while (std::getline(ss, line, '\n'))
|
||||
{
|
||||
if (line.rfind("*", 0) == 0)
|
||||
{
|
||||
while (std::getline(ss, line, '\n')) {
|
||||
if (line.rfind("*", 0) == 0) {
|
||||
line.erase(std::remove(line.begin(), line.end(), '*'), line.end());
|
||||
|
||||
displays[dispNum].setFont(&FreeSansBold9pt7b);
|
||||
displays[dispNum].println(line.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
displays[dispNum].setFont(&FreeSans9pt7b);
|
||||
displays[dispNum].println(line.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void renderQr(const uint dispNum, const String &text, bool partial)
|
||||
{
|
||||
void renderQr(const uint dispNum, const String &text, bool partial) {
|
||||
#ifdef USE_QR
|
||||
|
||||
uint8_t tempBuffer[800];
|
||||
bool ok = qrcodegen_encodeText(text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW,
|
||||
bool ok = qrcodegen_encodeText(
|
||||
text.substring(2).c_str(), tempBuffer, qrcode, qrcodegen_Ecc_LOW,
|
||||
qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
|
||||
|
||||
const int size = qrcodegen_getSize(qrcode);
|
||||
|
||||
const int padding = floor(float(displays[dispNum].width() - (size * 4)) / 2);
|
||||
const int paddingY = floor(float(displays[dispNum].height() - (size * 4)) / 2);
|
||||
const int paddingY =
|
||||
floor(float(displays[dispNum].height() - (size * 4)) / 2);
|
||||
displays[dispNum].setRotation(2);
|
||||
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(), displays[dispNum].height());
|
||||
displays[dispNum].setPartialWindow(0, 0, displays[dispNum].width(),
|
||||
displays[dispNum].height());
|
||||
displays[dispNum].fillScreen(GxEPD_WHITE);
|
||||
const int border = 0;
|
||||
|
||||
for (int y = -border; y < size * 4 + border; y++)
|
||||
{
|
||||
for (int x = -border; x < size * 4 + border; x++)
|
||||
{
|
||||
displays[dispNum].drawPixel(padding + x, paddingY + y, qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4)) ? GxEPD_BLACK : GxEPD_WHITE);
|
||||
for (int y = -border; y < size * 4 + border; y++) {
|
||||
for (int x = -border; x < size * 4 + border; x++) {
|
||||
displays[dispNum].drawPixel(
|
||||
padding + x, paddingY + y,
|
||||
qrcodegen_getModule(qrcode, floor(float(x) / 4), floor(float(y) / 4))
|
||||
? GxEPD_BLACK
|
||||
: GxEPD_WHITE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void waitUntilNoneBusy()
|
||||
{
|
||||
for (int i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
void waitUntilNoneBusy() {
|
||||
for (int i = 0; i < NUM_SCREENS; i++) {
|
||||
uint count = 0;
|
||||
while (EPD_BUSY[i].digitalRead())
|
||||
{
|
||||
while (EPD_BUSY[i].digitalRead()) {
|
||||
count++;
|
||||
vTaskDelay(10);
|
||||
if (count == 200)
|
||||
{
|
||||
if (count == 200) {
|
||||
// displays[i].init(0, false);
|
||||
vTaskDelay(100);
|
||||
}
|
||||
else if (count > 205)
|
||||
{
|
||||
} else if (count > 205) {
|
||||
Serial.printf("Busy timeout %d", i);
|
||||
break;
|
||||
}
|
||||
|
@ -1,23 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <GxEPD2_BW.h>
|
||||
#include <native_pin.hpp>
|
||||
#include <mcp23x17_pin.hpp>
|
||||
#include "shared.hpp"
|
||||
#include "config.hpp"
|
||||
#include "fonts/fonts.hpp"
|
||||
#include <Fonts/FreeSansBold9pt7b.h>
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include <Fonts/FreeSans9pt7b.h>
|
||||
#include <regex>
|
||||
#include <Fonts/FreeSansBold9pt7b.h>
|
||||
#include <GxEPD2_BW.h>
|
||||
#include <mcp23x17_pin.hpp>
|
||||
#include <mutex>
|
||||
#include <native_pin.hpp>
|
||||
#include <regex>
|
||||
|
||||
#ifdef USE_QR
|
||||
#include "qrcodegen.h"
|
||||
#endif
|
||||
// extern TaskHandle_t epdTaskHandle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
char dispNum;
|
||||
} UpdateDisplayTaskItem;
|
||||
|
||||
@ -25,10 +24,12 @@ void forceFullRefresh();
|
||||
void refreshFromMemory();
|
||||
void setupDisplays();
|
||||
|
||||
void splitText(const uint dispNum, const String& top, const String& bottom, bool partial);
|
||||
void splitText(const uint dispNum, const String &top, const String &bottom,
|
||||
bool partial);
|
||||
|
||||
void showDigit(const uint dispNum, char chr, bool partial, const GFXfont *font);
|
||||
void showChars(const uint dispNum, const String& chars, bool partial, const GFXfont *font);
|
||||
void showChars(const uint dispNum, const String &chars, bool partial,
|
||||
const GFXfont *font);
|
||||
|
||||
extern "C" void updateDisplay(void *pvParameters) noexcept;
|
||||
void updateDisplayAlt(int epdIndex);
|
||||
@ -42,7 +43,8 @@ void setFgColor(int color);
|
||||
void renderText(const uint dispNum, const String &text, bool partial);
|
||||
void renderQr(const uint dispNum, const String &text, bool partial);
|
||||
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent, bool forceUpdate);
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent,
|
||||
bool forceUpdate);
|
||||
void setEpdContent(std::array<String, NUM_SCREENS> newEpdContent);
|
||||
|
||||
void setEpdContent(std::array<std::string, NUM_SCREENS> newEpdContent);
|
||||
|
@ -2,11 +2,13 @@
|
||||
|
||||
namespace improv {
|
||||
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data, bool check_checksum) {
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data,
|
||||
bool check_checksum) {
|
||||
return parse_improv_data(data.data(), data.size(), check_checksum);
|
||||
}
|
||||
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length, bool check_checksum) {
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length,
|
||||
bool check_checksum) {
|
||||
ImprovCommand improv_command;
|
||||
Command command = (Command)data[0];
|
||||
uint8_t data_length = data[1];
|
||||
@ -48,8 +50,10 @@ ImprovCommand parse_improv_data(const uint8_t *data, size_t length, bool check_c
|
||||
return improv_command;
|
||||
}
|
||||
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte, const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback, std::function<void(Error)> &&on_error) {
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte,
|
||||
const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback,
|
||||
std::function<void(Error)> &&on_error) {
|
||||
if (position == 0)
|
||||
return byte == 'I';
|
||||
if (position == 1)
|
||||
@ -94,7 +98,9 @@ bool parse_improv_serial_byte(size_t position, uint8_t byte, const uint8_t *buff
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<std::string> &datum, bool add_checksum) {
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<std::string> &datum,
|
||||
bool add_checksum) {
|
||||
std::vector<uint8_t> out;
|
||||
uint32_t length = 0;
|
||||
out.push_back(command);
|
||||
@ -118,7 +124,9 @@ std::vector<uint8_t> build_rpc_response(Command command, const std::vector<std::
|
||||
}
|
||||
|
||||
#ifdef ARDUINO
|
||||
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<String> &datum, bool add_checksum) {
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<String> &datum,
|
||||
bool add_checksum) {
|
||||
std::vector<uint8_t> out;
|
||||
uint32_t length = 0;
|
||||
out.push_back(command);
|
||||
|
@ -14,9 +14,12 @@ namespace improv {
|
||||
static const char *const SERVICE_UUID = "00467768-6228-2272-4663-277478268000";
|
||||
static const char *const STATUS_UUID = "00467768-6228-2272-4663-277478268001";
|
||||
static const char *const ERROR_UUID = "00467768-6228-2272-4663-277478268002";
|
||||
static const char *const RPC_COMMAND_UUID = "00467768-6228-2272-4663-277478268003";
|
||||
static const char *const RPC_RESULT_UUID = "00467768-6228-2272-4663-277478268004";
|
||||
static const char *const CAPABILITIES_UUID = "00467768-6228-2272-4663-277478268005";
|
||||
static const char *const RPC_COMMAND_UUID =
|
||||
"00467768-6228-2272-4663-277478268003";
|
||||
static const char *const RPC_RESULT_UUID =
|
||||
"00467768-6228-2272-4663-277478268004";
|
||||
static const char *const CAPABILITIES_UUID =
|
||||
"00467768-6228-2272-4663-277478268005";
|
||||
|
||||
enum Error : uint8_t {
|
||||
ERROR_NONE = 0x00,
|
||||
@ -61,16 +64,23 @@ struct ImprovCommand {
|
||||
std::string password;
|
||||
};
|
||||
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data, bool check_checksum = true);
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length, bool check_checksum = true);
|
||||
ImprovCommand parse_improv_data(const std::vector<uint8_t> &data,
|
||||
bool check_checksum = true);
|
||||
ImprovCommand parse_improv_data(const uint8_t *data, size_t length,
|
||||
bool check_checksum = true);
|
||||
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte, const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback, std::function<void(Error)> &&on_error);
|
||||
bool parse_improv_serial_byte(size_t position, uint8_t byte,
|
||||
const uint8_t *buffer,
|
||||
std::function<bool(ImprovCommand)> &&callback,
|
||||
std::function<void(Error)> &&on_error);
|
||||
|
||||
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<std::string> &datum,
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<std::string> &datum,
|
||||
bool add_checksum = true);
|
||||
#ifdef ARDUINO
|
||||
std::vector<uint8_t> build_rpc_response(Command command, const std::vector<String> &datum, bool add_checksum = true);
|
||||
std::vector<uint8_t> build_rpc_response(Command command,
|
||||
const std::vector<String> &datum,
|
||||
bool add_checksum = true);
|
||||
#endif // ARDUINO
|
||||
|
||||
} // namespace improv
|
@ -5,30 +5,26 @@ QueueHandle_t ledTaskQueue = NULL;
|
||||
Adafruit_NeoPixel pixels(NEOPIXEL_COUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
|
||||
uint ledTaskParams;
|
||||
|
||||
void ledTask(void *parameter)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
if (ledTaskQueue != NULL)
|
||||
{
|
||||
if (xQueueReceive(ledTaskQueue, &ledTaskParams, portMAX_DELAY) == pdPASS)
|
||||
{
|
||||
void ledTask(void *parameter) {
|
||||
while (1) {
|
||||
if (ledTaskQueue != NULL) {
|
||||
if (xQueueReceive(ledTaskQueue, &ledTaskParams, portMAX_DELAY) ==
|
||||
pdPASS) {
|
||||
uint32_t oldLights[NEOPIXEL_COUNT];
|
||||
|
||||
// get current state
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
oldLights[i] = pixels.getPixelColor(i);
|
||||
}
|
||||
|
||||
switch (ledTaskParams)
|
||||
{
|
||||
switch (ledTaskParams) {
|
||||
case LED_POWER_TEST:
|
||||
ledRainbow(20);
|
||||
pixels.clear();
|
||||
break;
|
||||
case LED_EFFECT_WIFI_CONNECT_ERROR:
|
||||
blinkDelayTwoColor(100, 3, pixels.Color(8, 161, 236), pixels.Color(255, 0, 0));
|
||||
blinkDelayTwoColor(100, 3, pixels.Color(8, 161, 236),
|
||||
pixels.Color(255, 0, 0));
|
||||
break;
|
||||
case LED_FLASH_ERROR:
|
||||
blinkDelayColor(250, 3, 255, 0, 0);
|
||||
@ -53,25 +49,22 @@ void ledTask(void *parameter)
|
||||
case LED_FLASH_UPDATE:
|
||||
break;
|
||||
case LED_FLASH_BLOCK_NOTIFY:
|
||||
blinkDelayTwoColor(250, 3, pixels.Color(224, 67, 0), pixels.Color(8, 2, 0));
|
||||
blinkDelayTwoColor(250, 3, pixels.Color(224, 67, 0),
|
||||
pixels.Color(8, 2, 0));
|
||||
break;
|
||||
case LED_EFFECT_WIFI_WAIT_FOR_CONFIG:
|
||||
blinkDelayTwoColor(100, 1, pixels.Color(8, 161, 236), pixels.Color(156, 225, 240));
|
||||
blinkDelayTwoColor(100, 1, pixels.Color(8, 161, 236),
|
||||
pixels.Color(156, 225, 240));
|
||||
break;
|
||||
case LED_EFFECT_WIFI_ERASE_SETTINGS:
|
||||
blinkDelay(100, 3);
|
||||
break;
|
||||
case LED_EFFECT_WIFI_CONNECTING:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--)
|
||||
{
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--)
|
||||
{
|
||||
if (j == i)
|
||||
{
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
if (j == i) {
|
||||
pixels.setPixelColor(i, pixels.Color(16, 197, 236));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
pixels.setPixelColor(j, pixels.Color(0, 0, 0));
|
||||
}
|
||||
}
|
||||
@ -80,10 +73,8 @@ void ledTask(void *parameter)
|
||||
}
|
||||
break;
|
||||
case LED_EFFECT_PAUSE_TIMER:
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--)
|
||||
{
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--)
|
||||
{
|
||||
for (int i = NEOPIXEL_COUNT; i >= 0; i--) {
|
||||
for (int j = NEOPIXEL_COUNT; j >= 0; j--) {
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = pixels.Color(0, 255, 0);
|
||||
@ -109,11 +100,9 @@ void ledTask(void *parameter)
|
||||
|
||||
delay(900);
|
||||
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0)
|
||||
{
|
||||
for (int i = NEOPIXEL_COUNT; i--; i > 0) {
|
||||
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0)
|
||||
{
|
||||
for (int j = NEOPIXEL_COUNT; j--; j > 0) {
|
||||
uint32_t c = pixels.Color(0, 0, 0);
|
||||
if (i == j)
|
||||
c = pixels.Color(0, 255, 0);
|
||||
@ -133,8 +122,7 @@ void ledTask(void *parameter)
|
||||
|
||||
// revert to previous state unless power test
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, oldLights[i]);
|
||||
}
|
||||
|
||||
@ -144,17 +132,14 @@ void ledTask(void *parameter)
|
||||
}
|
||||
}
|
||||
|
||||
void setupLeds()
|
||||
{
|
||||
void setupLeds() {
|
||||
pixels.begin();
|
||||
pixels.setBrightness(preferences.getUInt("ledBrightness", 128));
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
setupLedTask();
|
||||
if (preferences.getBool("ledTestOnPower", true))
|
||||
{
|
||||
while (!ledTaskQueue)
|
||||
{
|
||||
if (preferences.getBool("ledTestOnPower", true)) {
|
||||
while (!ledTaskQueue) {
|
||||
delay(1);
|
||||
// wait until queue is available
|
||||
}
|
||||
@ -162,17 +147,14 @@ void setupLeds()
|
||||
}
|
||||
}
|
||||
|
||||
void setupLedTask()
|
||||
{
|
||||
void setupLedTask() {
|
||||
ledTaskQueue = xQueueCreate(5, sizeof(uint));
|
||||
|
||||
xTaskCreate(ledTask, "LedTask", 2048, NULL, tskIDLE_PRIORITY, &ledTaskHandle);
|
||||
}
|
||||
|
||||
void blinkDelay(int d, int times)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
void blinkDelay(int d, int times) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
|
||||
pixels.setPixelColor(0, pixels.Color(255, 0, 0));
|
||||
pixels.setPixelColor(1, pixels.Color(0, 255, 0));
|
||||
@ -192,12 +174,9 @@ void blinkDelay(int d, int times)
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
void blinkDelayColor(int d, int times, uint r, uint g, uint b) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, pixels.Color(r, g, b));
|
||||
}
|
||||
|
||||
@ -212,19 +191,15 @@ void blinkDelayColor(int d, int times, uint r, uint g, uint b)
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2)
|
||||
{
|
||||
for (int j = 0; j < times; j++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2) {
|
||||
for (int j = 0; j < times; j++) {
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c1);
|
||||
}
|
||||
pixels.show();
|
||||
vTaskDelay(pdMS_TO_TICKS(d));
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, c2);
|
||||
}
|
||||
pixels.show();
|
||||
@ -234,43 +209,33 @@ void blinkDelayTwoColor(int d, int times, uint32_t c1, uint32_t c2)
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void clearLeds()
|
||||
{
|
||||
void clearLeds() {
|
||||
preferences.putBool("ledStatus", false);
|
||||
pixels.clear();
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void setLights(int r, int g, int b)
|
||||
{
|
||||
setLights(pixels.Color(r, g, b));
|
||||
}
|
||||
void setLights(int r, int g, int b) { setLights(pixels.Color(r, g, b)); }
|
||||
|
||||
void setLights(uint32_t color)
|
||||
{
|
||||
void setLights(uint32_t color) {
|
||||
|
||||
bool ledStatus = true;
|
||||
|
||||
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++)
|
||||
{
|
||||
for (int i = 0; i < NEOPIXEL_COUNT; i++) {
|
||||
pixels.setPixelColor(i, color);
|
||||
}
|
||||
pixels.show();
|
||||
|
||||
if (color == pixels.Color(0, 0, 0))
|
||||
{
|
||||
if (color == pixels.Color(0, 0, 0)) {
|
||||
ledStatus = false;
|
||||
} else {
|
||||
saveLedState();
|
||||
}
|
||||
preferences.putBool("ledStatus", ledStatus);
|
||||
|
||||
}
|
||||
|
||||
void saveLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++)
|
||||
{
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
int pixelColor = pixels.getPixelColor(i);
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
@ -281,8 +246,7 @@ void saveLedState() {
|
||||
}
|
||||
|
||||
void restoreLedState() {
|
||||
for (int i = 0; i < pixels.numPixels(); i++)
|
||||
{
|
||||
for (int i = 0; i < pixels.numPixels(); i++) {
|
||||
char key[12];
|
||||
snprintf(key, 12, "%s%d", "ledColor_", i);
|
||||
uint pixelColor = preferences.getUInt(key, pixels.Color(0, 0, 0));
|
||||
@ -292,15 +256,10 @@ void restoreLedState() {
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
QueueHandle_t getLedTaskQueue()
|
||||
{
|
||||
return ledTaskQueue;
|
||||
}
|
||||
QueueHandle_t getLedTaskQueue() { return ledTaskQueue; }
|
||||
|
||||
bool queueLedEffect(uint effect)
|
||||
{
|
||||
if (ledTaskQueue == NULL)
|
||||
{
|
||||
bool queueLedEffect(uint effect) {
|
||||
if (ledTaskQueue == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -308,14 +267,13 @@ bool queueLedEffect(uint effect)
|
||||
xQueueSend(ledTaskQueue, &flashType, portMAX_DELAY);
|
||||
}
|
||||
|
||||
void ledRainbow(int wait)
|
||||
{
|
||||
void ledRainbow(int wait) {
|
||||
// Hue of first pixel runs 5 complete loops through the color wheel.
|
||||
// Color wheel has a range of 65536 but it's OK if we roll over, so
|
||||
// just count from 0 to 5*65536. Adding 256 to firstPixelHue each time
|
||||
// means we'll make 5*65536/256 = 1280 passes through this loop:
|
||||
for (long firstPixelHue = 0; firstPixelHue < 5 * 65536; firstPixelHue += 256)
|
||||
{
|
||||
for (long firstPixelHue = 0; firstPixelHue < 5 * 65536;
|
||||
firstPixelHue += 256) {
|
||||
// strip.rainbow() can take a single argument (first pixel hue) or
|
||||
// optionally a few extras: number of rainbow repetitions (default 1),
|
||||
// saturation and value (brightness) (both 0-255, similar to the
|
||||
@ -330,16 +288,12 @@ void ledRainbow(int wait)
|
||||
}
|
||||
}
|
||||
|
||||
void ledTheaterChase(uint32_t color, int wait)
|
||||
{
|
||||
for (int a = 0; a < 10; a++)
|
||||
{ // Repeat 10 times...
|
||||
for (int b = 0; b < 3; b++)
|
||||
{ // 'b' counts from 0 to 2...
|
||||
void ledTheaterChase(uint32_t color, int wait) {
|
||||
for (int a = 0; a < 10; a++) { // Repeat 10 times...
|
||||
for (int b = 0; b < 3; b++) { // 'b' counts from 0 to 2...
|
||||
pixels.clear(); // Set all pixels in RAM to 0 (off)
|
||||
// 'c' counts up from 'b' to end of strip in steps of 3...
|
||||
for (int c = b; c < pixels.numPixels(); c += 3)
|
||||
{
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
pixels.setPixelColor(c, color); // Set pixel 'c' to value 'color'
|
||||
}
|
||||
pixels.show(); // Update strip with new contents
|
||||
@ -348,17 +302,13 @@ void ledTheaterChase(uint32_t color, int wait)
|
||||
}
|
||||
}
|
||||
|
||||
void ledTheaterChaseRainbow(int wait)
|
||||
{
|
||||
void ledTheaterChaseRainbow(int wait) {
|
||||
int firstPixelHue = 0; // First pixel starts at red (hue 0)
|
||||
for (int a = 0; a < 30; a++)
|
||||
{ // Repeat 30 times...
|
||||
for (int b = 0; b < 3; b++)
|
||||
{ // 'b' counts from 0 to 2...
|
||||
for (int a = 0; a < 30; a++) { // Repeat 30 times...
|
||||
for (int b = 0; b < 3; b++) { // 'b' counts from 0 to 2...
|
||||
pixels.clear(); // Set all pixels in RAM to 0 (off)
|
||||
// 'c' counts up from 'b' to end of strip in increments of 3...
|
||||
for (int c = b; c < pixels.numPixels(); c += 3)
|
||||
{
|
||||
for (int c = b; c < pixels.numPixels(); c += 3) {
|
||||
// hue of pixel 'c' is offset by an amount to make one full
|
||||
// revolution of the color wheel (range 65536) along the length
|
||||
// of the strip (strip.numPixels() steps):
|
||||
@ -373,7 +323,4 @@ void ledTheaterChaseRainbow(int wait)
|
||||
}
|
||||
}
|
||||
|
||||
Adafruit_NeoPixel getPixels()
|
||||
{
|
||||
return pixels;
|
||||
}
|
||||
Adafruit_NeoPixel getPixels() { return pixels; }
|
@ -1,11 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "lib/shared.hpp"
|
||||
#include "lib/webserver.hpp"
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#include <Arduino.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include "webserver.hpp"
|
||||
#include "shared.hpp"
|
||||
|
||||
#ifndef NEOPIXEL_PIN
|
||||
#define NEOPIXEL_PIN 34
|
||||
|
@ -2,10 +2,8 @@
|
||||
|
||||
TaskHandle_t taskOtaHandle = NULL;
|
||||
|
||||
void setupOTA()
|
||||
{
|
||||
if (preferences.getBool("otaEnabled", true))
|
||||
{
|
||||
void setupOTA() {
|
||||
if (preferences.getBool("otaEnabled", true)) {
|
||||
ArduinoOTA.onStart(onOTAStart);
|
||||
|
||||
ArduinoOTA.onProgress(onOTAProgress);
|
||||
@ -18,37 +16,33 @@ void setupOTA()
|
||||
ArduinoOTA.begin();
|
||||
// downloadUpdate();
|
||||
|
||||
xTaskCreate(handleOTATask, "handleOTA", 4096, NULL, tskIDLE_PRIORITY, &taskOtaHandle);
|
||||
xTaskCreate(handleOTATask, "handleOTA", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&taskOtaHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void onOTAProgress(unsigned int progress, unsigned int total)
|
||||
{
|
||||
void onOTAProgress(unsigned int progress, unsigned int total) {
|
||||
uint percentage = progress / (total / 100);
|
||||
pixels.fill(pixels.Color(0, 255, 0));
|
||||
if (percentage < 100)
|
||||
{
|
||||
if (percentage < 100) {
|
||||
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 75)
|
||||
{
|
||||
if (percentage < 75) {
|
||||
pixels.setPixelColor(1, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 50)
|
||||
{
|
||||
if (percentage < 50) {
|
||||
pixels.setPixelColor(2, pixels.Color(0, 0, 0));
|
||||
}
|
||||
if (percentage < 25)
|
||||
{
|
||||
if (percentage < 25) {
|
||||
pixels.setPixelColor(3, pixels.Color(0, 0, 0));
|
||||
}
|
||||
pixels.show();
|
||||
}
|
||||
|
||||
void onOTAStart()
|
||||
{
|
||||
void onOTAStart() {
|
||||
forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A", "T", "E", "!"};
|
||||
std::array<String, NUM_SCREENS> epdContent = {"U", "P", "D", "A",
|
||||
"T", "E", "!"};
|
||||
setEpdContent(epdContent);
|
||||
// Stop all timers
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
@ -68,17 +62,14 @@ void onOTAStart()
|
||||
stopPriceNotify();
|
||||
}
|
||||
|
||||
void handleOTATask(void *parameter)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
void handleOTATask(void *parameter) {
|
||||
for (;;) {
|
||||
ArduinoOTA.handle(); // Allow OTA updates to occur
|
||||
vTaskDelay(pdMS_TO_TICKS(2500));
|
||||
}
|
||||
}
|
||||
|
||||
void downloadUpdate()
|
||||
{
|
||||
void downloadUpdate() {
|
||||
WiFiClientSecure client;
|
||||
client.setInsecure();
|
||||
HTTPClient http;
|
||||
@ -87,11 +78,11 @@ void downloadUpdate()
|
||||
// Send HTTP request to CoinGecko API
|
||||
http.useHTTP10(true);
|
||||
|
||||
http.begin(client, "https://api.github.com/repos/btclock/btclock_v3/releases/latest");
|
||||
http.begin(client,
|
||||
"https://api.github.com/repos/btclock/btclock_v3/releases/latest");
|
||||
int httpCode = http.GET();
|
||||
|
||||
if (httpCode == 200)
|
||||
{
|
||||
if (httpCode == 200) {
|
||||
// WiFiClient * stream = http->getStreamPtr();
|
||||
|
||||
StaticJsonDocument<64> filter;
|
||||
@ -102,18 +93,17 @@ void downloadUpdate()
|
||||
|
||||
SpiRamJsonDocument doc(1536);
|
||||
|
||||
DeserializationError error = deserializeJson(doc, http.getStream(), DeserializationOption::Filter(filter));
|
||||
DeserializationError error = deserializeJson(
|
||||
doc, http.getStream(), DeserializationOption::Filter(filter));
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (error) {
|
||||
Serial.print("deserializeJson() failed: ");
|
||||
Serial.println(error.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
String downloadUrl;
|
||||
for (JsonObject asset : doc["assets"].as<JsonArray>())
|
||||
{
|
||||
for (JsonObject asset : doc["assets"].as<JsonArray>()) {
|
||||
if (asset["name"].as<String>().compareTo("firmware.bin") == 0) {
|
||||
downloadUrl = asset["browser_download_url"].as<String>();
|
||||
break;
|
||||
@ -122,8 +112,6 @@ void downloadUpdate()
|
||||
|
||||
Serial.printf("Download update from %s", downloadUrl);
|
||||
|
||||
|
||||
|
||||
// esp_http_client_config_t config = {
|
||||
// .url = CONFIG_FIRMWARE_UPGRADE_URL,
|
||||
// };
|
||||
@ -138,8 +126,7 @@ void downloadUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
void onOTAError(ota_error_t error)
|
||||
{
|
||||
void onOTAError(ota_error_t error) {
|
||||
Serial.println("\nOTA update error, restarting");
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
@ -147,8 +134,7 @@ void onOTAError(ota_error_t error)
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void onOTAComplete()
|
||||
{
|
||||
void onOTAComplete() {
|
||||
Serial.println("\nOTA update finished");
|
||||
Wire.end();
|
||||
SPI.end();
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoOTA.h>
|
||||
#include "config.hpp"
|
||||
#include "shared.hpp"
|
||||
|
||||
void setupOTA();
|
||||
void onOTAStart();
|
||||
|
@ -1,15 +1,14 @@
|
||||
#include "price_fetch.hpp"
|
||||
|
||||
const PROGMEM char *cgApiUrl = "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd%2Ceur";
|
||||
const PROGMEM char *cgApiUrl = "https://api.coingecko.com/api/v3/simple/"
|
||||
"price?ids=bitcoin&vs_currencies=usd%2Ceur";
|
||||
|
||||
TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
void taskPriceFetch(void *pvParameters)
|
||||
{
|
||||
void taskPriceFetch(void *pvParameters) {
|
||||
WiFiClientSecure *client = new WiFiClientSecure;
|
||||
client->setInsecure();
|
||||
for (;;)
|
||||
{
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
HTTPClient *http = new HTTPClient();
|
||||
@ -22,8 +21,7 @@ void taskPriceFetch(void *pvParameters)
|
||||
|
||||
// Parse JSON response and extract average price
|
||||
uint usdPrice, eurPrice;
|
||||
if (httpCode == 200)
|
||||
{
|
||||
if (httpCode == 200) {
|
||||
String payload = http->getString();
|
||||
StaticJsonDocument<96> doc;
|
||||
deserializeJson(doc, payload);
|
||||
@ -31,30 +29,28 @@ void taskPriceFetch(void *pvParameters)
|
||||
eurPrice = doc["bitcoin"]["eur"].as<uint>();
|
||||
|
||||
setPrice(eurPrice);
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || getCurrentScreen() == SCREEN_MSCW_TIME || getCurrentScreen() == SCREEN_MARKET_CAP))
|
||||
{
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
|
||||
preferences.putUInt("lastPrice", eurPrice);
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.print(F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
||||
} else {
|
||||
Serial.print(
|
||||
F("Error retrieving BTC/USD price (CoinGecko). HTTP status code: "));
|
||||
Serial.println(httpCode);
|
||||
if (httpCode == -1)
|
||||
{
|
||||
if (httpCode == -1) {
|
||||
WiFi.reconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setupPriceFetchTask()
|
||||
{
|
||||
xTaskCreate(taskPriceFetch, "priceFetch", (6*1024), NULL, tskIDLE_PRIORITY, &priceFetchTaskHandle);
|
||||
void setupPriceFetchTask() {
|
||||
xTaskCreate(taskPriceFetch, "priceFetch", (6 * 1024), NULL, tskIDLE_PRIORITY,
|
||||
&priceFetchTaskHandle);
|
||||
|
||||
xTaskNotifyGive(priceFetchTaskHandle);
|
||||
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
#include "lib/config.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
#include <Arduino.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "config.hpp"
|
||||
#include "shared.hpp"
|
||||
|
||||
extern TaskHandle_t priceFetchTaskHandle;
|
||||
|
||||
|
@ -38,28 +38,25 @@ esp_websocket_client_handle_t clientPrice = NULL;
|
||||
uint currentPrice = 30000;
|
||||
unsigned long int lastPriceUpdate;
|
||||
|
||||
void setupPriceNotify()
|
||||
{
|
||||
void setupPriceNotify() {
|
||||
// currentPrice = preferences.get("lastPrice", 30000);
|
||||
|
||||
esp_websocket_client_config_t config = {
|
||||
.uri = wsServerPrice,
|
||||
esp_websocket_client_config_t config = {.uri = wsServerPrice,
|
||||
// .task_stack = (7*1024),
|
||||
// .cert_pem = coinCapWsCert,
|
||||
.user_agent = USER_AGENT
|
||||
};
|
||||
.user_agent = USER_AGENT};
|
||||
|
||||
clientPrice = esp_websocket_client_init(&config);
|
||||
esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY, onWebsocketPriceEvent, clientPrice);
|
||||
esp_websocket_register_events(clientPrice, WEBSOCKET_EVENT_ANY,
|
||||
onWebsocketPriceEvent, clientPrice);
|
||||
esp_websocket_client_start(clientPrice);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
switch (event_id)
|
||||
{
|
||||
switch (event_id) {
|
||||
case WEBSOCKET_EVENT_CONNECTED:
|
||||
Serial.println(F("Connected to CoinCap.io WebSocket"));
|
||||
break;
|
||||
@ -75,8 +72,7 @@ void onWebsocketPriceEvent(void *handler_args, esp_event_base_t base, int32_t ev
|
||||
}
|
||||
}
|
||||
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data)
|
||||
{
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data) {
|
||||
SpiRamJsonDocument doc(event_data->data_len);
|
||||
|
||||
deserializeJson(doc, (char *)event_data->data_ptr);
|
||||
@ -84,16 +80,20 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data)
|
||||
if (doc.containsKey("bitcoin")) {
|
||||
if (currentPrice != doc["bitcoin"].as<long>()) {
|
||||
|
||||
uint minSecPriceUpd = preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
uint minSecPriceUpd = preferences.getUInt(
|
||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
uint currentTime = esp_timer_get_time() / 1000000;
|
||||
|
||||
if (lastPriceUpdate == 0 || (currentTime - lastPriceUpdate) > minSecPriceUpd) {
|
||||
if (lastPriceUpdate == 0 ||
|
||||
(currentTime - lastPriceUpdate) > minSecPriceUpd) {
|
||||
// const unsigned long oldPrice = currentPrice;
|
||||
currentPrice = doc["bitcoin"].as<uint>();
|
||||
preferences.putUInt("lastPrice", currentPrice);
|
||||
lastPriceUpdate = currentTime;
|
||||
// if (abs((int)(oldPrice-currentPrice)) > round(0.0015*oldPrice)) {
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER || getCurrentScreen() == SCREEN_MSCW_TIME || getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
if (workQueue != nullptr && (getCurrentScreen() == SCREEN_BTC_TICKER ||
|
||||
getCurrentScreen() == SCREEN_MSCW_TIME ||
|
||||
getCurrentScreen() == SCREEN_MARKET_CAP)) {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
}
|
||||
@ -103,13 +103,9 @@ void onWebsocketPriceMessage(esp_websocket_event_data_t* event_data)
|
||||
}
|
||||
}
|
||||
|
||||
uint getPrice() {
|
||||
return currentPrice;
|
||||
}
|
||||
uint getPrice() { return currentPrice; }
|
||||
|
||||
void setPrice(uint newPrice) {
|
||||
currentPrice = newPrice;
|
||||
}
|
||||
void setPrice(uint newPrice) { currentPrice = newPrice; }
|
||||
|
||||
bool isPriceNotifyConnected() {
|
||||
if (clientPrice == NULL)
|
||||
|
@ -1,17 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <string>
|
||||
|
||||
#include "esp_websocket_client.h"
|
||||
#include "screen_handler.hpp"
|
||||
#include <esp_websocket_client.h>
|
||||
#include "lib/screen_handler.hpp"
|
||||
|
||||
// using namespace websockets;
|
||||
|
||||
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);
|
||||
void onWebsocketPriceMessage(esp_websocket_event_data_t *event_data);
|
||||
|
||||
uint getPrice();
|
||||
|
@ -8,7 +8,8 @@ TaskHandle_t workerTaskHandle;
|
||||
esp_timer_handle_t screenRotateTimer;
|
||||
esp_timer_handle_t minuteTimer;
|
||||
|
||||
std::array<std::string, NUM_SCREENS> taskEpdContent = {"", "", "", "", "", "", ""};
|
||||
std::array<std::string, NUM_SCREENS> taskEpdContent = {"", "", "", "",
|
||||
"", "", ""};
|
||||
std::string priceString;
|
||||
|
||||
// typedef enum
|
||||
@ -29,65 +30,50 @@ QueueHandle_t workQueue = NULL;
|
||||
|
||||
uint currentScreen;
|
||||
|
||||
void workerTask(void *pvParameters)
|
||||
{
|
||||
void workerTask(void *pvParameters) {
|
||||
WorkItem receivedItem;
|
||||
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
// Wait for a work item to be available in the queue
|
||||
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY))
|
||||
{
|
||||
if (xQueueReceive(workQueue, &receivedItem, portMAX_DELAY)) {
|
||||
uint firstIndex = 0;
|
||||
|
||||
// Process the work item based on its type
|
||||
switch (receivedItem.type)
|
||||
{
|
||||
case TASK_PRICE_UPDATE:
|
||||
{
|
||||
switch (receivedItem.type) {
|
||||
case TASK_PRICE_UPDATE: {
|
||||
uint price = getPrice();
|
||||
char priceSymbol = '$';
|
||||
if (preferences.getBool("fetchEurPrice", false))
|
||||
{
|
||||
if (preferences.getBool("fetchEurPrice", false)) {
|
||||
priceSymbol = '[';
|
||||
}
|
||||
if (getCurrentScreen() == SCREEN_BTC_TICKER)
|
||||
{
|
||||
if (getCurrentScreen() == SCREEN_BTC_TICKER) {
|
||||
taskEpdContent = parsePriceData(price, priceSymbol);
|
||||
}
|
||||
else if (getCurrentScreen() == SCREEN_MSCW_TIME)
|
||||
{
|
||||
} else if (getCurrentScreen() == SCREEN_MSCW_TIME) {
|
||||
taskEpdContent = parseSatsPerCurrency(price, priceSymbol);
|
||||
}
|
||||
else
|
||||
{
|
||||
taskEpdContent = parseMarketCap(getBlockHeight(), price, priceSymbol, preferences.getBool("mcapBigChar", true));
|
||||
} else {
|
||||
taskEpdContent =
|
||||
parseMarketCap(getBlockHeight(), price, priceSymbol,
|
||||
preferences.getBool("mcapBigChar", true));
|
||||
}
|
||||
|
||||
setEpdContent(taskEpdContent);
|
||||
break;
|
||||
}
|
||||
case TASK_BLOCK_UPDATE:
|
||||
{
|
||||
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN)
|
||||
{
|
||||
case TASK_BLOCK_UPDATE: {
|
||||
if (getCurrentScreen() != SCREEN_HALVING_COUNTDOWN) {
|
||||
taskEpdContent = parseBlockHeight(getBlockHeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
taskEpdContent = parseHalvingCountdown(getBlockHeight());
|
||||
}
|
||||
|
||||
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN || getCurrentScreen() == SCREEN_BLOCK_HEIGHT)
|
||||
{
|
||||
if (getCurrentScreen() == SCREEN_HALVING_COUNTDOWN ||
|
||||
getCurrentScreen() == SCREEN_BLOCK_HEIGHT) {
|
||||
setEpdContent(taskEpdContent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TASK_TIME_UPDATE:
|
||||
{
|
||||
if (getCurrentScreen() == SCREEN_TIME)
|
||||
{
|
||||
case TASK_TIME_UPDATE: {
|
||||
if (getCurrentScreen() == SCREEN_TIME) {
|
||||
time_t currentTime;
|
||||
struct tm timeinfo;
|
||||
time(¤tTime);
|
||||
@ -95,17 +81,17 @@ void workerTask(void *pvParameters)
|
||||
std::string timeString;
|
||||
|
||||
String minute = String(timeinfo.tm_min);
|
||||
if (minute.length() < 2)
|
||||
{
|
||||
if (minute.length() < 2) {
|
||||
minute = "0" + minute;
|
||||
}
|
||||
|
||||
timeString = std::to_string(timeinfo.tm_hour) + ":" + minute.c_str();
|
||||
timeString.insert(timeString.begin(), NUM_SCREENS - timeString.length(), ' ');
|
||||
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" + std::to_string(timeinfo.tm_mon + 1);
|
||||
timeString.insert(timeString.begin(),
|
||||
NUM_SCREENS - timeString.length(), ' ');
|
||||
taskEpdContent[0] = std::to_string(timeinfo.tm_mday) + "/" +
|
||||
std::to_string(timeinfo.tm_mon + 1);
|
||||
|
||||
for (uint i = 1; i < NUM_SCREENS; i++)
|
||||
{
|
||||
for (uint i = 1; i < NUM_SCREENS; i++) {
|
||||
taskEpdContent[i] = timeString[i];
|
||||
}
|
||||
setEpdContent(taskEpdContent);
|
||||
@ -119,17 +105,14 @@ void workerTask(void *pvParameters)
|
||||
}
|
||||
}
|
||||
|
||||
void taskScreenRotate(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
void taskScreenRotate(void *pvParameters) {
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
|
||||
int nextScreen = (currentScreen + 1) % SCREEN_COUNT;
|
||||
String key = "screen" + String(nextScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
nextScreen = (nextScreen + 1) % SCREEN_COUNT;
|
||||
key = "screen" + String(nextScreen) + "Visible";
|
||||
}
|
||||
@ -138,52 +121,48 @@ void taskScreenRotate(void *pvParameters)
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR minuteTimerISR(void *arg)
|
||||
{
|
||||
void IRAM_ATTR minuteTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
// vTaskNotifyGiveFromISR(timeUpdateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSendFromISR(workQueue, &timeUpdate, &xHigherPriorityTaskWoken);
|
||||
if (priceFetchTaskHandle != NULL)
|
||||
{
|
||||
if (priceFetchTaskHandle != NULL) {
|
||||
vTaskNotifyGiveFromISR(priceFetchTaskHandle, &xHigherPriorityTaskWoken);
|
||||
}
|
||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
||||
{
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg)
|
||||
{
|
||||
void IRAM_ATTR screenRotateTimerISR(void *arg) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
vTaskNotifyGiveFromISR(taskScreenRotateTaskHandle, &xHigherPriorityTaskWoken);
|
||||
if (xHigherPriorityTaskWoken == pdTRUE)
|
||||
{
|
||||
if (xHigherPriorityTaskWoken == pdTRUE) {
|
||||
portYIELD_FROM_ISR();
|
||||
}
|
||||
}
|
||||
|
||||
void setupTasks()
|
||||
{
|
||||
void setupTasks() {
|
||||
workQueue = xQueueCreate(WORK_QUEUE_SIZE, sizeof(WorkItem));
|
||||
|
||||
// xTaskCreate(taskPriceUpdate, "updatePrice", 1024, NULL, tskIDLE_PRIORITY, &priceUpdateTaskHandle);
|
||||
// xTaskCreate(taskBlockUpdate, "updateBlock", 1024, NULL, tskIDLE_PRIORITY, &blockUpdateTaskHandle);
|
||||
// xTaskCreate(taskTimeUpdate, "updateTime", 1024, NULL, tskIDLE_PRIORITY, &timeUpdateTaskHandle);
|
||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY, &workerTaskHandle);
|
||||
// xTaskCreate(taskPriceUpdate, "updatePrice", 1024, NULL, tskIDLE_PRIORITY,
|
||||
// &priceUpdateTaskHandle); xTaskCreate(taskBlockUpdate, "updateBlock", 1024,
|
||||
// NULL, tskIDLE_PRIORITY, &blockUpdateTaskHandle);
|
||||
// xTaskCreate(taskTimeUpdate, "updateTime", 1024, NULL, tskIDLE_PRIORITY,
|
||||
// &timeUpdateTaskHandle);
|
||||
xTaskCreate(workerTask, "workerTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&workerTaskHandle);
|
||||
|
||||
xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY, &taskScreenRotateTaskHandle);
|
||||
xTaskCreate(taskScreenRotate, "rotateScreen", 2048, NULL, tskIDLE_PRIORITY,
|
||||
&taskScreenRotateTaskHandle);
|
||||
|
||||
waitUntilNoneBusy();
|
||||
setCurrentScreen(preferences.getUInt("currentScreen", 0));
|
||||
}
|
||||
|
||||
void setupTimeUpdateTimer(void *pvParameters)
|
||||
{
|
||||
void setupTimeUpdateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t minuteTimerConfig = {
|
||||
.callback = &minuteTimerISR,
|
||||
.name = "minute_timer"};
|
||||
.callback = &minuteTimerISR, .name = "minute_timer"};
|
||||
|
||||
esp_timer_create(&minuteTimerConfig, &minuteTimer);
|
||||
|
||||
@ -205,42 +184,31 @@ void setupTimeUpdateTimer(void *pvParameters)
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void setupScreenRotateTimer(void *pvParameters)
|
||||
{
|
||||
void setupScreenRotateTimer(void *pvParameters) {
|
||||
const esp_timer_create_args_t screenRotateTimerConfig = {
|
||||
.callback = &screenRotateTimerISR,
|
||||
.name = "screen_rotate_timer"};
|
||||
.callback = &screenRotateTimerISR, .name = "screen_rotate_timer"};
|
||||
|
||||
esp_timer_create(&screenRotateTimerConfig, &screenRotateTimer);
|
||||
|
||||
if (preferences.getBool("timerActive", true))
|
||||
{
|
||||
esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond);
|
||||
if (preferences.getBool("timerActive", true)) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
uint getTimerSeconds()
|
||||
{
|
||||
return preferences.getUInt("timerSeconds", 1800);
|
||||
}
|
||||
uint getTimerSeconds() { return preferences.getUInt("timerSeconds", 1800); }
|
||||
|
||||
bool isTimerActive()
|
||||
{
|
||||
return esp_timer_is_active(screenRotateTimer);
|
||||
}
|
||||
bool isTimerActive() { return esp_timer_is_active(screenRotateTimer); }
|
||||
|
||||
void setTimerActive(bool status)
|
||||
{
|
||||
if (status)
|
||||
{
|
||||
esp_timer_start_periodic(screenRotateTimer, getTimerSeconds() * usPerSecond);
|
||||
void setTimerActive(bool status) {
|
||||
if (status) {
|
||||
esp_timer_start_periodic(screenRotateTimer,
|
||||
getTimerSeconds() * usPerSecond);
|
||||
queueLedEffect(LED_EFFECT_START_TIMER);
|
||||
preferences.putBool("timerActive", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
esp_timer_stop(screenRotateTimer);
|
||||
queueLedEffect(LED_EFFECT_PAUSE_TIMER);
|
||||
preferences.putBool("timerActive", false);
|
||||
@ -250,37 +218,26 @@ void setTimerActive(bool status)
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void toggleTimerActive()
|
||||
{
|
||||
setTimerActive(!isTimerActive());
|
||||
}
|
||||
void toggleTimerActive() { setTimerActive(!isTimerActive()); }
|
||||
|
||||
uint getCurrentScreen()
|
||||
{
|
||||
return currentScreen;
|
||||
}
|
||||
uint getCurrentScreen() { return currentScreen; }
|
||||
|
||||
void setCurrentScreen(uint newScreen)
|
||||
{
|
||||
if (newScreen != SCREEN_CUSTOM)
|
||||
{
|
||||
void setCurrentScreen(uint newScreen) {
|
||||
if (newScreen != SCREEN_CUSTOM) {
|
||||
preferences.putUInt("currentScreen", newScreen);
|
||||
}
|
||||
|
||||
currentScreen = newScreen;
|
||||
|
||||
switch (currentScreen)
|
||||
{
|
||||
case SCREEN_TIME:
|
||||
{
|
||||
switch (currentScreen) {
|
||||
case SCREEN_TIME: {
|
||||
WorkItem timeUpdate = {TASK_TIME_UPDATE, 0};
|
||||
xQueueSend(workQueue, &timeUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(timeUpdateTaskHandle);
|
||||
break;
|
||||
}
|
||||
case SCREEN_HALVING_COUNTDOWN:
|
||||
case SCREEN_BLOCK_HEIGHT:
|
||||
{
|
||||
case SCREEN_BLOCK_HEIGHT: {
|
||||
WorkItem blockUpdate = {TASK_BLOCK_UPDATE, 0};
|
||||
xQueueSend(workQueue, &blockUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(blockUpdateTaskHandle);
|
||||
@ -288,8 +245,7 @@ void setCurrentScreen(uint newScreen)
|
||||
}
|
||||
case SCREEN_MARKET_CAP:
|
||||
case SCREEN_MSCW_TIME:
|
||||
case SCREEN_BTC_TICKER:
|
||||
{
|
||||
case SCREEN_BTC_TICKER: {
|
||||
WorkItem priceUpdate = {TASK_PRICE_UPDATE, 0};
|
||||
xQueueSend(workQueue, &priceUpdate, portMAX_DELAY);
|
||||
// xTaskNotifyGive(priceUpdateTaskHandle);
|
||||
@ -301,36 +257,32 @@ void setCurrentScreen(uint newScreen)
|
||||
xTaskNotifyGive(eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void nextScreen()
|
||||
{
|
||||
void nextScreen() {
|
||||
int newCurrentScreen = (getCurrentScreen() + 1) % SCREEN_COUNT;
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
newCurrentScreen = (newCurrentScreen + 1) % SCREEN_COUNT;
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void previousScreen()
|
||||
{
|
||||
void previousScreen() {
|
||||
|
||||
int newCurrentScreen = modulo(getCurrentScreen() - 1, SCREEN_COUNT);
|
||||
String key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
|
||||
while (!preferences.getBool(key.c_str(), true))
|
||||
{
|
||||
while (!preferences.getBool(key.c_str(), true)) {
|
||||
newCurrentScreen = modulo(newCurrentScreen - 1, SCREEN_COUNT);
|
||||
key = "screen" + String(newCurrentScreen) + "Visible";
|
||||
}
|
||||
setCurrentScreen(newCurrentScreen);
|
||||
}
|
||||
|
||||
void showSystemStatusScreen()
|
||||
{
|
||||
std::array<String, NUM_SCREENS> sysStatusEpdContent = {"", "", "", "", "", "", ""};
|
||||
void showSystemStatusScreen() {
|
||||
std::array<String, NUM_SCREENS> sysStatusEpdContent = {"", "", "", "",
|
||||
"", "", ""};
|
||||
|
||||
String ipAddr = WiFi.localIP().toString();
|
||||
String subNet = WiFi.subnetMask().toString();
|
||||
@ -339,9 +291,9 @@ void showSystemStatusScreen()
|
||||
|
||||
int ipAddrPos = 0;
|
||||
int subnetPos = 0;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) + "/" + subNet.substring(0, subNet.indexOf('.'));
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sysStatusEpdContent[1 + i] = ipAddr.substring(0, ipAddr.indexOf('.')) +
|
||||
"/" + subNet.substring(0, subNet.indexOf('.'));
|
||||
ipAddrPos = ipAddr.indexOf('.') + 1;
|
||||
subnetPos = subNet.indexOf('.') + 1;
|
||||
ipAddr = ipAddr.substring(ipAddrPos);
|
||||
@ -349,7 +301,9 @@ void showSystemStatusScreen()
|
||||
}
|
||||
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);
|
||||
setEpdContent(sysStatusEpdContent);
|
||||
}
|
@ -2,13 +2,13 @@
|
||||
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include <data_handler.hpp>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <data_handler.hpp>
|
||||
|
||||
#include "price_fetch.hpp"
|
||||
#include "shared.hpp"
|
||||
#include "lib/epd.hpp"
|
||||
#include "lib/price_fetch.hpp"
|
||||
#include "lib/shared.hpp"
|
||||
|
||||
// extern TaskHandle_t priceUpdateTaskHandle;
|
||||
// extern TaskHandle_t blockUpdateTaskHandle;
|
||||
@ -21,15 +21,13 @@ extern esp_timer_handle_t minuteTimer;
|
||||
|
||||
extern QueueHandle_t workQueue;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
typedef enum {
|
||||
TASK_PRICE_UPDATE,
|
||||
TASK_BLOCK_UPDATE,
|
||||
TASK_TIME_UPDATE
|
||||
} TaskType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
TaskType type;
|
||||
char data;
|
||||
} WorkItem;
|
||||
|
@ -1,13 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <Adafruit_MCP23X17.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Preferences.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <mutex>
|
||||
|
||||
#include "utils.hpp"
|
||||
#include <utils.hpp>
|
||||
|
||||
extern Adafruit_MCP23X17 mcp1;
|
||||
#ifdef IS_BTCLOCK_S3
|
||||
@ -26,7 +26,9 @@ const PROGMEM int SCREEN_MARKET_CAP = 5;
|
||||
const PROGMEM int SCREEN_COUNTDOWN = 98;
|
||||
const PROGMEM int SCREEN_CUSTOM = 99;
|
||||
const int SCREEN_COUNT = 6;
|
||||
const PROGMEM int screens[SCREEN_COUNT] = { SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER, SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP };
|
||||
const PROGMEM int screens[SCREEN_COUNT] = {
|
||||
SCREEN_BLOCK_HEIGHT, SCREEN_MSCW_TIME, SCREEN_BTC_TICKER,
|
||||
SCREEN_TIME, SCREEN_HALVING_COUNTDOWN, SCREEN_MARKET_CAP};
|
||||
const int usPerSecond = 1000000;
|
||||
const int usPerMinute = 60 * usPerSecond;
|
||||
|
||||
@ -35,9 +37,7 @@ struct SpiRamAllocator {
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
void deallocate(void* pointer) {
|
||||
heap_caps_free(pointer);
|
||||
}
|
||||
void deallocate(void *pointer) { heap_caps_free(pointer); }
|
||||
|
||||
void *reallocate(void *ptr, size_t new_size) {
|
||||
return heap_caps_realloc(ptr, new_size, MALLOC_CAP_SPIRAM);
|
||||
@ -45,4 +45,3 @@ struct SpiRamAllocator {
|
||||
};
|
||||
|
||||
using SpiRamJsonDocument = BasicJsonDocument<SpiRamAllocator>;
|
||||
|
||||
|
@ -4,11 +4,11 @@ AsyncWebServer server(80);
|
||||
AsyncEventSource events("/events");
|
||||
TaskHandle_t eventSourceTaskHandle;
|
||||
|
||||
void setupWebserver()
|
||||
{
|
||||
void setupWebserver() {
|
||||
|
||||
events.onConnect([](AsyncEventSourceClient *client)
|
||||
{ client->send("welcome", NULL, millis(), 1000); });
|
||||
events.onConnect([](AsyncEventSourceClient *client) {
|
||||
client->send("welcome", NULL, millis(), 1000);
|
||||
});
|
||||
server.addHandler(&events);
|
||||
|
||||
// server.serveStatic("/css", LittleFS, "/css/");
|
||||
@ -34,42 +34,48 @@ void setupWebserver()
|
||||
server.on("/api/show/screen", HTTP_GET, onApiShowScreen);
|
||||
server.on("/api/show/text", HTTP_GET, onApiShowText);
|
||||
|
||||
AsyncCallbackJsonWebHandler *settingsPatchHandler = new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch);
|
||||
AsyncCallbackJsonWebHandler *settingsPatchHandler =
|
||||
new AsyncCallbackJsonWebHandler("/api/json/settings", onApiSettingsPatch);
|
||||
server.addHandler(settingsPatchHandler);
|
||||
|
||||
AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler("/api/show/custom", onApiShowTextAdvanced);
|
||||
AsyncCallbackJsonWebHandler *handler = new AsyncCallbackJsonWebHandler(
|
||||
"/api/show/custom", onApiShowTextAdvanced);
|
||||
server.addHandler(handler);
|
||||
|
||||
AsyncCallbackJsonWebHandler *lightsJsonHandler = new AsyncCallbackJsonWebHandler("/api/lights", onApiLightsSetJson);
|
||||
AsyncCallbackJsonWebHandler *lightsJsonHandler =
|
||||
new AsyncCallbackJsonWebHandler("/api/lights", onApiLightsSetJson);
|
||||
server.addHandler(lightsJsonHandler);
|
||||
|
||||
server.on("/api/lights/off", HTTP_GET, onApiLightsOff);
|
||||
server.on("/api/lights/color", HTTP_GET, onApiLightsSetColor);
|
||||
server.on("/api/lights", HTTP_GET, onApiLightsStatus);
|
||||
|
||||
// server.on("^\\/api\\/lights\\/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", HTTP_GET, onApiLightsSetColor);
|
||||
// server.on("^\\/api\\/lights\\/([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$", HTTP_GET,
|
||||
// onApiLightsSetColor);
|
||||
|
||||
server.on("/api/restart", HTTP_GET, onApiRestart);
|
||||
server.addRewrite(new OneParamRewrite("/api/lights/{color}", "/api/lights/color?c={color}"));
|
||||
server.addRewrite(new OneParamRewrite("/api/show/screen/{s}", "/api/show/screen?s={s}"));
|
||||
server.addRewrite(new OneParamRewrite("/api/show/text/{text}", "/api/show/text?t={text}"));
|
||||
server.addRewrite(new OneParamRewrite("/api/show/number/{number}", "/api/show/text?t={text}"));
|
||||
server.addRewrite(new OneParamRewrite("/api/lights/{color}",
|
||||
"/api/lights/color?c={color}"));
|
||||
server.addRewrite(
|
||||
new OneParamRewrite("/api/show/screen/{s}", "/api/show/screen?s={s}"));
|
||||
server.addRewrite(
|
||||
new OneParamRewrite("/api/show/text/{text}", "/api/show/text?t={text}"));
|
||||
server.addRewrite(new OneParamRewrite("/api/show/number/{number}",
|
||||
"/api/show/text?t={text}"));
|
||||
|
||||
server.onNotFound(onNotFound);
|
||||
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Origin", "*");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods", "GET, PATCH, POST, OPTIONS");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Methods",
|
||||
"GET, PATCH, POST, OPTIONS");
|
||||
DefaultHeaders::Instance().addHeader("Access-Control-Allow-Headers", "*");
|
||||
|
||||
server.begin();
|
||||
|
||||
if (preferences.getBool("mdnsEnabled", true))
|
||||
{
|
||||
if (!MDNS.begin(getMyHostname()))
|
||||
{
|
||||
if (preferences.getBool("mdnsEnabled", true)) {
|
||||
if (!MDNS.begin(getMyHostname())) {
|
||||
Serial.println(F("Error setting up MDNS responder!"));
|
||||
while (1)
|
||||
{
|
||||
while (1) {
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
@ -79,16 +85,13 @@ void setupWebserver()
|
||||
MDNS.addServiceTxt("http", "tcp", "rev", GIT_REV);
|
||||
}
|
||||
|
||||
xTaskCreate(eventSourceTask, "eventSourceTask", 4096, NULL, tskIDLE_PRIORITY, &eventSourceTaskHandle);
|
||||
xTaskCreate(eventSourceTask, "eventSourceTask", 4096, NULL, tskIDLE_PRIORITY,
|
||||
&eventSourceTaskHandle);
|
||||
}
|
||||
|
||||
void stopWebServer()
|
||||
{
|
||||
server.end();
|
||||
}
|
||||
void stopWebServer() { server.end(); }
|
||||
|
||||
StaticJsonDocument<768> getStatusObject()
|
||||
{
|
||||
StaticJsonDocument<768> getStatusObject() {
|
||||
StaticJsonDocument<768> root;
|
||||
|
||||
root["currentScreen"] = getCurrentScreen();
|
||||
@ -111,14 +114,12 @@ StaticJsonDocument<768> getStatusObject()
|
||||
return root;
|
||||
}
|
||||
|
||||
StaticJsonDocument<512> getLedStatusObject()
|
||||
{
|
||||
StaticJsonDocument<512> getLedStatusObject() {
|
||||
StaticJsonDocument<512> root;
|
||||
JsonArray colors = root.createNestedArray("data");
|
||||
// Adafruit_NeoPixel pix = getPixels();
|
||||
|
||||
for (uint i = 0; i < pixels.numPixels(); i++)
|
||||
{
|
||||
for (uint i = 0; i < pixels.numPixels(); i++) {
|
||||
uint32_t pixColor = pixels.getPixelColor(pixels.numPixels() - i - 1);
|
||||
uint alpha = (pixColor >> 24) & 0xFF;
|
||||
uint red = (pixColor >> 16) & 0xFF;
|
||||
@ -137,8 +138,7 @@ StaticJsonDocument<512> getLedStatusObject()
|
||||
return root;
|
||||
}
|
||||
|
||||
void eventSourceUpdate()
|
||||
{
|
||||
void eventSourceUpdate() {
|
||||
if (!events.count())
|
||||
return;
|
||||
StaticJsonDocument<768> root = getStatusObject();
|
||||
@ -162,9 +162,9 @@ void eventSourceUpdate()
|
||||
* @Api
|
||||
* @Path("/api/status")
|
||||
*/
|
||||
void onApiStatus(AsyncWebServerRequest *request)
|
||||
{
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
void onApiStatus(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *response =
|
||||
request->beginResponseStream("application/json");
|
||||
|
||||
StaticJsonDocument<1024> root = getStatusObject();
|
||||
JsonArray data = root.createNestedArray("data");
|
||||
@ -188,8 +188,7 @@ void onApiStatus(AsyncWebServerRequest *request)
|
||||
* @Api
|
||||
* @Path("/api/action/pause")
|
||||
*/
|
||||
void onApiActionPause(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiActionPause(AsyncWebServerRequest *request) {
|
||||
setTimerActive(false);
|
||||
request->send(200);
|
||||
};
|
||||
@ -198,8 +197,7 @@ void onApiActionPause(AsyncWebServerRequest *request)
|
||||
* @Api
|
||||
* @Path("/api/action/timer_restart")
|
||||
*/
|
||||
void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiActionTimerRestart(AsyncWebServerRequest *request) {
|
||||
setTimerActive(true);
|
||||
request->send(200);
|
||||
}
|
||||
@ -208,8 +206,7 @@ void onApiActionTimerRestart(AsyncWebServerRequest *request)
|
||||
* @Api
|
||||
* @Path("/api/full_refresh")
|
||||
*/
|
||||
void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiFullRefresh(AsyncWebServerRequest *request) {
|
||||
forceFullRefresh();
|
||||
std::array<String, NUM_SCREENS> newEpdContent = getCurrentEpdContent();
|
||||
|
||||
@ -222,10 +219,8 @@ void onApiFullRefresh(AsyncWebServerRequest *request)
|
||||
* @Api
|
||||
* @Path("/api/show/screen")
|
||||
*/
|
||||
void onApiShowScreen(AsyncWebServerRequest *request)
|
||||
{
|
||||
if (request->hasParam("s"))
|
||||
{
|
||||
void onApiShowScreen(AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("s")) {
|
||||
AsyncWebParameter *p = request->getParam("s");
|
||||
uint currentScreen = p->value().toInt();
|
||||
setCurrentScreen(currentScreen);
|
||||
@ -233,17 +228,14 @@ void onApiShowScreen(AsyncWebServerRequest *request)
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiShowText(AsyncWebServerRequest *request)
|
||||
{
|
||||
if (request->hasParam("t"))
|
||||
{
|
||||
void onApiShowText(AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("t")) {
|
||||
AsyncWebParameter *p = request->getParam("t");
|
||||
String t = p->value();
|
||||
t.toUpperCase(); // This is needed as long as lowercase letters are glitchy
|
||||
|
||||
std::array<String, NUM_SCREENS> textEpdContent;
|
||||
for (uint i = 0; i < NUM_SCREENS; i++)
|
||||
{
|
||||
for (uint i = 0; i < NUM_SCREENS; i++) {
|
||||
textEpdContent[i] = t[i];
|
||||
}
|
||||
|
||||
@ -253,14 +245,12 @@ void onApiShowText(AsyncWebServerRequest *request)
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
{
|
||||
void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||
JsonArray screens = json.as<JsonArray>();
|
||||
|
||||
std::array<String, NUM_SCREENS> epdContent;
|
||||
int i = 0;
|
||||
for (JsonVariant s : screens)
|
||||
{
|
||||
for (JsonVariant s : screens) {
|
||||
epdContent[i] = s.as<String>();
|
||||
i++;
|
||||
}
|
||||
@ -271,14 +261,12 @@ void onApiShowTextAdvanced(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
{
|
||||
void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||
JsonObject settings = json.as<JsonObject>();
|
||||
|
||||
bool settingsChanged = true;
|
||||
|
||||
if (settings.containsKey("fgColor"))
|
||||
{
|
||||
if (settings.containsKey("fgColor")) {
|
||||
String fgColor = settings["fgColor"].as<String>();
|
||||
preferences.putUInt("fgColor", strtol(fgColor.c_str(), NULL, 16));
|
||||
setFgColor(int(strtol(fgColor.c_str(), NULL, 16)));
|
||||
@ -286,8 +274,7 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
Serial.println(strtol(fgColor.c_str(), NULL, 16));
|
||||
settingsChanged = true;
|
||||
}
|
||||
if (settings.containsKey("bgColor"))
|
||||
{
|
||||
if (settings.containsKey("bgColor")) {
|
||||
String bgColor = settings["bgColor"].as<String>();
|
||||
|
||||
preferences.putUInt("bgColor", strtol(bgColor.c_str(), NULL, 16));
|
||||
@ -297,56 +284,52 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (settings.containsKey("timePerScreen"))
|
||||
{
|
||||
preferences.putUInt("timerSeconds", settings["timePerScreen"].as<uint>() * 60);
|
||||
if (settings.containsKey("timePerScreen")) {
|
||||
preferences.putUInt("timerSeconds",
|
||||
settings["timePerScreen"].as<uint>() * 60);
|
||||
}
|
||||
|
||||
String strSettings[] = {"hostnamePrefix", "mempoolInstance"};
|
||||
|
||||
for (String setting : strSettings)
|
||||
{
|
||||
if (settings.containsKey(setting))
|
||||
{
|
||||
for (String setting : strSettings) {
|
||||
if (settings.containsKey(setting)) {
|
||||
preferences.putString(setting.c_str(), settings[setting].as<String>());
|
||||
Serial.printf("Setting %s to %s\r\n", setting.c_str(), settings[setting].as<String>());
|
||||
Serial.printf("Setting %s to %s\r\n", setting.c_str(),
|
||||
settings[setting].as<String>());
|
||||
}
|
||||
}
|
||||
|
||||
String uintSettings[] = {"minSecPriceUpd", "fullRefreshMin", "ledBrightness"};
|
||||
|
||||
for (String setting : uintSettings)
|
||||
{
|
||||
if (settings.containsKey(setting))
|
||||
{
|
||||
for (String setting : uintSettings) {
|
||||
if (settings.containsKey(setting)) {
|
||||
preferences.putUInt(setting.c_str(), settings[setting].as<uint>());
|
||||
Serial.printf("Setting %s to %d\r\n", setting.c_str(), settings[setting].as<uint>());
|
||||
Serial.printf("Setting %s to %d\r\n", setting.c_str(),
|
||||
settings[setting].as<uint>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (settings.containsKey("tzOffset"))
|
||||
{
|
||||
if (settings.containsKey("tzOffset")) {
|
||||
int gmtOffset = settings["tzOffset"].as<int>() * 60;
|
||||
size_t written = preferences.putInt("gmtOffset", gmtOffset);
|
||||
Serial.printf("Setting %s to %d (%d minutes, written %d)\r\n", "gmtOffset", gmtOffset, settings["tzOffset"].as<int>(), written);
|
||||
Serial.printf("Setting %s to %d (%d minutes, written %d)\r\n", "gmtOffset",
|
||||
gmtOffset, settings["tzOffset"].as<int>(), written);
|
||||
}
|
||||
|
||||
String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd", "mdnsEnabled", "otaEnabled", "stealFocus", "mcapBigChar"};
|
||||
String boolSettings[] = {"fetchEurPrice", "ledTestOnPower", "ledFlashOnUpd",
|
||||
"mdnsEnabled", "otaEnabled", "stealFocus",
|
||||
"mcapBigChar"};
|
||||
|
||||
for (String setting : boolSettings)
|
||||
{
|
||||
if (settings.containsKey(setting))
|
||||
{
|
||||
for (String setting : boolSettings) {
|
||||
if (settings.containsKey(setting)) {
|
||||
preferences.putBool(setting.c_str(), settings[setting].as<boolean>());
|
||||
Serial.printf("Setting %s to %d\r\n", setting.c_str(), settings[setting].as<boolean>());
|
||||
Serial.printf("Setting %s to %d\r\n", setting.c_str(),
|
||||
settings[setting].as<boolean>());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.containsKey("screens"))
|
||||
{
|
||||
for (JsonVariant screen : settings["screens"].as<JsonArray>())
|
||||
{
|
||||
if (settings.containsKey("screens")) {
|
||||
for (JsonVariant screen : settings["screens"].as<JsonArray>()) {
|
||||
JsonObject s = screen.as<JsonObject>();
|
||||
uint id = s["id"].as<uint>();
|
||||
String key = "screen[" + String(id) + "]";
|
||||
@ -364,11 +347,11 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
if (WiFi.getTxPower() != 80) {
|
||||
ESP.restart();
|
||||
}
|
||||
} else if (static_cast<int>(wifi_power_t::WIFI_POWER_MINUS_1dBm) <= txPower &&
|
||||
} else if (static_cast<int>(wifi_power_t::WIFI_POWER_MINUS_1dBm) <=
|
||||
txPower &&
|
||||
txPower <= static_cast<int>(wifi_power_t::WIFI_POWER_19_5dBm)) {
|
||||
// is valid value
|
||||
|
||||
|
||||
if (WiFi.setTxPower(static_cast<wifi_power_t>(txPower))) {
|
||||
Serial.printf("Set WiFi Tx power to: %d\n", txPower);
|
||||
preferences.putInt("txPower", txPower);
|
||||
@ -378,14 +361,12 @@ void onApiSettingsPatch(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
}
|
||||
|
||||
request->send(200);
|
||||
if (settingsChanged)
|
||||
{
|
||||
if (settingsChanged) {
|
||||
queueLedEffect(LED_FLASH_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void onApiRestart(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiRestart(AsyncWebServerRequest *request) {
|
||||
request->send(200);
|
||||
|
||||
if (events.count())
|
||||
@ -401,20 +382,22 @@ void onApiRestart(AsyncWebServerRequest *request)
|
||||
* @Method GET
|
||||
* @Path("/api/settings")
|
||||
*/
|
||||
void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiSettingsGet(AsyncWebServerRequest *request) {
|
||||
StaticJsonDocument<1536> root;
|
||||
root["numScreens"] = NUM_SCREENS;
|
||||
root["fgColor"] = getFgColor();
|
||||
root["bgColor"] = getBgColor();
|
||||
root["timerSeconds"] = getTimerSeconds();
|
||||
root["timerRunning"] = isTimerActive();
|
||||
root["minSecPriceUpd"] = preferences.getUInt("minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
root["fullRefreshMin"] = preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH);
|
||||
root["minSecPriceUpd"] = preferences.getUInt(
|
||||
"minSecPriceUpd", DEFAULT_SECONDS_BETWEEN_PRICE_UPDATE);
|
||||
root["fullRefreshMin"] =
|
||||
preferences.getUInt("fullRefreshMin", DEFAULT_MINUTES_FULL_REFRESH);
|
||||
root["wpTimeout"] = preferences.getUInt("wpTimeout", 600);
|
||||
root["tzOffset"] = preferences.getInt("gmtOffset", TIME_OFFSET_SECONDS) / 60;
|
||||
root["useBitcoinNode"] = preferences.getBool("useNode", false);
|
||||
root["mempoolInstance"] = preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
root["mempoolInstance"] =
|
||||
preferences.getString("mempoolInstance", DEFAULT_MEMPOOL_INSTANCE);
|
||||
root["ledTestOnPower"] = preferences.getBool("ledTestOnPower", true);
|
||||
root["ledFlashOnUpd"] = preferences.getBool("ledFlashOnUpd", false);
|
||||
root["ledBrightness"] = preferences.getUInt("ledBrightness", 128);
|
||||
@ -438,8 +421,7 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||
|
||||
std::vector<std::string> screenNameMap = getScreenNameMap();
|
||||
|
||||
for (int i = 0; i < screenNameMap.size(); i++)
|
||||
{
|
||||
for (int i = 0; i < screenNameMap.size(); i++) {
|
||||
JsonObject o = screens.createNestedObject();
|
||||
String key = "screen" + String(i) + "Visible";
|
||||
o["id"] = i;
|
||||
@ -447,17 +429,16 @@ void onApiSettingsGet(AsyncWebServerRequest *request)
|
||||
o["enabled"] = preferences.getBool(key.c_str(), true);
|
||||
}
|
||||
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
AsyncResponseStream *response =
|
||||
request->beginResponseStream("application/json");
|
||||
serializeJson(root, *response);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
bool processEpdColorSettings(AsyncWebServerRequest *request)
|
||||
{
|
||||
bool processEpdColorSettings(AsyncWebServerRequest *request) {
|
||||
bool settingsChanged = false;
|
||||
if (request->hasParam("fgColor", true))
|
||||
{
|
||||
if (request->hasParam("fgColor", true)) {
|
||||
AsyncWebParameter *fgColor = request->getParam("fgColor", true);
|
||||
preferences.putUInt("fgColor", strtol(fgColor->value().c_str(), NULL, 16));
|
||||
setFgColor(int(strtol(fgColor->value().c_str(), NULL, 16)));
|
||||
@ -465,8 +446,7 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
|
||||
// Serial.println(fgColor->value().c_str());
|
||||
settingsChanged = true;
|
||||
}
|
||||
if (request->hasParam("bgColor", true))
|
||||
{
|
||||
if (request->hasParam("bgColor", true)) {
|
||||
AsyncWebParameter *bgColor = request->getParam("bgColor", true);
|
||||
|
||||
preferences.putUInt("bgColor", strtol(bgColor->value().c_str(), NULL, 16));
|
||||
@ -479,163 +459,136 @@ bool processEpdColorSettings(AsyncWebServerRequest *request)
|
||||
return settingsChanged;
|
||||
}
|
||||
|
||||
void onApiSettingsPost(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiSettingsPost(AsyncWebServerRequest *request) {
|
||||
bool settingsChanged = false;
|
||||
|
||||
settingsChanged = processEpdColorSettings(request);
|
||||
|
||||
int headers = request->headers();
|
||||
int i;
|
||||
for (i = 0; i < headers; 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++)
|
||||
{
|
||||
for (int i = 0; i < params; i++) {
|
||||
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())
|
||||
{
|
||||
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
|
||||
{
|
||||
} else {
|
||||
Serial.printf("GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (request->hasParam("fetchEurPrice", true))
|
||||
{
|
||||
if (request->hasParam("fetchEurPrice", true)) {
|
||||
AsyncWebParameter *fetchEurPrice = request->getParam("fetchEurPrice", true);
|
||||
|
||||
preferences.putBool("fetchEurPrice", fetchEurPrice->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("fetchEurPrice", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("ledTestOnPower", true))
|
||||
{
|
||||
AsyncWebParameter *ledTestOnPower = request->getParam("ledTestOnPower", true);
|
||||
if (request->hasParam("ledTestOnPower", true)) {
|
||||
AsyncWebParameter *ledTestOnPower =
|
||||
request->getParam("ledTestOnPower", true);
|
||||
|
||||
preferences.putBool("ledTestOnPower", ledTestOnPower->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("ledTestOnPower", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("ledFlashOnUpd", true))
|
||||
{
|
||||
AsyncWebParameter *ledFlashOnUpdate = request->getParam("ledFlashOnUpd", true);
|
||||
if (request->hasParam("ledFlashOnUpd", true)) {
|
||||
AsyncWebParameter *ledFlashOnUpdate =
|
||||
request->getParam("ledFlashOnUpd", true);
|
||||
|
||||
preferences.putBool("ledFlashOnUpd", ledFlashOnUpdate->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("ledFlashOnUpd", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("mdnsEnabled", true))
|
||||
{
|
||||
if (request->hasParam("mdnsEnabled", true)) {
|
||||
AsyncWebParameter *mdnsEnabled = request->getParam("mdnsEnabled", true);
|
||||
|
||||
preferences.putBool("mdnsEnabled", mdnsEnabled->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("mdnsEnabled", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("otaEnabled", true))
|
||||
{
|
||||
if (request->hasParam("otaEnabled", true)) {
|
||||
AsyncWebParameter *otaEnabled = request->getParam("otaEnabled", true);
|
||||
|
||||
preferences.putBool("otaEnabled", otaEnabled->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("otaEnabled", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("stealFocusOnBlock", true))
|
||||
{
|
||||
AsyncWebParameter *stealFocusOnBlock = request->getParam("stealFocusOnBlock", true);
|
||||
if (request->hasParam("stealFocusOnBlock", true)) {
|
||||
AsyncWebParameter *stealFocusOnBlock =
|
||||
request->getParam("stealFocusOnBlock", true);
|
||||
|
||||
preferences.putBool("stealFocus", stealFocusOnBlock->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("stealFocus", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("mcapBigChar", true))
|
||||
{
|
||||
if (request->hasParam("mcapBigChar", true)) {
|
||||
AsyncWebParameter *mcapBigChar = request->getParam("mcapBigChar", true);
|
||||
|
||||
preferences.putBool("mcapBigChar", mcapBigChar->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
preferences.putBool("mcapBigChar", 0);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("mempoolInstance", true))
|
||||
{
|
||||
AsyncWebParameter *mempoolInstance = request->getParam("mempoolInstance", true);
|
||||
if (request->hasParam("mempoolInstance", true)) {
|
||||
AsyncWebParameter *mempoolInstance =
|
||||
request->getParam("mempoolInstance", true);
|
||||
|
||||
preferences.putString("mempoolInstance", mempoolInstance->value().c_str());
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("hostnamePrefix", true))
|
||||
{
|
||||
AsyncWebParameter *hostnamePrefix = request->getParam("hostnamePrefix", true);
|
||||
if (request->hasParam("hostnamePrefix", true)) {
|
||||
AsyncWebParameter *hostnamePrefix =
|
||||
request->getParam("hostnamePrefix", true);
|
||||
|
||||
preferences.putString("hostnamePrefix", hostnamePrefix->value().c_str());
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("ledBrightness", true))
|
||||
{
|
||||
if (request->hasParam("ledBrightness", true)) {
|
||||
AsyncWebParameter *ledBrightness = request->getParam("ledBrightness", true);
|
||||
|
||||
preferences.putUInt("ledBrightness", ledBrightness->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("fullRefreshMin", true))
|
||||
{
|
||||
AsyncWebParameter *fullRefreshMin = request->getParam("fullRefreshMin", true);
|
||||
if (request->hasParam("fullRefreshMin", true)) {
|
||||
AsyncWebParameter *fullRefreshMin =
|
||||
request->getParam("fullRefreshMin", true);
|
||||
|
||||
preferences.putUInt("fullRefreshMin", fullRefreshMin->value().toInt());
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("wpTimeout", true))
|
||||
{
|
||||
if (request->hasParam("wpTimeout", true)) {
|
||||
AsyncWebParameter *wpTimeout = request->getParam("wpTimeout", true);
|
||||
|
||||
preferences.putUInt("wpTimeout", wpTimeout->value().toInt());
|
||||
@ -644,20 +597,17 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
||||
|
||||
std::vector<std::string> screenNameMap = getScreenNameMap();
|
||||
|
||||
if (request->hasParam("screens"))
|
||||
{
|
||||
if (request->hasParam("screens")) {
|
||||
AsyncWebParameter *screenParam = request->getParam("screens", true);
|
||||
|
||||
Serial.printf(screenParam->value().c_str());
|
||||
}
|
||||
|
||||
for (int i = 0; i < screenNameMap.size(); i++)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (request->hasParam(key, true)) {
|
||||
AsyncWebParameter *screenParam = request->getParam(key, true);
|
||||
visible = screenParam->value().toInt();
|
||||
}
|
||||
@ -665,24 +615,21 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
||||
preferences.putBool(prefKey.c_str(), visible);
|
||||
}
|
||||
|
||||
if (request->hasParam("tzOffset", true))
|
||||
{
|
||||
if (request->hasParam("tzOffset", true)) {
|
||||
AsyncWebParameter *p = request->getParam("tzOffset", true);
|
||||
int tzOffsetSeconds = p->value().toInt() * 60;
|
||||
preferences.putInt("gmtOffset", tzOffsetSeconds);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("minSecPriceUpd", true))
|
||||
{
|
||||
if (request->hasParam("minSecPriceUpd", true)) {
|
||||
AsyncWebParameter *p = request->getParam("minSecPriceUpd", true);
|
||||
int minSecPriceUpd = p->value().toInt();
|
||||
preferences.putUInt("minSecPriceUpd", minSecPriceUpd);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
if (request->hasParam("timePerScreen", true))
|
||||
{
|
||||
if (request->hasParam("timePerScreen", true)) {
|
||||
AsyncWebParameter *p = request->getParam("timePerScreen", true);
|
||||
uint timerSeconds = p->value().toInt() * 60;
|
||||
preferences.putUInt("timerSeconds", timerSeconds);
|
||||
@ -690,15 +637,14 @@ void onApiSettingsPost(AsyncWebServerRequest *request)
|
||||
}
|
||||
|
||||
request->send(200);
|
||||
if (settingsChanged)
|
||||
{
|
||||
if (settingsChanged) {
|
||||
queueLedEffect(LED_FLASH_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
void onApiSystemStatus(AsyncWebServerRequest *request)
|
||||
{
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
void onApiSystemStatus(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *response =
|
||||
request->beginResponseStream("application/json");
|
||||
|
||||
StaticJsonDocument<128> root;
|
||||
|
||||
@ -717,16 +663,17 @@ void onApiSystemStatus(AsyncWebServerRequest *request)
|
||||
#define STRINGIFY(x) #x
|
||||
#define ENUM_TO_STRING(x) STRINGIFY(x)
|
||||
|
||||
|
||||
void onApiSetWifiTxPower(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiSetWifiTxPower(AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("txPower")) {
|
||||
AsyncWebParameter *txPowerParam = request->getParam("txPower");
|
||||
int txPower = txPowerParam->value().toInt();
|
||||
if (static_cast<int>(wifi_power_t::WIFI_POWER_MINUS_1dBm) <= txPower &&
|
||||
txPower <= static_cast<int>(wifi_power_t::WIFI_POWER_19_5dBm)) {
|
||||
// is valid value
|
||||
String txPowerName = std::to_string(static_cast<std::underlying_type_t<wifi_power_t>>(txPower)).c_str();
|
||||
String txPowerName =
|
||||
std::to_string(
|
||||
static_cast<std::underlying_type_t<wifi_power_t>>(txPower))
|
||||
.c_str();
|
||||
|
||||
Serial.printf("Set WiFi Tx power to: %s\n", txPowerName);
|
||||
|
||||
@ -741,36 +688,30 @@ void onApiSetWifiTxPower(AsyncWebServerRequest *request)
|
||||
return request->send(400);
|
||||
}
|
||||
|
||||
|
||||
void onApiLightsStatus(AsyncWebServerRequest *request)
|
||||
{
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
void onApiLightsStatus(AsyncWebServerRequest *request) {
|
||||
AsyncResponseStream *response =
|
||||
request->beginResponseStream("application/json");
|
||||
|
||||
serializeJson(getLedStatusObject()["data"], *response);
|
||||
|
||||
request->send(response);
|
||||
}
|
||||
|
||||
void onApiLightsOff(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onApiLightsOff(AsyncWebServerRequest *request) {
|
||||
setLights(0, 0, 0);
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onApiLightsSetColor(AsyncWebServerRequest *request)
|
||||
{
|
||||
if (request->hasParam("c"))
|
||||
{
|
||||
AsyncResponseStream *response = request->beginResponseStream("application/json");
|
||||
void onApiLightsSetColor(AsyncWebServerRequest *request) {
|
||||
if (request->hasParam("c")) {
|
||||
AsyncResponseStream *response =
|
||||
request->beginResponseStream("application/json");
|
||||
|
||||
String rgbColor = request->getParam("c")->value();
|
||||
|
||||
if (rgbColor.compareTo("off") == 0)
|
||||
{
|
||||
if (rgbColor.compareTo("off") == 0) {
|
||||
setLights(0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
uint r, g, b;
|
||||
sscanf(rgbColor.c_str(), "%02x%02x%02x", &r, &g, &b);
|
||||
setLights(r, g, b);
|
||||
@ -779,7 +720,6 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
|
||||
StaticJsonDocument<48> doc;
|
||||
doc["result"] = rgbColor;
|
||||
|
||||
|
||||
serializeJson(getLedStatusObject()["data"], *response);
|
||||
|
||||
request->send(response);
|
||||
@ -788,48 +728,39 @@ void onApiLightsSetColor(AsyncWebServerRequest *request)
|
||||
}
|
||||
}
|
||||
|
||||
void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
{
|
||||
void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json) {
|
||||
JsonArray lights = json.as<JsonArray>();
|
||||
|
||||
if (lights.size() != pixels.numPixels())
|
||||
{
|
||||
if (lights.size() != pixels.numPixels()) {
|
||||
Serial.printf("Invalid values for LED set %d\n", lights.size());
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint i = 0; i < pixels.numPixels(); i++)
|
||||
{
|
||||
for (uint i = 0; i < pixels.numPixels(); i++) {
|
||||
unsigned int red, green, blue;
|
||||
|
||||
if (lights[i].containsKey("red") && lights[i].containsKey("green") && lights[i].containsKey("blue"))
|
||||
{
|
||||
if (lights[i].containsKey("red") && lights[i].containsKey("green") &&
|
||||
lights[i].containsKey("blue")) {
|
||||
|
||||
red = lights[i]["red"].as<uint>();
|
||||
green = lights[i]["green"].as<uint>();
|
||||
blue = lights[i]["blue"].as<uint>();
|
||||
}
|
||||
else if (lights[i].containsKey("hex"))
|
||||
{
|
||||
if (!sscanf(lights[i]["hex"].as<String>().c_str(), "#%02X%02X%02X", &red, &green, &blue) == 3)
|
||||
{
|
||||
} else if (lights[i].containsKey("hex")) {
|
||||
if (!sscanf(lights[i]["hex"].as<String>().c_str(), "#%02X%02X%02X", &red,
|
||||
&green, &blue) == 3) {
|
||||
Serial.printf("Invalid hex for LED %d\n", i);
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Serial.printf("No valid color for LED %d\n", i);
|
||||
request->send(400);
|
||||
return;
|
||||
}
|
||||
|
||||
pixels.setPixelColor((pixels.numPixels() - i - 1), pixels.Color(
|
||||
red,
|
||||
green,
|
||||
blue));
|
||||
pixels.setPixelColor((pixels.numPixels() - i - 1),
|
||||
pixels.Color(red, green, blue));
|
||||
}
|
||||
|
||||
pixels.show();
|
||||
@ -838,10 +769,11 @@ void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json)
|
||||
request->send(200);
|
||||
}
|
||||
|
||||
void onIndex(AsyncWebServerRequest *request) { request->send(LittleFS, "/index.html", String(), false); }
|
||||
void onIndex(AsyncWebServerRequest *request) {
|
||||
request->send(LittleFS, "/index.html", String(), false);
|
||||
}
|
||||
|
||||
void onNotFound(AsyncWebServerRequest *request)
|
||||
{
|
||||
void onNotFound(AsyncWebServerRequest *request) {
|
||||
// Serial.printf("NotFound, URL[%s]\n", request->url());
|
||||
|
||||
// Serial.printf("NotFound, METHOD[%s]\n", request->methodToString());
|
||||
@ -851,7 +783,8 @@ void onNotFound(AsyncWebServerRequest *request)
|
||||
// for (i = 0; i < headers; i++)
|
||||
// {
|
||||
// AsyncWebHeader *h = request->getHeader(i);
|
||||
// Serial.printf("NotFound HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
|
||||
// Serial.printf("NotFound HEADER[%s]: %s\n", h->name().c_str(),
|
||||
// h->value().c_str());
|
||||
// }
|
||||
|
||||
// int params = request->params();
|
||||
@ -860,37 +793,36 @@ void onNotFound(AsyncWebServerRequest *request)
|
||||
// AsyncWebParameter *p = request->getParam(i);
|
||||
// if (p->isFile())
|
||||
// { // p->isPost() is also true
|
||||
// Serial.printf("NotFound FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
|
||||
// Serial.printf("NotFound FILE[%s]: %s, size: %u\n",
|
||||
// p->name().c_str(), p->value().c_str(), p->size());
|
||||
// }
|
||||
// else if (p->isPost())
|
||||
// {
|
||||
// Serial.printf("NotFound POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
// Serial.printf("NotFound POST[%s]: %s\n", p->name().c_str(),
|
||||
// p->value().c_str());
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Serial.printf("NotFound GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||
// Serial.printf("NotFound GET[%s]: %s\n", p->name().c_str(),
|
||||
// p->value().c_str());
|
||||
// }
|
||||
// }
|
||||
|
||||
// Access-Control-Request-Method == POST might be better
|
||||
|
||||
if (request->method() == HTTP_OPTIONS || request->hasHeader("Sec-Fetch-Mode"))
|
||||
{
|
||||
if (request->method() == HTTP_OPTIONS ||
|
||||
request->hasHeader("Sec-Fetch-Mode")) {
|
||||
// Serial.printf("NotFound, Return[%d]\n", 200);
|
||||
|
||||
request->send(200);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// Serial.printf("NotFound, Return[%d]\n", 404);
|
||||
request->send(404);
|
||||
}
|
||||
};
|
||||
|
||||
void eventSourceTask(void *pvParameters)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
void eventSourceTask(void *pvParameters) {
|
||||
for (;;) {
|
||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||
eventSourceUpdate();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "WebServer.h"
|
||||
#include "ESPAsyncWebServer.h"
|
||||
#include <ArduinoJson.h>
|
||||
@ -7,10 +8,19 @@
|
||||
#include "AsyncJson.h"
|
||||
#include <iostream>
|
||||
|
||||
|
||||
// #include "AsyncJson.h"
|
||||
// #include "ESPAsyncWebServer.h"
|
||||
// #include "WebServer.h"
|
||||
// #include <ArduinoJson.h>
|
||||
// #include <ESPmDNS.h>
|
||||
// #include <LittleFS.h>
|
||||
// #include <iostream>
|
||||
|
||||
#include "lib/block_notify.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
#include "lib/price_notify.hpp"
|
||||
#include "lib/screen_handler.hpp"
|
||||
#include "lib/led_handler.hpp"
|
||||
|
||||
#include "webserver/OneParamRewrite.hpp"
|
||||
|
||||
@ -40,7 +50,6 @@ void onApiLightsOff(AsyncWebServerRequest *request);
|
||||
void onApiLightsSetColor(AsyncWebServerRequest *request);
|
||||
void onApiLightsSetJson(AsyncWebServerRequest *request, JsonVariant &json);
|
||||
|
||||
|
||||
void onApiRestart(AsyncWebServerRequest *request);
|
||||
|
||||
void onIndex(AsyncWebServerRequest *request);
|
||||
|
@ -1,43 +1,31 @@
|
||||
#include "OneParamRewrite.hpp"
|
||||
|
||||
OneParamRewrite::OneParamRewrite(const char *from, const char *to)
|
||||
: AsyncWebRewrite(from, to)
|
||||
{
|
||||
: AsyncWebRewrite(from, to) {
|
||||
|
||||
_paramIndex = _from.indexOf('{');
|
||||
|
||||
if (_paramIndex >= 0 && _from.endsWith("}"))
|
||||
{
|
||||
if (_paramIndex >= 0 && _from.endsWith("}")) {
|
||||
_urlPrefix = _from.substring(0, _paramIndex);
|
||||
int index = _params.indexOf('{');
|
||||
if (index >= 0)
|
||||
{
|
||||
if (index >= 0) {
|
||||
_params = _params.substring(0, index);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_urlPrefix = _from;
|
||||
}
|
||||
_paramsBackup = _params;
|
||||
}
|
||||
|
||||
bool OneParamRewrite::match(AsyncWebServerRequest *request)
|
||||
{
|
||||
if (request->url().startsWith(_urlPrefix))
|
||||
{
|
||||
if (_paramIndex >= 0)
|
||||
{
|
||||
bool OneParamRewrite::match(AsyncWebServerRequest *request) {
|
||||
if (request->url().startsWith(_urlPrefix)) {
|
||||
if (_paramIndex >= 0) {
|
||||
_params = _paramsBackup + request->url().substring(_paramIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
_params = _paramsBackup;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
@ -2,8 +2,7 @@
|
||||
|
||||
#include "ESPAsyncWebServer.h"
|
||||
|
||||
class OneParamRewrite : public AsyncWebRewrite
|
||||
{
|
||||
class OneParamRewrite : public AsyncWebRewrite {
|
||||
protected:
|
||||
String _urlPrefix;
|
||||
int _paramIndex;
|
||||
|
24
src/main.cpp
24
src/main.cpp
@ -1,23 +1,33 @@
|
||||
/*
|
||||
* Copyright 2023 Djuri Baars
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "Arduino.h"
|
||||
#include <WiFiManager.h>
|
||||
#define WEBSERVER_H
|
||||
#include "ESPAsyncWebServer.h"
|
||||
|
||||
#include "lib/config.hpp"
|
||||
|
||||
//char ptrTaskList[400];
|
||||
|
||||
uint wifiLostConnection;
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
extern "C" void app_main() {
|
||||
initArduino();
|
||||
|
||||
Serial.begin(115200);
|
||||
setup();
|
||||
|
||||
while (true)
|
||||
{
|
||||
while (true) {
|
||||
// vTaskList(ptrTaskList);
|
||||
// Serial.println(F("**********************************"));
|
||||
// Serial.println(F("Task State Prio Stack Num"));
|
||||
|
Loading…
Reference in New Issue
Block a user