From b4461d629b3e6d5fd52fcb82671657fef54fc00e Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Sat, 6 Sep 2025 19:32:46 +0200 Subject: [PATCH 1/6] 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/6] 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/6] 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/6] 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/6] 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(); } From 9f13a6db8758bc9c93f0dde86751dedd485e0155 Mon Sep 17 00:00:00 2001 From: Nicu Hodos Date: Mon, 8 Sep 2025 17:22:35 +0200 Subject: [PATCH 6/6] move web server here - it simplifies the dependency management --- library.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/library.json b/library.json index e32a3aa..932f164 100644 --- a/library.json +++ b/library.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/platformio/platformio-core/develop/platformio/assets/schema/library.json", "name": "ha-mqtt", - "version": "1.9.0", + "version": "1.10.0", "description": "Home Assistant classes for integration with MQTT auto discovery", "repository": { "type": "git", @@ -16,7 +16,8 @@ ], "dependencies": { "bblanchon/ArduinoJson": "6.21.5", - "marvinroger/AsyncMqttClient": "^0.9.0" + "marvinroger/AsyncMqttClient": "^0.9.0", + "esphome/ESPAsyncWebServer-esphome": "^3.4.0" }, "license": "MIT", "frameworks": "arduino",