Merge remote-tracking branch 'origin/web_server' into integration

This commit is contained in:
J. Nick Koston
2026-02-27 16:02:33 -10:00
11 changed files with 82 additions and 32 deletions

View File

@@ -12,7 +12,14 @@ AlarmControlPanelCall::AlarmControlPanelCall(AlarmControlPanel *parent) : parent
AlarmControlPanelCall &AlarmControlPanelCall::set_code(const char *code) {
if (code != nullptr) {
this->code_ = std::string(code);
return this->set_code(code, strlen(code));
}
return *this;
}
AlarmControlPanelCall &AlarmControlPanelCall::set_code(const char *code, size_t len) {
if (code != nullptr) {
this->code_ = std::string(code, len);
}
return *this;
}

View File

@@ -15,7 +15,8 @@ class AlarmControlPanelCall {
AlarmControlPanelCall(AlarmControlPanel *parent);
AlarmControlPanelCall &set_code(const char *code);
AlarmControlPanelCall &set_code(const std::string &code) { return this->set_code(code.c_str()); }
AlarmControlPanelCall &set_code(const char *code, size_t len);
AlarmControlPanelCall &set_code(const std::string &code) { return this->set_code(code.c_str(), code.size()); }
AlarmControlPanelCall &arm_away();
AlarmControlPanelCall &arm_home();
AlarmControlPanelCall &arm_night();

View File

@@ -879,7 +879,7 @@ uint16_t APIConnection::try_send_text_info(EntityBase *entity, APIConnection *co
}
void APIConnection::on_text_command_request(const TextCommandRequest &msg) {
ENTITY_COMMAND_MAKE_CALL(text::Text, text, text)
call.set_value(msg.state);
call.set_value(msg.state.c_str(), msg.state.size());
call.perform();
}
#endif
@@ -1350,7 +1350,7 @@ void APIConnection::on_alarm_control_panel_command_request(const AlarmControlPan
call.pending();
break;
}
call.set_code(msg.code);
call.set_code(msg.code.c_str(), msg.code.size());
call.perform();
}
#endif

View File

