diff --git a/main/webserver.cpp b/main/webserver.cpp index 88e9ba5..391170e 100644 --- a/main/webserver.cpp +++ b/main/webserver.cpp @@ -25,6 +25,7 @@ #endif #include "webserver_settings.h" #include "webserver_stringsettings.h" +#include "webserver_newsettings.h" #ifdef OLD_NVS #include "webserver_dumpnvs.h" #endif @@ -58,7 +59,7 @@ void initWebserver() { httpd_config_t httpConfig HTTPD_DEFAULT_CONFIG(); httpConfig.core_id = 1; - httpConfig.max_uri_handlers = 14; + httpConfig.max_uri_handlers = 16; httpConfig.stack_size = 8192; const auto result = httpd_start(&httpdHandle, &httpConfig); @@ -82,6 +83,8 @@ void initWebserver() httpd_uri_t { .uri = "/saveSettings", .method = HTTP_GET, .handler = webserver_saveSettings_handler, .user_ctx = NULL }, httpd_uri_t { .uri = "/stringSettings", .method = HTTP_GET, .handler = webserver_stringSettings_handler, .user_ctx = NULL }, httpd_uri_t { .uri = "/saveStringSettings", .method = HTTP_GET, .handler = webserver_saveStringSettings_handler, .user_ctx = NULL }, + httpd_uri_t { .uri = "/newSettings", .method = HTTP_GET, .handler = webserver_newSettings_handler, .user_ctx = NULL }, + httpd_uri_t { .uri = "/saveNewSettings", .method = HTTP_GET, .handler = webserver_saveNewSettings_handler, .user_ctx = NULL }, #ifdef OLD_NVS httpd_uri_t { .uri = "/dumpnvs", .method = HTTP_GET, .handler = webserver_dump_nvs_handler, .user_ctx = NULL }, #endif @@ -99,6 +102,7 @@ void handleWebserver() { #ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET webserver_lock->give(); + vTaskDelay(1); webserver_lock->take(portMAX_DELAY); #endif } diff --git a/main/webserver_displaycontrol.cpp b/main/webserver_displaycontrol.cpp index 61ce8bc..cd3efc7 100644 --- a/main/webserver_displaycontrol.cpp +++ b/main/webserver_displaycontrol.cpp @@ -34,7 +34,8 @@ constexpr const char * const TAG = "BOBBYWEB"; esp_err_t webserver_root_handler(httpd_req_t *req) { -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET + ESP_LOGI(TAG, "locking..."); espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -42,6 +43,7 @@ esp_err_t webserver_root_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } + ESP_LOGI(TAG, "succeeded"); #endif std::string body; @@ -184,6 +186,7 @@ esp_err_t webserver_root_handler(httpd_req_t *req) "Settings - " "String Settings - " + "New Settings - " "Dump NVS"; } @@ -245,7 +248,7 @@ esp_err_t webserver_root_handler(httpd_req_t *req) esp_err_t webserver_triggerButton_handler(httpd_req_t *req) { -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -363,8 +366,7 @@ esp_err_t webserver_triggerButton_handler(httpd_req_t *req) esp_err_t webserver_triggerItem_handler(httpd_req_t *req) { - -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -452,8 +454,7 @@ esp_err_t webserver_triggerItem_handler(httpd_req_t *req) esp_err_t webserver_setValue_handler(httpd_req_t *req) { - -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { diff --git a/main/webserver_dumpnvs.cpp b/main/webserver_dumpnvs.cpp index 7094b69..278c8ad 100644 --- a/main/webserver_dumpnvs.cpp +++ b/main/webserver_dumpnvs.cpp @@ -135,8 +135,7 @@ showInputForSetting(std::string_view key, T value, JsonObject &body) esp_err_t webserver_dump_nvs_handler(httpd_req_t *req) { - -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { diff --git a/main/webserver_newsettings.cpp b/main/webserver_newsettings.cpp index e69de29..35cc6e8 100644 --- a/main/webserver_newsettings.cpp +++ b/main/webserver_newsettings.cpp @@ -0,0 +1,367 @@ +#include "webserver_newsettings.h" + +// system includes +#include + +// esp-idf includes +#ifdef FEATURE_WEBSERVER +#include +#endif +#include + +// 3rdparty lib includes +#include +#include +#include +#include +#include +#include +#include + +// local includes +#include "newsettings.h" +#include "webserver_lock.h" + +#ifdef FEATURE_WEBSERVER +using namespace std::chrono_literals; +using esphttpdutils::HtmlTag; + +namespace { +constexpr const char * const TAG = "BOBBYWEB"; + +template +typename std::enable_if< + !std::is_same::value && + !std::is_integral::value && + !std::is_same>::value + , bool>::type +showInputForSetting(std::string_view key, T value, std::string &body) +{ + HtmlTag spanTag{"span", "style=\"color: red;\"", body}; + body += "Unsupported config type"; + return false; +} + +template +typename std::enable_if< + std::is_same::value + , bool>::type +showInputForSetting(std::string_view key, T value, std::string &body) +{ + body += fmt::format("" + "", + esphttpdutils::htmlentities(key), + value ? "checked " : "", + esphttpdutils::htmlentities(key)); + return true; +} + +template +typename std::enable_if< + !std::is_same::value && + std::is_integral::value + , bool>::type +showInputForSetting(std::string_view key, T value, std::string &body) +{ + body += fmt::format("", + esphttpdutils::htmlentities(key), + value, + std::numeric_limits::min(), + std::numeric_limits::max()); + return true; +} + +template +typename std::enable_if< + std::is_same>::value + , bool>::type +showInputForSetting(std::string_view key, T value, std::string &body) +{ + body += fmt::format("", + esphttpdutils::htmlentities(key), + value[0], + value[1], + value[2], + value[3]); + return true; +} +} // namespace + +esp_err_t webserver_newSettings_handler(httpd_req_t *req) +{ +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET + espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; + if (!helper.locked()) + { + constexpr const std::string_view msg = "could not lock webserver_lock"; + ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } +#endif + + std::string body; + + { + HtmlTag htmlTag{"html", body}; + + { + HtmlTag headTag{"head", body}; + + { + HtmlTag titleTag{"title", body}; + body += "Settings"; + } + + body += ""; + + HtmlTag styleTag{"style", "type=\"text/css\"", body}; + body += + ".form-table {" + "display: table;" + "border-collapse: separate;" + "border-spacing: 10px 0;" + "}" + + ".form-table .form-table-row {" + "display: table-row;" + "}" + + ".form-table .form-table-row .form-table-cell {" + "display: table-cell;" + "}"; + } + + { + HtmlTag bodyTag{"body", body}; + + { + HtmlTag h1Tag{"h1", body}; + body += "Settings"; + } + + { + HtmlTag pTag{"p", body}; + body += "Display control - " +#ifdef FEATURE_OTA + "Update - " +#endif + "Settings - " + "String Settings - " + "New Settings - " + "Dump NVS"; + } + + HtmlTag divTag{"div", "class=\"form-table\"", body}; + + ESP_LOGI(TAG, "before the loop"); + for (const ConfigWrapperInterface &config : configs.getAllConfigParams()) + { + if (body.size() > 2048) + { + CALL_AND_EXIT_ON_ERROR(httpd_resp_send_chunk, req, body.data(), body.size()); + body.clear(); + } + + const std::string_view nvsName{config.nvsName()}; + ESP_LOGI(TAG, "in the loop %.*s %zd", nvsName.size(), nvsName.data(), body.size()); + + HtmlTag formTag{"form", "class=\"form-table-row\" action=\"/saveNewSettings\" method=\"GET\"", body}; + + { + HtmlTag divTag{"div", "class=\"form-table\"", body}; + HtmlTag bTag{"b", body}; + body += esphttpdutils::htmlentities(nvsName); + } + + { + HtmlTag divTag{"div", "class=\"form-table-cell\"", body}; + showInputForSetting(nvsName, 1, body); + } + + { + HtmlTag divTag{"div", "class=\"form-table-cell\"", body}; + HtmlTag buttonTag{"button", "type=\"submit\"", body}; + body += "Save"; + } + } + ESP_LOGI(TAG, "after the loop"); + +// settings.executeForEveryCommonSetting([&](std::string_view key, const auto &value){ +// HtmlTag formTag{"form", "class=\"form-table-row\" action=\"/saveNewSettings\" method=\"GET\"", body}; + +// { +// HtmlTag divTag{"div", "class=\"form-table\"", body}; +// HtmlTag bTag{"b", body}; +// body += esphttpdutils::htmlentities(key); +// } + +// { +// HtmlTag divTag{"div", "class=\"form-table-cell\"", body}; +// showInputForSetting(key, value, body); +// } + +// { +// HtmlTag divTag{"div", "class=\"form-table-cell\"", body}; +// HtmlTag buttonTag{"button", "type=\"submit\"", body}; +// body += "Save"; +// } +// }); + } + } + + CALL_AND_EXIT_ON_ERROR(httpd_resp_send_chunk, req, body.data(), body.size()); + body.clear(); + CALL_AND_EXIT(httpd_resp_send_chunk, req, nullptr, 0); + //CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, "text/html", body) +} + +namespace { +template +typename std::enable_if< + !std::is_same::value && + !std::is_integral::value && + !std::is_same>::value + , bool>::type +saveSetting(T &value, std::string_view newValue, std::string &body) +{ + body += "Unsupported config type"; + return false; +} + +template +typename std::enable_if< + std::is_same::value + , bool>::type +saveSetting(T &value, std::string_view newValue, std::string &body) +{ + if (newValue == "true") + { + value = true; + body += "applied"; + return true; + } + else if (newValue == "false") + { + value = false; + body += "applied"; + return true; + } + else + { + body += fmt::format("only true and false allowed, not {}", newValue); + return false; + } +} + +template +typename std::enable_if< + !std::is_same::value && + std::is_integral::value + , bool>::type +saveSetting(T &value, std::string_view newValue, std::string &body) +{ + if (auto parsed = cpputils::fromString(newValue)) + { + value = *parsed; + body += "applied"; + return true; + } + else + { + body += fmt::format("could not parse {}", newValue); + return false; + } +} + +template +typename std::enable_if< + std::is_same>::value + , bool>::type +saveSetting(T &value, std::string_view newValue, std::string &body) +{ + if (std::array parsed; std::sscanf(newValue.data(), "%1hhi%1hhi%1hhi%1hhi", &parsed[0], &parsed[1], &parsed[2], &parsed[3]) == 4) + { + value = parsed; + body += "applied"; + return true; + } + else + { + body += fmt::format("could not parse {}", newValue); + return false; + } +} +} // namespace + +esp_err_t webserver_saveNewSettings_handler(httpd_req_t *req) +{ +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET + espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; + if (!helper.locked()) + { + constexpr const std::string_view msg = "could not lock webserver_lock"; + ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); + } +#endif + + std::string query; + if (auto result = esphttpdutils::webserver_get_query(req)) + query = *result; + else + { + ESP_LOGE(TAG, "%.*s", result.error().size(), result.error().data()); + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", result.error()); + } + + std::string body; + bool success{true}; + +// settings.executeForEveryCommonSetting([&](std::string_view key, auto &value){ +// char valueBufEncoded[256]; +// if (const auto result = httpd_query_key_value(query.data(), key.data(), valueBufEncoded, 256); result != ESP_OK) +// { +// if (result != ESP_ERR_NOT_FOUND) +// { +// const auto msg = fmt::format("{}: httpd_query_key_value() failed with {}", key, esp_err_to_name(result)); +// ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); +// body += msg; +// body += '\n'; +// success = false; +// } +// return; +// } + +// char valueBuf[257]; +// esphttpdutils::urldecode(valueBuf, valueBufEncoded); + +// body += key; +// if (!saveSetting(value, valueBuf, body)) +// success = false; +// body += '\n'; +// }); + + if (body.empty()) + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, "text/plain", "nothing changed?!") + +// if (settingsPersister.save(settings)) +// body += "settings persisted successfully"; +// else +// { +// body += "error while persisting settings"; +// success = false; +// } + + if (success) + { + CALL_AND_EXIT_ON_ERROR(httpd_resp_set_hdr, req, "Location", "/settings") + body += "\nOk, continue at /settings"; + } + + CALL_AND_EXIT(esphttpdutils::webserver_resp_send, + req, + success ? esphttpdutils::ResponseStatus::TemporaryRedirect : esphttpdutils::ResponseStatus::BadRequest, + "text/plain", + body) +} +#endif diff --git a/main/webserver_newsettings.h b/main/webserver_newsettings.h index e69de29..5424186 100644 --- a/main/webserver_newsettings.h +++ b/main/webserver_newsettings.h @@ -0,0 +1,12 @@ +#pragma once + +// esp-idf includes +#ifdef FEATURE_WEBSERVER +#include +#endif +#include + +#ifdef FEATURE_WEBSERVER +esp_err_t webserver_newSettings_handler(httpd_req_t *req); +esp_err_t webserver_saveNewSettings_handler(httpd_req_t *req); +#endif diff --git a/main/webserver_ota.cpp b/main/webserver_ota.cpp index 706758b..e00a282 100644 --- a/main/webserver_ota.cpp +++ b/main/webserver_ota.cpp @@ -33,7 +33,7 @@ constexpr const char * const TAG = "BOBBYWEB"; esp_err_t webserver_ota_percentage_handler(httpd_req_t *req) { -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -92,7 +92,7 @@ esp_err_t webserver_ota_percentage_handler(httpd_req_t *req) esp_err_t webserver_ota_handler(httpd_req_t *req) { -#ifdef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_FUNKTIONIERT +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -209,6 +209,7 @@ esp_err_t webserver_ota_handler(httpd_req_t *req) "Update - " "Settings - " "String Settings - " + "New Settings - " "Dump NVS"; } @@ -360,6 +361,7 @@ esp_err_t webserver_ota_handler(httpd_req_t *req) esp_err_t webserver_trigger_ota_handler(httpd_req_t *req) { +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -367,6 +369,7 @@ esp_err_t webserver_trigger_ota_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } +#endif std::string query; if (auto result = esphttpdutils::webserver_get_query(req)) diff --git a/main/webserver_settings.cpp b/main/webserver_settings.cpp index 9af8304..dd9fee0 100644 --- a/main/webserver_settings.cpp +++ b/main/webserver_settings.cpp @@ -28,7 +28,6 @@ using esphttpdutils::HtmlTag; namespace { constexpr const char * const TAG = "BOBBYWEB"; -} // namespace template typename std::enable_if< @@ -86,9 +85,11 @@ showInputForSetting(std::string_view key, T value, std::string &body) value[3]); return true; } +} // namespace esp_err_t webserver_settings_handler(httpd_req_t *req) { +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -96,6 +97,7 @@ esp_err_t webserver_settings_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } +#endif std::string body; @@ -145,6 +147,7 @@ esp_err_t webserver_settings_handler(httpd_req_t *req) #endif "Settings - " "String Settings - " + "New Settings - " "Dump NVS"; } @@ -175,6 +178,7 @@ esp_err_t webserver_settings_handler(httpd_req_t *req) CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::Ok, "text/html", body) } +namespace { template typename std::enable_if< !std::is_same::value && @@ -250,9 +254,11 @@ saveSetting(T &value, std::string_view newValue, std::string &body) return false; } } +} // namespace esp_err_t webserver_saveSettings_handler(httpd_req_t *req) { +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -260,6 +266,7 @@ esp_err_t webserver_saveSettings_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } +#endif std::string query; if (auto result = esphttpdutils::webserver_get_query(req)) diff --git a/main/webserver_stringsettings.cpp b/main/webserver_stringsettings.cpp index f398d36..92b995e 100644 --- a/main/webserver_stringsettings.cpp +++ b/main/webserver_stringsettings.cpp @@ -27,6 +27,7 @@ constexpr const char * const TAG = "BOBBYWEB"; esp_err_t webserver_stringSettings_handler(httpd_req_t *req) { +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -34,6 +35,7 @@ esp_err_t webserver_stringSettings_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } +#endif std::string body; @@ -83,6 +85,7 @@ esp_err_t webserver_stringSettings_handler(httpd_req_t *req) #endif "Settings - " "String Settings - " + "New Settings - " "Dump NVS"; } @@ -117,6 +120,7 @@ esp_err_t webserver_stringSettings_handler(httpd_req_t *req) esp_err_t webserver_saveStringSettings_handler(httpd_req_t *req) { +#ifndef FEATURE_IS_MIR_EGAL_OB_DER_WEBSERVER_KORREKT_ARBEITET espcpputils::LockHelper helper{webserver_lock->handle, std::chrono::ceil(5s).count()}; if (!helper.locked()) { @@ -124,6 +128,7 @@ esp_err_t webserver_saveStringSettings_handler(httpd_req_t *req) ESP_LOGE(TAG, "%.*s", msg.size(), msg.data()); CALL_AND_EXIT(esphttpdutils::webserver_resp_send, req, esphttpdutils::ResponseStatus::BadRequest, "text/plain", msg); } +#endif std::string query; if (auto result = esphttpdutils::webserver_get_query(req))