From b4461d629b3e6d5fd52fcb82671657fef54fc00e Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Sat, 6 Sep 2025 19:32:46 +0200 Subject: [PATCH 1/5] first draft - use it as a library --- src/webserver.h | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 src/webserver.h diff --git a/src/webserver.h b/src/webserver.h new file mode 100644 index 0000000..a98dbc4 --- /dev/null +++ b/src/webserver.h @@ -0,0 +1,54 @@ +#ifdef ESP32 +#include +#elif defined(ESP8266) +#include +#endif +#include +#include "ha.h" + +AsyncWebServer server(80); + +namespace WebServer { + void notFound(AsyncWebServerRequest *request) { + request->send(404, "text/plain", "Not found"); + } + + void setup() { + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain", "Hello, world"); + }); + + server.on("/switch", HTTP_PUT, [](AsyncWebServerRequest *request) { + if (request->hasParam("id") && request->hasParam("state")) { + AsyncWebParameter* switchId = request->getParam("id"); + AsyncWebParameter* switchState = request->getParam("state"); + auto cmd = Command::mapCommandIds[string(switchId->value().c_str())]; + if (cmd) cmd->onCommand(switchState->value().c_str()); + request->send(200, "text/plain", switchState->value().c_str()); + } else { + request->send(200, "text/plain", "No parameters provided"); + } + }); + + server.on("/switch", HTTP_GET, [](AsyncWebServerRequest *request) { + char switchList[1024] = {}; + for ( auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it ) + snprintf(switchList, sizeof(switchList), "%s ", it->first.c_str()); + request->send(200, "text/plain", switchList); + }); + + server.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request) { + request->send(200, "text/plain"); + ESP.restart(); + }); + + server.onNotFound(notFound); + + server.begin(); + } + + void stop() { + server.end(); + } +} From 234649cdd227460bae794bdb16ad54788b03f1df Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Sat, 6 Sep 2025 21:41:45 +0200 Subject: [PATCH 2/5] implement getting commands and changing the state --- src/webserver.h | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/webserver.h b/src/webserver.h index a98dbc4..07e7904 100644 --- a/src/webserver.h +++ b/src/webserver.h @@ -15,32 +15,27 @@ namespace WebServer { void setup() { - server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain", "Hello, world"); - }); - - server.on("/switch", HTTP_PUT, [](AsyncWebServerRequest *request) { - if (request->hasParam("id") && request->hasParam("state")) { - AsyncWebParameter* switchId = request->getParam("id"); - AsyncWebParameter* switchState = request->getParam("state"); + server.on("/command", HTTP_PUT, [](AsyncWebServerRequest *request) { + if (request->hasParam("id", true) && request->hasParam("state", true)) { + AsyncWebParameter* switchId = request->getParam("id", true); + AsyncWebParameter* switchState = request->getParam("state", true); auto cmd = Command::mapCommandIds[string(switchId->value().c_str())]; - if (cmd) cmd->onCommand(switchState->value().c_str()); - request->send(200, "text/plain", switchState->value().c_str()); + if (cmd) { + cmd->onCommand(switchState->value().c_str()); + request->send(200, "text/plain", switchState->value().c_str()); + } else { + request->send(200, "text/plain", "Command not found"); + } } else { request->send(200, "text/plain", "No parameters provided"); } }); - server.on("/switch", HTTP_GET, [](AsyncWebServerRequest *request) { - char switchList[1024] = {}; - for ( auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it ) - snprintf(switchList, sizeof(switchList), "%s ", it->first.c_str()); - request->send(200, "text/plain", switchList); - }); - - server.on("/restart", HTTP_GET, [](AsyncWebServerRequest *request) { - request->send(200, "text/plain"); - ESP.restart(); + server.on("/command", HTTP_GET, [](AsyncWebServerRequest *request) { + string list; + for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) + list.append(it->first.c_str()).append("\n"); + request->send(200, "text/plain", list.c_str()); }); server.onNotFound(notFound); From 73f72839183854b461b584dfde944f52427d6e13 Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Sun, 7 Sep 2025 10:19:07 +0200 Subject: [PATCH 3/5] use POST for commands, it aligns better with REST specs --- src/webserver.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/webserver.h b/src/webserver.h index 07e7904..4a0338c 100644 --- a/src/webserver.h +++ b/src/webserver.h @@ -15,7 +15,7 @@ namespace WebServer { void setup() { - server.on("/command", HTTP_PUT, [](AsyncWebServerRequest *request) { + server.on("/commands", HTTP_POST, [](AsyncWebServerRequest *request) { if (request->hasParam("id", true) && request->hasParam("state", true)) { AsyncWebParameter* switchId = request->getParam("id", true); AsyncWebParameter* switchState = request->getParam("state", true); @@ -31,7 +31,7 @@ namespace WebServer { } }); - server.on("/command", HTTP_GET, [](AsyncWebServerRequest *request) { + server.on("/commands", HTTP_GET, [](AsyncWebServerRequest *request) { string list; for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) list.append(it->first.c_str()).append("\n"); From 74f1dc1553cd7a59c1774bc8060f133ecc940c3e Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Mon, 8 Sep 2025 12:21:10 +0200 Subject: [PATCH 4/5] return list of commands as JSON array --- src/webserver.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/webserver.h b/src/webserver.h index 4a0338c..ee58f14 100644 --- a/src/webserver.h +++ b/src/webserver.h @@ -32,10 +32,18 @@ namespace WebServer { }); server.on("/commands", HTTP_GET, [](AsyncWebServerRequest *request) { - string list; - for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) - list.append(it->first.c_str()).append("\n"); - request->send(200, "text/plain", list.c_str()); + AsyncResponseStream *response = request->beginResponseStream("application/json"); + + StaticJsonDocument jsonResponse; + JsonArray array = jsonResponse.to(); + for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) { + StaticJsonDocument jsonDoc; + it->second->toJson(jsonDoc); + array.add(jsonDoc); + } + serializeJson(jsonResponse, *response); + + request->send(response); }); server.onNotFound(notFound); From 10afc57b6547411c49c4311bc94fcf39f23c009e Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Mon, 8 Sep 2025 12:21:10 +0200 Subject: [PATCH 5/5] fix crash due to memory issues by using heap - dynamic json --- src/webserver.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/webserver.h b/src/webserver.h index ee58f14..01c3db7 100644 --- a/src/webserver.h +++ b/src/webserver.h @@ -9,9 +9,6 @@ AsyncWebServer server(80); namespace WebServer { - void notFound(AsyncWebServerRequest *request) { - request->send(404, "text/plain", "Not found"); - } void setup() { @@ -34,7 +31,7 @@ namespace WebServer { server.on("/commands", HTTP_GET, [](AsyncWebServerRequest *request) { AsyncResponseStream *response = request->beginResponseStream("application/json"); - StaticJsonDocument jsonResponse; + DynamicJsonDocument jsonResponse(JSON_SIZE*10); JsonArray array = jsonResponse.to(); for (auto it = Command::mapCommandIds.begin(); it != Command::mapCommandIds.end(); ++it) { StaticJsonDocument jsonDoc; @@ -46,7 +43,9 @@ namespace WebServer { request->send(response); }); - server.onNotFound(notFound); + server.onNotFound([](AsyncWebServerRequest *request) { + request->send(404, "text/plain", "Not found"); + }); server.begin(); }