297 lines
9.7 KiB
C++
297 lines
9.7 KiB
C++
#ifndef NODE_H
|
|
#define NODE_H
|
|
|
|
#include <patrix/display/DisplayMatrix.h>
|
|
#include <patrix/node/PatrixNode.h>
|
|
|
|
#include <mode.h>
|
|
#include <patrix/core/http.h>
|
|
|
|
DisplayMatrix<32, 8> display(13);
|
|
|
|
static const auto style = R"(
|
|
<style>
|
|
body {
|
|
font-family: sans-serif;
|
|
font-size: 8vw;
|
|
margin: 0;
|
|
}
|
|
button.player{
|
|
width: 33vmin;
|
|
height: 33vmin;
|
|
font-size: 9vw;
|
|
}
|
|
table{
|
|
border-collapse: collapse;
|
|
}
|
|
td{
|
|
text-align: center;
|
|
}
|
|
</style>
|
|
)";
|
|
|
|
static const auto script = R"(
|
|
<script>
|
|
function get(path){
|
|
var r = new XMLHttpRequest();
|
|
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>
|
|
)";
|
|
|
|
inline void httpMode(AsyncWebServerRequest *request) {
|
|
if (!request->hasParam("mode")) {
|
|
request->send(400);
|
|
}
|
|
setMode(static_cast<ModeId>(request->getParam("mode")->value().toInt()));
|
|
request->send(200);
|
|
}
|
|
|
|
inline void httpIndex(AsyncWebServerRequest *request) {
|
|
auto *response = request->beginResponseStream("text/html");
|
|
response->print(style);
|
|
response->print(script);
|
|
|
|
response->print(R"(<p>)");
|
|
response->print(R"(<a href="/player?index=0">Player 0</a><br>)");
|
|
response->print(R"(<a href="/player?index=1">Player 1</a><br>)");
|
|
response->print(R"(</p>)");
|
|
|
|
response->print(R"(<p>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=0');">NONE</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=1');">BORDER</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=2');">CLOCK</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=3');">GAME_OF_LIFE_BLACK_WHITE</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=4');">GAME_OF_LIFE_GRAYSCALE</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=5');">GAME_OF_LIFE_COLOR_FADE</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=6');">GAME_OF_LIFE_RANDOM_COLOR</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=7');">PONG</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=8');">SPACE_INVADERS</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=9');">COUNT_DOWN</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=10');">COUNT_DOWN_BARS</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=11');">COUNT_DOWN_SLEEP</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=12');">STARFIELD</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=13');">MATRIX</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=14');">POWER</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=15');">ENERGY</a><br>)");
|
|
response->print(R"(<a onclick="get('/mode?mode=16');">TIMER</a><br>)");
|
|
response->print(R"(</p>)");
|
|
|
|
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"(</p>)");
|
|
|
|
response->print(R"(<p>)");
|
|
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>)");
|
|
response->print(R"(<button onclick="get('/config/save');">Speichern erzwingen</button>)");
|
|
response->print(R"(</p>)");
|
|
|
|
request->send(response);
|
|
}
|
|
|
|
inline void web_player(AsyncWebServerRequest *request) {
|
|
char buffer[128];
|
|
|
|
if (!request->hasParam("index")) {
|
|
request->send(400, "text/plain", "Missing 'index'");
|
|
return;
|
|
}
|
|
const auto value = request->getParam("index")->value().toDouble();
|
|
const auto index = static_cast<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) {
|
|
// ReSharper disable once CppJoinDeclarationAndAssignment
|
|
double value;
|
|
|
|
if (!request->hasParam("index")) {
|
|
request->send(400, "text/plain", "Missing 'index'");
|
|
return;
|
|
}
|
|
value = request->getParam("index")->value().toDouble();
|
|
const auto index = static_cast<int>(value);
|
|
|
|
if (!request->hasParam("x")) {
|
|
request->send(400, "text/plain", "Missing 'x'");
|
|
return;
|
|
}
|
|
value = request->getParam("x")->value().toDouble();
|
|
const auto x = static_cast<int>(value);
|
|
|
|
if (!request->hasParam("y")) {
|
|
request->send(400, "text/plain", "Missing 'y'");
|
|
return;
|
|
}
|
|
value = request->getParam("y")->value().toDouble();
|
|
const auto y = static_cast<int>(value);
|
|
|
|
modeMove(index, x, y);
|
|
|
|
request->send(200, "application/json", "true");
|
|
}
|
|
|
|
inline void web_player_fire(AsyncWebServerRequest *request) {
|
|
// ReSharper disable once CppJoinDeclarationAndAssignment
|
|
double value;
|
|
|
|
if (!request->hasParam("index")) {
|
|
request->send(400, "text/plain", "Missing 'index'");
|
|
return;
|
|
}
|
|
value = request->getParam("index")->value().toDouble();
|
|
const auto index = static_cast<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;
|
|
}
|
|
auto value = request->getParam("mode")->value().toDouble();
|
|
if (isnan(value)) {
|
|
request->send(400, "text/plain", "'mode' not a number");
|
|
return;
|
|
}
|
|
setMode(static_cast<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:
|
|
|
|
explicit Node() : PatrixNode(true, true, true) {
|
|
//
|
|
}
|
|
|
|
void setup() override {
|
|
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);
|
|
display.clear();
|
|
}
|
|
|
|
void loop() override {
|
|
modeLoop(display);
|
|
display.loop();
|
|
}
|
|
|
|
void mqttMessage(char *topic, char *message) override {
|
|
modeMqttMessage(topic, message);
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|