http hooks for targetEpochSeconds, mode_speed, config.write, brightness, player_move, player_fire, display segments font style
This commit is contained in:
parent
0b891d9604
commit
4efc101e56
173
src/Node.h
173
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);
|
||||
}
|
||||
</script>
|
||||
)";
|
||||
|
||||
@ -81,14 +91,16 @@ inline void httpIndex(AsyncWebServerRequest *request) {
|
||||
response->print(R"(<p>)");
|
||||
response->print(R"(Helligkeit: <a onclick="get('/brighter');">+</a> / <a onclick="get('/darker');">-</a><br>)");
|
||||
response->print(R"(Geschwindigkeit: <a onclick="get('/faster');">+</a> / <a onclick="get('/slower');">-</a><br>)");
|
||||
response->print(R"(FPS: <a onclick="get('/fps/on');">EIN</a> / <a onclick="get('/fps/off');">AUS</a><br>)");
|
||||
response->print(R"(</p>)");
|
||||
|
||||
response->print(R"(<p>)");
|
||||
response->print(R"(<input type="number" min="1900" max="3000" step="1" name="year" id="year">)");
|
||||
response->print(R"(<input type="number" min="1" max="12" step="1" name="month" id="month">)");
|
||||
response->print(R"(<input type="number" min="1" max="31" step="1" name="day" id="day">)");
|
||||
response->print(R"(<button onclick="get('/config/date?year=' + document.getElementById('year').value + '&month=' + document.getElementById('month').value + '&day=' + document.getElementById('day').value);">Datum setzen</button>)");
|
||||
response->printf(R"(<input type="number" min="2025" max="3000" step="1" id="year">)");
|
||||
response->printf(R"(<input type="number" min="1" max="12" step="1" id="month">)");
|
||||
response->printf(R"(<input type="number" min="1" max="31" step="1" id="day">)");
|
||||
response->printf(R"(<input type="number" min="0" max="23" step="1" id="hour">)");
|
||||
response->printf(R"(<input type="number" min="0" max="59" step="1" id="minute">)");
|
||||
response->printf(R"(<input type="number" min="0" max="59" step="1" id="second">)");
|
||||
response->print(R"(<button onclick="configDate();">Datum setzen</button>)");
|
||||
response->print(R"(</p>)");
|
||||
|
||||
response->print(R"(<p>)");
|
||||
@ -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"(<meta name="viewport" content= "width=device-width, user-scalable=no">)");
|
||||
response->print(R"(<table>)");
|
||||
response->print(R"(<tr>)");
|
||||
response->print(R"(<td><a href='/'>←</td>)");
|
||||
response->print(R"(<td>)");
|
||||
snprintf(buffer, sizeof buffer, R"(<button class="player" onclick="get('/player/move?index=%d&x=0&y=-1');">↑</button><br>)", index);
|
||||
response->print(buffer);
|
||||
response->print(R"(</td>)");
|
||||
response->print(R"(<td> </td>)");
|
||||
response->print(R"(</tr>)");
|
||||
response->print(R"(<tr>)");
|
||||
response->print(R"(<td>)");
|
||||
snprintf(buffer, sizeof buffer, R"(<button class="player" onclick="get('/player/move?index=%d&x=-1&y=0');">←</button><br>)", index);
|
||||
response->print(buffer);
|
||||
response->print(R"(</td>)");
|
||||
response->print(R"(<td>)");
|
||||
snprintf(buffer, sizeof buffer, R"(<button class="player" onclick="get('/player/fire?index=%d');">X</button><br>)", index);
|
||||
response->print(buffer);
|
||||
response->print(R"(</td>)");
|
||||
response->print(R"(<td>)");
|
||||
snprintf(buffer, sizeof buffer, R"(<button class="player" onclick="get('/player/move?index=%d&x=+1&y=0');">→</button><br>)", index);
|
||||
response->print(buffer);
|
||||
response->print(R"(</td>)");
|
||||
response->print(R"(</tr>)");
|
||||
response->print(R"(<tr>)");
|
||||
response->print(R"(<td> </td>)");
|
||||
response->print(R"(<td>)");
|
||||
snprintf(buffer, sizeof buffer, R"(<button class="player" onclick="get('/player/move?index=%d&x=0&y=+1');">↓</button><br>)", index);
|
||||
response->print(buffer);
|
||||
response->print(R"(</td>)");
|
||||
response->print(R"(<td> </td>)");
|
||||
response->print(R"(</tr>)");
|
||||
response->print(R"(</table>)");
|
||||
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);
|
||||
|
||||
12
src/mode.cpp
12
src/mode.cpp
@ -12,8 +12,6 @@
|
||||
#include "mode/Energy/Energy.h"
|
||||
#include "mode/Timer/Timer.h"
|
||||
|
||||
#include <patrix/core/Config.h>
|
||||
|
||||
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);
|
||||
|
||||
@ -1,14 +1,19 @@
|
||||
#ifndef RGB_MATRIX_DISPLAY_MODE_H
|
||||
#define RGB_MATRIX_DISPLAY_MODE_H
|
||||
|
||||
#include <patrix/core/Config.h>
|
||||
#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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -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<int>(floor(diffSeconds / (24 * 60 * 60)));
|
||||
hours = static_cast<int>(floor(diffSeconds / (60 * 60))) % 24;
|
||||
minutes = static_cast<int>(floor(diffSeconds / 60)) % 60;
|
||||
seconds = static_cast<int>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -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<long>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user