mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[water_heater] (3/4) Implement web_server for new water_heater component (#12511)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
@@ -136,7 +136,7 @@ bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmCont
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
bool ListEntitiesIterator::on_water_heater(water_heater::WaterHeater *obj) {
|
||||
// Water heater web_server support not yet implemented - this stub acknowledges the entity
|
||||
this->events_->deferrable_send_state(obj, "state_detail_all", WebServer::water_heater_all_json_generator);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -28,6 +28,10 @@
|
||||
#include "esphome/components/climate/climate.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
#include "esphome/components/water_heater/water_heater.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_WEBSERVER_LOCAL
|
||||
#if USE_WEBSERVER_VERSION == 2
|
||||
#include "server_index_v2.h"
|
||||
@@ -558,7 +562,7 @@ static void set_json_icon_state_value(JsonObject &root, EntityBase *obj, const c
|
||||
|
||||
// Helper to get request detail parameter
|
||||
static JsonDetail get_request_detail(AsyncWebServerRequest *request) {
|
||||
auto *param = request->getParam("detail");
|
||||
auto *param = request->getParam(ESPHOME_F("detail"));
|
||||
return (param && param->value() == "all") ? DETAIL_ALL : DETAIL_STATE;
|
||||
}
|
||||
|
||||
@@ -837,10 +841,10 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
|
||||
}
|
||||
auto call = is_on ? obj->turn_on() : obj->turn_off();
|
||||
|
||||
parse_int_param_(request, "speed_level", call, &decltype(call)::set_speed);
|
||||
parse_int_param_(request, ESPHOME_F("speed_level"), call, &decltype(call)::set_speed);
|
||||
|
||||
if (request->hasParam("oscillation")) {
|
||||
auto speed = request->getParam("oscillation")->value();
|
||||
if (request->hasParam(ESPHOME_F("oscillation"))) {
|
||||
auto speed = request->getParam(ESPHOME_F("oscillation"))->value();
|
||||
auto val = parse_on_off(speed.c_str());
|
||||
switch (val) {
|
||||
case PARSE_ON:
|
||||
@@ -920,20 +924,20 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
|
||||
|
||||
if (is_on) {
|
||||
// Parse color parameters
|
||||
parse_light_param_(request, "brightness", call, &decltype(call)::set_brightness, 255.0f);
|
||||
parse_light_param_(request, "r", call, &decltype(call)::set_red, 255.0f);
|
||||
parse_light_param_(request, "g", call, &decltype(call)::set_green, 255.0f);
|
||||
parse_light_param_(request, "b", call, &decltype(call)::set_blue, 255.0f);
|
||||
parse_light_param_(request, "white_value", call, &decltype(call)::set_white, 255.0f);
|
||||
parse_light_param_(request, "color_temp", call, &decltype(call)::set_color_temperature);
|
||||
parse_light_param_(request, ESPHOME_F("brightness"), call, &decltype(call)::set_brightness, 255.0f);
|
||||
parse_light_param_(request, ESPHOME_F("r"), call, &decltype(call)::set_red, 255.0f);
|
||||
parse_light_param_(request, ESPHOME_F("g"), call, &decltype(call)::set_green, 255.0f);
|
||||
parse_light_param_(request, ESPHOME_F("b"), call, &decltype(call)::set_blue, 255.0f);
|
||||
parse_light_param_(request, ESPHOME_F("white_value"), call, &decltype(call)::set_white, 255.0f);
|
||||
parse_light_param_(request, ESPHOME_F("color_temp"), call, &decltype(call)::set_color_temperature);
|
||||
|
||||
// Parse timing parameters
|
||||
parse_light_param_uint_(request, "flash", call, &decltype(call)::set_flash_length, 1000);
|
||||
parse_light_param_uint_(request, ESPHOME_F("flash"), call, &decltype(call)::set_flash_length, 1000);
|
||||
}
|
||||
parse_light_param_uint_(request, "transition", call, &decltype(call)::set_transition_length, 1000);
|
||||
parse_light_param_uint_(request, ESPHOME_F("transition"), call, &decltype(call)::set_transition_length, 1000);
|
||||
|
||||
if (is_on) {
|
||||
parse_string_param_(request, "effect", call, &decltype(call)::set_effect);
|
||||
parse_string_param_(request, ESPHOME_F("effect"), call, &decltype(call)::set_effect);
|
||||
}
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
@@ -1016,14 +1020,14 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
|
||||
auto traits = obj->get_traits();
|
||||
if ((request->hasParam("position") && !traits.get_supports_position()) ||
|
||||
(request->hasParam("tilt") && !traits.get_supports_tilt())) {
|
||||
if ((request->hasParam(ESPHOME_F("position")) && !traits.get_supports_position()) ||
|
||||
(request->hasParam(ESPHOME_F("tilt")) && !traits.get_supports_tilt())) {
|
||||
request->send(409);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_float_param_(request, "position", call, &decltype(call)::set_position);
|
||||
parse_float_param_(request, "tilt", call, &decltype(call)::set_tilt);
|
||||
parse_float_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
|
||||
parse_float_param_(request, ESPHOME_F("tilt"), call, &decltype(call)::set_tilt);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1082,7 +1086,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
parse_float_param_(request, "value", call, &decltype(call)::set_value);
|
||||
parse_float_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_value);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1150,12 +1154,12 @@ void WebServer::handle_date_request(AsyncWebServerRequest *request, const UrlMat
|
||||
|
||||
auto call = obj->make_call();
|
||||
|
||||
if (!request->hasParam("value")) {
|
||||
if (!request->hasParam(ESPHOME_F("value"))) {
|
||||
request->send(409);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_string_param_(request, "value", call, &decltype(call)::set_date);
|
||||
parse_string_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_date);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1214,12 +1218,12 @@ void WebServer::handle_time_request(AsyncWebServerRequest *request, const UrlMat
|
||||
|
||||
auto call = obj->make_call();
|
||||
|
||||
if (!request->hasParam("value")) {
|
||||
if (!request->hasParam(ESPHOME_F("value"))) {
|
||||
request->send(409);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_string_param_(request, "value", call, &decltype(call)::set_time);
|
||||
parse_string_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_time);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1277,12 +1281,12 @@ void WebServer::handle_datetime_request(AsyncWebServerRequest *request, const Ur
|
||||
|
||||
auto call = obj->make_call();
|
||||
|
||||
if (!request->hasParam("value")) {
|
||||
if (!request->hasParam(ESPHOME_F("value"))) {
|
||||
request->send(409);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_string_param_(request, "value", call, &decltype(call)::set_datetime);
|
||||
parse_string_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_datetime);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1342,7 +1346,7 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
parse_string_param_(request, "value", call, &decltype(call)::set_value);
|
||||
parse_string_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_value);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1400,7 +1404,7 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
parse_string_param_(request, "option", call, &decltype(call)::set_option);
|
||||
parse_string_param_(request, ESPHOME_F("option"), call, &decltype(call)::set_option);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1460,14 +1464,15 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
|
||||
auto call = obj->make_call();
|
||||
|
||||
// Parse string mode parameters
|
||||
parse_string_param_(request, "mode", call, &decltype(call)::set_mode);
|
||||
parse_string_param_(request, "fan_mode", call, &decltype(call)::set_fan_mode);
|
||||
parse_string_param_(request, "swing_mode", call, &decltype(call)::set_swing_mode);
|
||||
parse_string_param_(request, ESPHOME_F("mode"), call, &decltype(call)::set_mode);
|
||||
parse_string_param_(request, ESPHOME_F("fan_mode"), call, &decltype(call)::set_fan_mode);
|
||||
parse_string_param_(request, ESPHOME_F("swing_mode"), call, &decltype(call)::set_swing_mode);
|
||||
|
||||
// Parse temperature parameters
|
||||
parse_float_param_(request, "target_temperature_high", call, &decltype(call)::set_target_temperature_high);
|
||||
parse_float_param_(request, "target_temperature_low", call, &decltype(call)::set_target_temperature_low);
|
||||
parse_float_param_(request, "target_temperature", call, &decltype(call)::set_target_temperature);
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature_high"), call,
|
||||
&decltype(call)::set_target_temperature_high);
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature_low"), call, &decltype(call)::set_target_temperature_low);
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature"), call, &decltype(call)::set_target_temperature);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1706,12 +1711,12 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
|
||||
}
|
||||
|
||||
auto traits = obj->get_traits();
|
||||
if (request->hasParam("position") && !traits.get_supports_position()) {
|
||||
if (request->hasParam(ESPHOME_F("position")) && !traits.get_supports_position()) {
|
||||
request->send(409);
|
||||
return;
|
||||
}
|
||||
|
||||
parse_float_param_(request, "position", call, &decltype(call)::set_position);
|
||||
parse_float_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
@@ -1764,7 +1769,7 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
|
||||
}
|
||||
|
||||
auto call = obj->make_call();
|
||||
parse_string_param_(request, "code", call, &decltype(call)::set_code);
|
||||
parse_string_param_(request, ESPHOME_F("code"), call, &decltype(call)::set_code);
|
||||
|
||||
// Lookup table for alarm control panel methods
|
||||
static const struct {
|
||||
@@ -1825,6 +1830,117 @@ std::string WebServer::alarm_control_panel_json_(alarm_control_panel::AlarmContr
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
void WebServer::on_water_heater_update(water_heater::WaterHeater *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
return;
|
||||
this->events_.deferrable_send_state(obj, "state", water_heater_state_json_generator);
|
||||
}
|
||||
void WebServer::handle_water_heater_request(AsyncWebServerRequest *request, const UrlMatch &match) {
|
||||
for (water_heater::WaterHeater *obj : App.get_water_heaters()) {
|
||||
auto entity_match = match.match_entity(obj);
|
||||
if (!entity_match.matched)
|
||||
continue;
|
||||
|
||||
if (request->method() == HTTP_GET && entity_match.action_is_empty) {
|
||||
auto detail = get_request_detail(request);
|
||||
std::string data = this->water_heater_json_(obj, detail);
|
||||
request->send(200, "application/json", data.c_str());
|
||||
return;
|
||||
}
|
||||
if (!match.method_equals("set")) {
|
||||
request->send(404);
|
||||
return;
|
||||
}
|
||||
auto call = obj->make_call();
|
||||
// Use base class reference for template deduction (make_call returns WaterHeaterCallInternal)
|
||||
water_heater::WaterHeaterCall &base_call = call;
|
||||
|
||||
// Parse mode parameter
|
||||
parse_string_param_(request, ESPHOME_F("mode"), base_call, &water_heater::WaterHeaterCall::set_mode);
|
||||
|
||||
// Parse temperature parameters
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature"), base_call,
|
||||
&water_heater::WaterHeaterCall::set_target_temperature);
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature_low"), base_call,
|
||||
&water_heater::WaterHeaterCall::set_target_temperature_low);
|
||||
parse_float_param_(request, ESPHOME_F("target_temperature_high"), base_call,
|
||||
&water_heater::WaterHeaterCall::set_target_temperature_high);
|
||||
|
||||
// Parse away mode parameter
|
||||
parse_bool_param_(request, ESPHOME_F("away"), base_call, &water_heater::WaterHeaterCall::set_away);
|
||||
|
||||
// Parse on/off parameter
|
||||
parse_bool_param_(request, ESPHOME_F("is_on"), base_call, &water_heater::WaterHeaterCall::set_on);
|
||||
|
||||
this->defer([call]() mutable { call.perform(); });
|
||||
request->send(200);
|
||||
return;
|
||||
}
|
||||
request->send(404);
|
||||
}
|
||||
|
||||
std::string WebServer::water_heater_state_json_generator(WebServer *web_server, void *source) {
|
||||
return web_server->water_heater_json_(static_cast<water_heater::WaterHeater *>(source), DETAIL_STATE);
|
||||
}
|
||||
std::string WebServer::water_heater_all_json_generator(WebServer *web_server, void *source) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
return web_server->water_heater_json_(static_cast<water_heater::WaterHeater *>(source), DETAIL_ALL);
|
||||
}
|
||||
std::string WebServer::water_heater_json_(water_heater::WaterHeater *obj, JsonDetail start_config) {
|
||||
json::JsonBuilder builder;
|
||||
JsonObject root = builder.root();
|
||||
char buf[PSTR_LOCAL_SIZE];
|
||||
|
||||
const auto mode = obj->get_mode();
|
||||
const char *mode_s = PSTR_LOCAL(water_heater::water_heater_mode_to_string(mode));
|
||||
|
||||
set_json_icon_state_value(root, obj, "water_heater", mode_s, mode, start_config);
|
||||
|
||||
auto traits = obj->get_traits();
|
||||
|
||||
if (start_config == DETAIL_ALL) {
|
||||
JsonArray modes = root[ESPHOME_F("modes")].to<JsonArray>();
|
||||
for (auto m : traits.get_supported_modes())
|
||||
modes.add(PSTR_LOCAL(water_heater::water_heater_mode_to_string(m)));
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
if (traits.get_supports_current_temperature()) {
|
||||
float current = obj->get_current_temperature();
|
||||
if (!std::isnan(current))
|
||||
root[ESPHOME_F("current_temperature")] = current;
|
||||
}
|
||||
|
||||
if (traits.get_supports_two_point_target_temperature()) {
|
||||
float low = obj->get_target_temperature_low();
|
||||
float high = obj->get_target_temperature_high();
|
||||
if (!std::isnan(low))
|
||||
root[ESPHOME_F("target_temperature_low")] = low;
|
||||
if (!std::isnan(high))
|
||||
root[ESPHOME_F("target_temperature_high")] = high;
|
||||
} else {
|
||||
float target = obj->get_target_temperature();
|
||||
if (!std::isnan(target))
|
||||
root[ESPHOME_F("target_temperature")] = target;
|
||||
}
|
||||
|
||||
root[ESPHOME_F("min_temperature")] = traits.get_min_temperature();
|
||||
root[ESPHOME_F("max_temperature")] = traits.get_max_temperature();
|
||||
root[ESPHOME_F("step")] = traits.get_target_temperature_step();
|
||||
|
||||
if (traits.get_supports_away_mode()) {
|
||||
root[ESPHOME_F("away")] = obj->is_away();
|
||||
}
|
||||
|
||||
if (traits.has_feature_flags(water_heater::WATER_HEATER_SUPPORTS_ON_OFF)) {
|
||||
root[ESPHOME_F("is_on")] = obj->is_on();
|
||||
}
|
||||
|
||||
return builder.serialize();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void WebServer::on_event(event::Event *obj) {
|
||||
if (!this->include_internal_ && obj->is_internal())
|
||||
@@ -2060,6 +2176,9 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
"update",
|
||||
#endif
|
||||
#ifdef USE_WATER_HEATER
|
||||
"water_heater",
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -2220,6 +2339,11 @@ void WebServer::handleRequest(AsyncWebServerRequest *request) {
|
||||
else if (match.domain_equals("update")) {
|
||||
this->handle_update_request(request, match);
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_WATER_HEATER
|
||||
else if (match.domain_equals("water_heater")) {
|
||||
this->handle_water_heater_request(request, match);
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
// No matching handler found - send 404
|
||||
|
||||
@@ -35,6 +35,13 @@ extern const size_t ESPHOME_WEBSERVER_JS_INCLUDE_SIZE;
|
||||
|
||||
namespace esphome::web_server {
|
||||
|
||||
// Type for parameter names that can be stored in flash on ESP8266
|
||||
#ifdef USE_ESP8266
|
||||
using ParamNameType = const __FlashStringHelper *;
|
||||
#else
|
||||
using ParamNameType = const char *;
|
||||
#endif
|
||||
|
||||
/// Result of matching a URL against an entity
|
||||
struct EntityMatchResult {
|
||||
bool matched; ///< True if entity matched the URL
|
||||
@@ -429,6 +436,16 @@ class WebServer : public Controller,
|
||||
static std::string alarm_control_panel_all_json_generator(WebServer *web_server, void *source);
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
void on_water_heater_update(water_heater::WaterHeater *obj) override;
|
||||
|
||||
/// Handle a water_heater request under '/water_heater/<id>/<mode/set>'.
|
||||
void handle_water_heater_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
||||
|
||||
static std::string water_heater_state_json_generator(WebServer *web_server, void *source);
|
||||
static std::string water_heater_all_json_generator(WebServer *web_server, void *source);
|
||||
#endif
|
||||
|
||||
#ifdef USE_EVENT
|
||||
void on_event(event::Event *obj) override;
|
||||
|
||||
@@ -472,7 +489,7 @@ class WebServer : public Controller,
|
||||
#ifdef USE_LIGHT
|
||||
// Helper to parse and apply a float parameter with optional scaling
|
||||
template<typename T, typename Ret>
|
||||
void parse_light_param_(AsyncWebServerRequest *request, const char *param_name, T &call, Ret (T::*setter)(float),
|
||||
void parse_light_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(float),
|
||||
float scale = 1.0f) {
|
||||
if (request->hasParam(param_name)) {
|
||||
auto value = parse_number<float>(request->getParam(param_name)->value().c_str());
|
||||
@@ -484,7 +501,7 @@ class WebServer : public Controller,
|
||||
|
||||
// Helper to parse and apply a uint32_t parameter with optional scaling
|
||||
template<typename T, typename Ret>
|
||||
void parse_light_param_uint_(AsyncWebServerRequest *request, const char *param_name, T &call,
|
||||
void parse_light_param_uint_(AsyncWebServerRequest *request, ParamNameType param_name, T &call,
|
||||
Ret (T::*setter)(uint32_t), uint32_t scale = 1) {
|
||||
if (request->hasParam(param_name)) {
|
||||
auto value = parse_number<uint32_t>(request->getParam(param_name)->value().c_str());
|
||||
@@ -497,7 +514,7 @@ class WebServer : public Controller,
|
||||
|
||||
// Generic helper to parse and apply a float parameter
|
||||
template<typename T, typename Ret>
|
||||
void parse_float_param_(AsyncWebServerRequest *request, const char *param_name, T &call, Ret (T::*setter)(float)) {
|
||||
void parse_float_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(float)) {
|
||||
if (request->hasParam(param_name)) {
|
||||
auto value = parse_number<float>(request->getParam(param_name)->value().c_str());
|
||||
if (value.has_value()) {
|
||||
@@ -508,7 +525,7 @@ class WebServer : public Controller,
|
||||
|
||||
// Generic helper to parse and apply an int parameter
|
||||
template<typename T, typename Ret>
|
||||
void parse_int_param_(AsyncWebServerRequest *request, const char *param_name, T &call, Ret (T::*setter)(int)) {
|
||||
void parse_int_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(int)) {
|
||||
if (request->hasParam(param_name)) {
|
||||
auto value = parse_number<int>(request->getParam(param_name)->value().c_str());
|
||||
if (value.has_value()) {
|
||||
@@ -519,7 +536,7 @@ class WebServer : public Controller,
|
||||
|
||||
// Generic helper to parse and apply a string parameter
|
||||
template<typename T, typename Ret>
|
||||
void parse_string_param_(AsyncWebServerRequest *request, const char *param_name, T &call,
|
||||
void parse_string_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call,
|
||||
Ret (T::*setter)(const std::string &)) {
|
||||
if (request->hasParam(param_name)) {
|
||||
// .c_str() is required for Arduino framework where value() returns Arduino String instead of std::string
|
||||
@@ -528,6 +545,28 @@ class WebServer : public Controller,
|
||||
}
|
||||
}
|
||||
|
||||
// Generic helper to parse and apply a bool parameter
|
||||
// Accepts: "on", "true", "1" (case-insensitive) as true
|
||||
// Accepts: "off", "false", "0" (case-insensitive) as false
|
||||
// Invalid values are ignored (setter not called)
|
||||
template<typename T, typename Ret>
|
||||
void parse_bool_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(bool)) {
|
||||
if (request->hasParam(param_name)) {
|
||||
auto param_value = request->getParam(param_name)->value();
|
||||
// First check on/off (default), then true/false (custom)
|
||||
auto val = parse_on_off(param_value.c_str());
|
||||
if (val == PARSE_NONE) {
|
||||
val = parse_on_off(param_value.c_str(), "true", "false");
|
||||
}
|
||||
if (val == PARSE_ON || param_value == "1") {
|
||||
(call.*setter)(true);
|
||||
} else if (val == PARSE_OFF || param_value == "0") {
|
||||
(call.*setter)(false);
|
||||
}
|
||||
// PARSE_NONE/PARSE_TOGGLE: ignore invalid values
|
||||
}
|
||||
}
|
||||
|
||||
web_server_base::WebServerBase *base_;
|
||||
#ifdef USE_ESP32
|
||||
AsyncEventSource events_{"/events", this};
|
||||
@@ -606,6 +645,9 @@ class WebServer : public Controller,
|
||||
#ifdef USE_EVENT
|
||||
std::string event_json_(event::Event *obj, const std::string &event_type, JsonDetail start_config);
|
||||
#endif
|
||||
#ifdef USE_WATER_HEATER
|
||||
std::string water_heater_json_(water_heater::WaterHeater *obj, JsonDetail start_config);
|
||||
#endif
|
||||
#ifdef USE_UPDATE
|
||||
std::string update_json_(update::UpdateEntity *obj, JsonDetail start_config);
|
||||
#endif
|
||||
|
||||
@@ -232,6 +232,13 @@ void WebServer::handle_index_request(AsyncWebServerRequest *request) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_WATER_HEATER
|
||||
for (auto *obj : App.get_water_heaters()) {
|
||||
if (this->include_internal_ || !obj->is_internal())
|
||||
write_row(stream, obj, "water_heater", "");
|
||||
}
|
||||
#endif
|
||||
|
||||
stream->print(ESPHOME_F("</tbody></table><p>See <a href=\"https://esphome.io/web-api/\">ESPHome Web API</a> for "
|
||||
"REST API documentation.</p>"));
|
||||
#if defined(USE_WEBSERVER_OTA) && !defined(USE_WEBSERVER_OTA_DISABLED)
|
||||
|
||||
Reference in New Issue
Block a user