@@ -173,14 +173,17 @@ ClimateCall &ClimateCall::set_mode(ClimateMode mode) {
return *this;
}
ClimateCall &ClimateCall::set_mode(const std::string &mode) {
ClimateCall &ClimateCall::set_mode(const std::string &mode) { return this->set_mode(mode.c_str(), mode.size()); }
ClimateCall &ClimateCall::set_mode(const char *mode, size_t len) {
StringRef mode_ref(mode, len);
for (const auto &mode_entry : CLIMATE_MODES_BY_STR) {
if (str_equals_case_insensitive(mode, mode_entry.str)) {
if (str_equals_case_insensitive(mode_ref, mode_entry.str)) {
this->set_mode(static_cast<ClimateMode>(mode_entry.value));
return *this;
}
}
ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str());
ESP_LOGW(TAG, "'%s' - Unrecognized mode %.*s", this->parent_->get_name().c_str(), (int) len, mode);
return *this;
}
@@ -266,13 +269,18 @@ ClimateCall &ClimateCall::set_swing_mode(ClimateSwingMode swing_mode) {
}
ClimateCall &ClimateCall::set_swing_mode(const std::string &swing_mode) {
return this->set_swing_mode(swing_mode.c_str(), swing_mode.size());
}
ClimateCall &ClimateCall::set_swing_mode(const char *swing_mode, size_t len) {
StringRef mode_ref(swing_mode, len);
for (const auto &mode_entry : CLIMATE_SWING_MODES_BY_STR) {
if (str_equals_case_insensitive(swing_mode, mode_entry.str)) {
if (str_equals_case_insensitive(mode_ref, mode_entry.str)) {
this->set_swing_mode(static_cast<ClimateSwingMode>(mode_entry.value));
return *this;
}
}
ESP_LOGW(TAG, "'%s' - Unrecognized swing mode %s", this->parent_->get_name().c_str(), swing_mode.c_str());
ESP_LOGW(TAG, "'%s' - Unrecognized swing mode %.*s", this->parent_->get_name().c_str(), (int) len, swing_mode);
return *this;
}

View File

@@ -41,6 +41,8 @@ class ClimateCall {
ClimateCall &set_mode(optional<ClimateMode> mode);
/// Set the mode of the climate device based on a string.
ClimateCall &set_mode(const std::string &mode);
/// Set the mode of the climate device based on a C string.
ClimateCall &set_mode(const char *mode, size_t len);
/// Set the target temperature of the climate device.
ClimateCall &set_target_temperature(float target_temperature);
/// Set the target temperature of the climate device.
@@ -87,6 +89,8 @@ class ClimateCall {
ClimateCall &set_swing_mode(optional<ClimateSwingMode> swing_mode);
/// Set the swing mode of the climate device based on a string.
ClimateCall &set_swing_mode(const std::string &swing_mode);
/// Set the swing mode of the climate device based on a C string.
ClimateCall &set_swing_mode(const char *swing_mode, size_t len);
/// Set the preset of the climate device.
ClimateCall &set_preset(ClimatePreset preset);
/// Set the preset of the climate device.

View File

@@ -11,6 +11,11 @@ TextCall &TextCall::set_value(const std::string &value) {
return *this;
}
TextCall &TextCall::set_value(const char *value, size_t len) {
this->value_ = std::string(value, len);
return *this;
}
void TextCall::validate_() {
const auto *name = this->parent_->get_name().c_str();

View File

@@ -13,6 +13,7 @@ class TextCall {
void perform();
TextCall &set_value(const std::string &value);
TextCall &set_value(const char *value, size_t len);
protected:
Text *const parent_;

View File

@@ -5,6 +5,7 @@
#include "esphome/core/progmem.h"
#include <cmath>
#include <cstring>
namespace esphome::water_heater {
@@ -23,23 +24,25 @@ WaterHeaterCall &WaterHeaterCall::set_mode(WaterHeaterMode mode) {
return *this;
}
WaterHeaterCall &WaterHeaterCall::set_mode(const char *mode) {
if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("OFF")) == 0) {
WaterHeaterCall &WaterHeaterCall::set_mode(const char *mode) { return this->set_mode(mode, strlen(mode)); }
WaterHeaterCall &WaterHeaterCall::set_mode(const char *mode, size_t len) {
if (len == 3 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("OFF"), 3) == 0) {
this->set_mode(WATER_HEATER_MODE_OFF);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("ECO")) == 0) {
} else if (len == 3 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("ECO"), 3) == 0) {
this->set_mode(WATER_HEATER_MODE_ECO);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("ELECTRIC")) == 0) {
} else if (len == 8 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("ELECTRIC"), 8) == 0) {
this->set_mode(WATER_HEATER_MODE_ELECTRIC);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("PERFORMANCE")) == 0) {
} else if (len == 11 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("PERFORMANCE"), 11) == 0) {
this->set_mode(WATER_HEATER_MODE_PERFORMANCE);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("HIGH_DEMAND")) == 0) {
} else if (len == 11 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("HIGH_DEMAND"), 11) == 0) {
this->set_mode(WATER_HEATER_MODE_HIGH_DEMAND);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("HEAT_PUMP")) == 0) {
} else if (len == 9 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("HEAT_PUMP"), 9) == 0) {
this->set_mode(WATER_HEATER_MODE_HEAT_PUMP);
} else if (ESPHOME_strcasecmp_P(mode, ESPHOME_PSTR("GAS")) == 0) {
} else if (len == 3 && ESPHOME_strncasecmp_P(mode, ESPHOME_PSTR("GAS"), 3) == 0) {
this->set_mode(WATER_HEATER_MODE_GAS);
} else {
ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode);
ESP_LOGW(TAG, "'%s' - Unrecognized mode %.*s", this->parent_->get_name().c_str(), (int) len, mode);
}
return *this;
}

View File

