From 4efc101e56257aa5afd7ff213fc7f0c48811c5f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patrick=20Ha=C3=9Fel?= Date: Sat, 25 Jan 2025 19:26:21 +0100 Subject: [PATCH] http hooks for targetEpochSeconds, mode_speed, config.write, brightness, player_move, player_fire, display segments font style --- src/Node.h | 173 ++++++++++++++++++++++++++++++++- src/mode.cpp | 12 ++- src/mode.h | 7 ++ src/mode/Border/Border.h | 2 +- src/mode/Clock/Clock.h | 4 +- src/mode/CountDown/CountDown.h | 26 ++--- src/mode/Energy/Energy.h | 12 +-- src/mode/Mode.h | 2 + src/mode/Pong/Pong.h | 12 +-- src/mode/Power/Power.h | 4 +- src/mode/Timer/Timer.h | 53 +++++++--- 11 files changed, 257 insertions(+), 50 deletions(-) diff --git a/src/Node.h b/src/Node.h index d96d365..6c4525b 100644 --- a/src/Node.h +++ b/src/Node.h @@ -37,6 +37,16 @@ function get(path){ r.open("GET", path, true); r.send(); } +function configDate(){ + const year = document.getElementById('year').value; + const month = document.getElementById('month').value - 1; + const day = document.getElementById('day').value; + const hour = document.getElementById('hour').value; + const minute = document.getElementById('minute').value; + const second = document.getElementById('second').value; + const targetEpochSeconds = (new Date(year, month, day, hour, minute, second).getTime() / 1000).toFixed(0); + get('/config/date?targetEpochSeconds=' + targetEpochSeconds); +} )"; @@ -81,14 +91,16 @@ inline void httpIndex(AsyncWebServerRequest *request) { response->print(R"(

)"); response->print(R"(Helligkeit: + / -
)"); response->print(R"(Geschwindigkeit: + / -
)"); - response->print(R"(FPS: EIN / AUS
)"); response->print(R"(

)"); response->print(R"(

)"); - response->print(R"()"); - response->print(R"()"); - response->print(R"()"); - response->print(R"()"); + response->printf(R"()"); + response->printf(R"()"); + response->printf(R"()"); + response->printf(R"()"); + response->printf(R"()"); + response->printf(R"()"); + response->print(R"()"); response->print(R"(

)"); response->print(R"(

)"); @@ -98,6 +110,148 @@ inline void httpIndex(AsyncWebServerRequest *request) { request->send(response); } +inline void web_player(AsyncWebServerRequest *request) { + char buffer[128]; + + if (!request->hasParam("index")) { + request->send(400, "text/plain", "Missing 'index'"); + return; + } + double value = request->getParam("index")->value().toDouble(); + int index = (int) value; + + auto *response = request->beginResponseStream("text/html"); + + response->print(style); + response->print(script); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"()"); + response->print(R"(
)"); + snprintf(buffer, sizeof buffer, R"(
)", index); + response->print(buffer); + response->print(R"(
 
)"); + snprintf(buffer, sizeof buffer, R"(
)", index); + response->print(buffer); + response->print(R"(
)"); + snprintf(buffer, sizeof buffer, R"(
)", index); + response->print(buffer); + response->print(R"(
)"); + snprintf(buffer, sizeof buffer, R"(
)", index); + response->print(buffer); + response->print(R"(
 )"); + snprintf(buffer, sizeof buffer, R"(
)", index); + response->print(buffer); + response->print(R"(
 
)"); + request->send(response); +} + +inline void web_player_move(AsyncWebServerRequest *request) { + double value; + + if (!request->hasParam("index")) { + request->send(400, "text/plain", "Missing 'index'"); + return; + } + value = request->getParam("index")->value().toDouble(); + int index = (int) value; + + if (!request->hasParam("x")) { + request->send(400, "text/plain", "Missing 'x'"); + return; + } + value = request->getParam("x")->value().toDouble(); + int x = (int) value; + + if (!request->hasParam("y")) { + request->send(400, "text/plain", "Missing 'y'"); + return; + } + value = request->getParam("y")->value().toDouble(); + int y = (int) value; + + modeMove(index, x, y); + + request->send(200, "application/json", "true"); +} + +inline void web_player_fire(AsyncWebServerRequest *request) { + double value; + + if (!request->hasParam("index")) { + request->send(400, "text/plain", "Missing 'index'"); + return; + } + value = request->getParam("index")->value().toDouble(); + int index = (int) value; + + modeFire(index); + + request->send(200, "application/json", "true"); +} + +inline void web_setMode(AsyncWebServerRequest *request) { + if (!request->hasParam("mode")) { + request->send(400, "text/plain", "Missing 'mode'"); + return; + } + double value = request->getParam("mode")->value().toDouble(); + if (isnan(value)) { + request->send(400, "text/plain", "'mode' not a number"); + return; + } + setMode((ModeId) value); + request->send(200); +} + +inline void web_brighter(AsyncWebServerRequest *request) { + const auto newBrightness = display.getBrightness() + 10; + display.setBrightness(newBrightness >= 255 ? 255 : newBrightness); + request->send(200); +} + +inline void web_darker(AsyncWebServerRequest *request) { + const auto newBrightness = display.getBrightness() - 10; + display.setBrightness(newBrightness <= 0 ? 0 : newBrightness); + request->send(200); +} + +inline void web_faster(AsyncWebServerRequest *request) { + setSpeed(getSpeed() * 1.1); + request->send(200); +} + +inline void web_slower(AsyncWebServerRequest *request) { + setSpeed(getSpeed() / 1.1); + request->send(200); +} + +inline void web_config_save(AsyncWebServerRequest *request) { + config.write(); + request->send(200); +} + +inline void web_config_date(AsyncWebServerRequest *request) { + const auto targetEpochSeconds = std::stoul(request->getParam("targetEpochSeconds")->value().c_str()); + config.set("targetEpochSeconds", targetEpochSeconds); + modeLoadConfig(); + request->send(200); +} + class Node final : public PatrixNode { public: @@ -110,7 +264,16 @@ public: modeSetup(); server.on("/", httpIndex); + server.on("/player", web_player); + server.on("/player/move", web_player_move); + server.on("/player/fire", web_player_fire); server.on("/mode", httpMode); + server.on("/brighter", web_brighter); + server.on("/darker", web_darker); + server.on("/faster", web_faster); + server.on("/slower", web_slower); + server.on("/config/date", web_config_date); + server.on("/config/save", web_config_save); display.setup(); display.setBrightness(10); diff --git a/src/mode.cpp b/src/mode.cpp index 85651dd..3b646cd 100644 --- a/src/mode.cpp +++ b/src/mode.cpp @@ -12,8 +12,6 @@ #include "mode/Energy/Energy.h" #include "mode/Timer/Timer.h" -#include - Config config("/main.json"); auto current = NONE; @@ -51,11 +49,21 @@ void modeMqttMessage(const char *topic, const char *message) { } } +void modeLoadConfig() { + if (mode != nullptr) { + mode->loadConfig(); + } +} + void setMode(const ModeId newMode) { config.setIfNot("mode", newMode); wanted = newMode; } +double getSpeed() { + return modeSpeed; +} + void setSpeed(const double newSpeed) { modeSpeed = min(max(0.01, newSpeed), 10000.0); config.setIfNot("speed", modeSpeed); diff --git a/src/mode.h b/src/mode.h index 5f9292b..8020efb 100644 --- a/src/mode.h +++ b/src/mode.h @@ -1,14 +1,19 @@ #ifndef RGB_MATRIX_DISPLAY_MODE_H #define RGB_MATRIX_DISPLAY_MODE_H +#include #include "mode/Mode.h" +extern Config config; + void modeSetup(); void modeLoop(Display& display); void setMode(ModeId newMode); +double getSpeed(); + void setSpeed(double newSpeed); void modeMove(int index, int x, int y); @@ -17,4 +22,6 @@ void modeFire(int index); void modeMqttMessage(const char *topic, const char *message); +void modeLoadConfig(); + #endif diff --git a/src/mode/Border/Border.h b/src/mode/Border/Border.h index 8b32929..bd48687 100644 --- a/src/mode/Border/Border.h +++ b/src/mode/Border/Border.h @@ -18,7 +18,7 @@ public: protected: void draw(Display& display) override { - display.foreground = White; + display.clear(); display.drawLineWH(0, 0, display.width, 0, 1); display.drawLineWH(0, 0, 0, display.height, 1); display.drawLineWH(display.width - 1, display.height - 1, -display.width, 0, 1); diff --git a/src/mode/Clock/Clock.h b/src/mode/Clock/Clock.h index 6738587..6039d82 100644 --- a/src/mode/Clock/Clock.h +++ b/src/mode/Clock/Clock.h @@ -27,11 +27,9 @@ protected: void draw(Display& display) override { display.clear(); - display.foreground = White; - display.background = Transparent; display.cursorX = 2; display.cursorY = 1; - display.printf("%2d:%02d:%02d", now.tm_hour, now.tm_min, now.tm_sec); + display.printf(true, "%2d:%02d:%02d", now.tm_hour, now.tm_min, now.tm_sec); } }; diff --git a/src/mode/CountDown/CountDown.h b/src/mode/CountDown/CountDown.h index 41d80f3..726f8b7 100644 --- a/src/mode/CountDown/CountDown.h +++ b/src/mode/CountDown/CountDown.h @@ -12,6 +12,8 @@ class CountDown : public Mode { Firework fireworks[MAX_FIREWORKS]; + time_t targetEpochSeconds = 0; + tm target{}; uint16_t days = 0; @@ -43,6 +45,10 @@ public: return "CountDown (Numbers)"; } + void start() override { + targetEpochSeconds = config.get("targetEpochSeconds", 1767222000); + } + protected: void step(const microseconds_t microseconds) override { @@ -59,22 +65,18 @@ protected: return; } - // GRRRRRRR... - target.tm_year -= 1900; - target.tm_mon -= 1; - const auto dateEpochSeconds = mktime(&target); + localtime_r(&targetEpochSeconds, &target); target.tm_year += 1900; target.tm_mon += 1; - // --- - const auto diffSeconds = difftime(dateEpochSeconds, nowEpochSeconds); + const auto diffSeconds = difftime(targetEpochSeconds, nowEpochSeconds); days = static_cast(floor(diffSeconds / (24 * 60 * 60))); hours = static_cast(floor(diffSeconds / (60 * 60))) % 24; minutes = static_cast(floor(diffSeconds / 60)) % 60; seconds = static_cast(diffSeconds) % 60; // Serial.printf("now=%4d.%02d.%02d (%ld), conf=%4d.%02d.%02d (%ld), diff=%f, %dd %2d:%02d:%02d\n", // now.tm_year, now.tm_mon, now.tm_mday, nowEpochSeconds, - // target.tm_year, target.tm_mon, target.tm_mday, dateEpochSeconds, + // target.tm_year, target.tm_mon, target.tm_mday, targetEpochSeconds, // diffSeconds, // days, hours, minutes, seconds); setMode(COUNTDOWN); @@ -146,7 +148,7 @@ private: void drawSleepingCount(Display& display) const { const auto sleepCount = days + 1; - display.printf("%02d Tag%s", sleepCount, sleepCount == 1 ? "" : "e"); + display.printf(true, "%3d TAG%s", sleepCount, sleepCount == 1 ? "" : "E"); } void drawCountdownBars(Display& display) const { @@ -177,10 +179,10 @@ private: void drawCountdownNumbers(Display& display) const { if (days > 0) { - display.printf("%02d. %2d:%02d", days, hours, minutes); + display.printf(true, "%02d. %2d:%02d", days, hours, minutes); drawSecondsBar(display, seconds); } else { - display.printf("%2d:%02d:%02d", hours, minutes, seconds); + display.printf(true, "%2d:%02d:%02d", hours, minutes, seconds); drawSubSecondsBar(display); } } @@ -209,11 +211,11 @@ private: void drawYear(Display& display, const int year) const { if (plus1DayForSleepingCount) { - display.printf("Emil 5"); + display.printf(true, "Emil 5"); display.cursorX = 32 - 8; display.cursorY = 0; } else { - display.printf("%5d", year); + display.printf(true, "%5d", year); } } diff --git a/src/mode/Energy/Energy.h b/src/mode/Energy/Energy.h index 70c2e0f..a3f8ec4 100644 --- a/src/mode/Energy/Energy.h +++ b/src/mode/Energy/Energy.h @@ -76,19 +76,19 @@ protected: display.cursorY = 1; if (page == 0) { display.foreground = Green; - display.printf("%3.0f€", costSaved); + display.printf(true, "%3.0f€", costSaved); display.foreground = White; - display.printf(" %3.0f%%", amortisationPercent); + display.printf(true, " %3.0f%%", amortisationPercent); } else if (page == 1) { display.foreground = Blue; - display.printf("%3.0f", photovoltaicEnergyKWh); + display.printf(true, "%3.0f", photovoltaicEnergyKWh); display.foreground = Green; - display.printf(" %3.0f", selfConsumedKWh); + display.printf(true, " %3.0f", selfConsumedKWh); } else { display.foreground = Yellow; - display.printf("%4.0f", gridImportKWh); + display.printf(true, "%4.0f", gridImportKWh); display.foreground = Magenta; - display.printf(" %3.0f", gridExportKWh); + display.printf(true, " %3.0f", gridExportKWh); } } diff --git a/src/mode/Mode.h b/src/mode/Mode.h index 31b16d4..2148973 100644 --- a/src/mode/Mode.h +++ b/src/mode/Mode.h @@ -105,6 +105,8 @@ public: virtual void mqttMessage(const String& topic, const String& message) {} + virtual void loadConfig() {} + void loop(const microseconds_t microseconds) { handleRealtime(); handleTimers(microseconds); diff --git a/src/mode/Pong/Pong.h b/src/mode/Pong/Pong.h index 523a9ca..d702961 100644 --- a/src/mode/Pong/Pong.h +++ b/src/mode/Pong/Pong.h @@ -95,10 +95,10 @@ protected: switch (status) { case SCORE: display.foreground = Green; - display.printf("%d", player0.score); + display.printf(true, "%d", player0.score); display.foreground = Red; - display.printf("%5d", player1.score); + display.printf(true, "%5d", player1.score); break; case PLAY: for (auto i = 0; i < player0.size; ++i) { @@ -112,16 +112,16 @@ protected: case OVER: if (player0.score > player1.score) { display.foreground = Green; - display.printf("W", player0.score); + display.printf(true, "W", player0.score); display.foreground = Red; - display.printf(" L", player1.score); + display.printf(true, " L", player1.score); } else if (player0.score < player1.score) { display.foreground = Red; - display.printf("L", player0.score); + display.printf(true, "L", player0.score); display.foreground = Green; - display.printf(" W", player1.score); + display.printf(true, " W", player1.score); } break; } diff --git a/src/mode/Power/Power.h b/src/mode/Power/Power.h index 368a3a1..1425c77 100644 --- a/src/mode/Power/Power.h +++ b/src/mode/Power/Power.h @@ -59,10 +59,10 @@ protected: display.clear(); display.foreground = photovoltaicPowerW >= 100 ? Green : photovoltaicPowerW >= 20 ? Yellow : Red; - display.printf("%3.0f", photovoltaicPowerW); + display.printf(true, "%3.0f", photovoltaicPowerW); display.foreground = gridPowerW >= 20 ? Yellow : gridPowerW >= -20 ? Green : Magenta; - display.printf(" %4.0f", gridPowerW); + display.printf(true, " %4.0f", gridPowerW); } }; diff --git a/src/mode/Timer/Timer.h b/src/mode/Timer/Timer.h index 60dbb3d..3d986c1 100644 --- a/src/mode/Timer/Timer.h +++ b/src/mode/Timer/Timer.h @@ -3,9 +3,15 @@ #include "mode/Mode.h" +#define DEFAULT_DURATION_MILLIS (6 * 60 * 1000L) + class Timer2 final : public Mode { - const unsigned long targetMillis = millis() + 6 * 60 * 1000; + long durationMillis = DEFAULT_DURATION_MILLIS; + + long restMillis = durationMillis; + + unsigned long lastMillis = 0; uint16_t days = 0; @@ -15,8 +21,6 @@ class Timer2 final : public Mode { uint16_t seconds = 0; - unsigned long diffSeconds = 0; - public: explicit Timer2(Display& display) : Mode(display) { @@ -27,30 +31,53 @@ public: return "Timer"; } + void loadConfig() override { + const auto newDurationMillis = config.get("durationMillis", DEFAULT_DURATION_MILLIS); + if (restMillis > 0) { + restMillis += newDurationMillis - durationMillis; + } + durationMillis = newDurationMillis; + } + + void start() override { + restMillis = durationMillis; + lastMillis = millis(); + } + protected: void step(microseconds_t microseconds) override { const auto now = millis(); - diffSeconds = now >= targetMillis ? 0 : (targetMillis - now) / 1000; - days = diffSeconds / (24 * 60 * 60); - hours = diffSeconds / (60 * 60) % 24; - minutes = diffSeconds / 60 % 60; - seconds = diffSeconds % 60; + const auto deltaMillis = now - lastMillis; + lastMillis = now; + + restMillis -= static_cast(deltaMillis); + if (restMillis < 0) { + restMillis = 0; + } + + const auto restSeconds = restMillis / 1000; + days = restSeconds / (24 * 60 * 60); + hours = restSeconds / (60 * 60) % 24; + minutes = restSeconds / 60 % 60; + seconds = restSeconds % 60; markDirty(); } void draw(Display& display) override { display.clear(); + display.cursorX = 1; + display.cursorY = 1; if (days > 1) { - display.printf("%4d Tage", days); + display.printf(true, "%4d TAGE", days); } else if (days > 0) { - display.printf("%2d. %02d:%02d", days, hours, minutes); + display.printf(true, "%2d. %02d:%02d", days, hours, minutes); } else if (hours > 0) { - display.printf("%2d:%02d:%02d", hours, minutes, seconds); + display.printf(true, "%2d:%02d:%02d", hours, minutes, seconds); } else if (minutes > 0) { - display.printf("%2d:%02d", minutes, seconds); + display.printf(true, "%2d:%02d", minutes, seconds); } else { - display.printf("%2d", seconds); + display.printf(true, "%2d", seconds); } }