@@ -76,7 +76,8 @@ class WaterHeaterCall {
WaterHeaterCall &set_mode(WaterHeaterMode mode);
WaterHeaterCall &set_mode(const char *mode);
WaterHeaterCall &set_mode(const std::string &mode) { return this->set_mode(mode.c_str()); }
WaterHeaterCall &set_mode(const char *mode, size_t len);
WaterHeaterCall &set_mode(const std::string &mode) { return this->set_mode(mode.c_str(), mode.size()); }
WaterHeaterCall &set_target_temperature(float temperature);
WaterHeaterCall &set_target_temperature_low(float temperature);
WaterHeaterCall &set_target_temperature_high(float temperature);

View File

@@ -970,7 +970,9 @@ void WebServer::handle_light_request(AsyncWebServerRequest *request, const UrlMa
parse_light_param_uint_(request, ESPHOME_F("transition"), call, &decltype(call)::set_transition_length, 1000);
if (is_on) {
parse_string_param_(request, ESPHOME_F("effect"), call, &decltype(call)::set_effect);
parse_cstr_param_(
request, ESPHOME_F("effect"), call,
static_cast<light::LightCall &(light::LightCall::*) (const char *, size_t)>(&decltype(call)::set_effect));
}
DEFER_ACTION(call, call.perform());
@@ -1369,7 +1371,9 @@ void WebServer::handle_text_request(AsyncWebServerRequest *request, const UrlMat
}
auto call = obj->make_call();
parse_string_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_value);
parse_cstr_param_(
request, ESPHOME_F("value"), call,
static_cast<text::TextCall &(text::TextCall::*) (const char *, size_t)>(&decltype(call)::set_value));
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1427,7 +1431,9 @@ void WebServer::handle_select_request(AsyncWebServerRequest *request, const UrlM
}
auto call = obj->make_call();
parse_string_param_(request, ESPHOME_F("option"), call, &decltype(call)::set_option);
parse_cstr_param_(
request, ESPHOME_F("option"), call,
static_cast<select::SelectCall &(select::SelectCall::*) (const char *, size_t)>(&decltype(call)::set_option));
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1488,10 +1494,18 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
auto call = obj->make_call();
// Parse string mode parameters
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_string_param_(request, ESPHOME_F("preset"), call, &decltype(call)::set_preset);
parse_cstr_param_(
request, ESPHOME_F("mode"), call,
static_cast<climate::ClimateCall &(climate::ClimateCall::*) (const char *, size_t)>(&decltype(call)::set_mode));
parse_cstr_param_(request, ESPHOME_F("fan_mode"), call,
static_cast<climate::ClimateCall &(climate::ClimateCall::*) (const char *, size_t)>(
&decltype(call)::set_fan_mode));
parse_cstr_param_(request, ESPHOME_F("swing_mode"), call,
static_cast<climate::ClimateCall &(climate::ClimateCall::*) (const char *, size_t)>(
&decltype(call)::set_swing_mode));
parse_cstr_param_(request, ESPHOME_F("preset"), call,
static_cast<climate::ClimateCall &(climate::ClimateCall::*) (const char *, size_t)>(
&decltype(call)::set_preset));
// Parse temperature parameters
// static_cast needed to disambiguate overloaded setters (float vs optional<float>)
@@ -1820,7 +1834,10 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
}
auto call = obj->make_call();
parse_string_param_(request, ESPHOME_F("code"), call, &decltype(call)::set_code);
parse_cstr_param_(
request, ESPHOME_F("code"), call,
static_cast<alarm_control_panel::AlarmControlPanelCall &(
alarm_control_panel::AlarmControlPanelCall::*) (const char *, size_t)>(&decltype(call)::set_code));
// Lookup table for alarm control panel methods
static const struct {
@@ -1908,7 +1925,10 @@ void WebServer::handle_water_heater_request(AsyncWebServerRequest *request, cons
water_heater::WaterHeaterCall &base_call = call;
// Parse mode parameter
parse_string_param_(request, ESPHOME_F("mode"), base_call, &water_heater::WaterHeaterCall::set_mode);
parse_cstr_param_(
request, ESPHOME_F("mode"), base_call,
static_cast<water_heater::WaterHeaterCall &(water_heater::WaterHeaterCall::*) (const char *, size_t)>(
&water_heater::WaterHeaterCall::set_mode));
// Parse temperature parameters
parse_num_param_(request, ESPHOME_F("target_temperature"), base_call,

View File

@@ -533,13 +533,13 @@ class WebServer final : public Controller, public Component, public AsyncWebHand
}
}
// Generic helper to parse and apply a string parameter
// Generic helper to parse and apply a string parameter using const char* setter (avoids std::string allocation)
template<typename T, typename Ret>
void parse_string_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call,
Ret (T::*setter)(const std::string &)) {
void parse_cstr_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call,
Ret (T::*setter)(const char *, size_t)) {
if (request->hasArg(param_name)) {
const auto &value = request->arg(param_name);
(call.*setter)(std::string(value.c_str(), value.length()));
(call.*setter)(value.c_str(), value.length());
}
}