Eliminate double query lookups and unify numeric parse helpers

- Mark find_query_value_ as const
- Remove redundant hasArg() guards where parse_number() already
  handles empty strings (returns nullopt)
- Use !empty() instead of hasArg() for parse_bool_param_
- Merge parse_float_param_ and parse_int_param_ into single
  parse_num_param_ template
- Combine missing/empty checks for IR data parameter
This commit is contained in:
J. Nick Koston
2026-02-11 17:54:56 -06:00
parent 2a89088bc3
commit f92725f76e
4 changed files with 34 additions and 57 deletions

View File

@@ -860,7 +860,7 @@ void WebServer::handle_fan_request(AsyncWebServerRequest *request, const UrlMatc
}
auto call = is_on ? obj->turn_on() : obj->turn_off();
parse_int_param_(request, ESPHOME_F("speed_level"), call, &decltype(call)::set_speed);
parse_num_param_(request, ESPHOME_F("speed_level"), call, &decltype(call)::set_speed);
if (request->hasArg(ESPHOME_F("oscillation"))) {
auto speed = request->arg(ESPHOME_F("oscillation"));
@@ -1045,8 +1045,8 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
return;
}
parse_float_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
parse_float_param_(request, ESPHOME_F("tilt"), call, &decltype(call)::set_tilt);
parse_num_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
parse_num_param_(request, ESPHOME_F("tilt"), call, &decltype(call)::set_tilt);
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1105,7 +1105,7 @@ void WebServer::handle_number_request(AsyncWebServerRequest *request, const UrlM
}
auto call = obj->make_call();
parse_float_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_value);
parse_num_param_(request, ESPHOME_F("value"), call, &decltype(call)::set_value);
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1476,10 +1476,9 @@ void WebServer::handle_climate_request(AsyncWebServerRequest *request, const Url
parse_string_param_(request, ESPHOME_F("swing_mode"), call, &decltype(call)::set_swing_mode);
// Parse temperature parameters
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);
parse_num_param_(request, ESPHOME_F("target_temperature_high"), call, &decltype(call)::set_target_temperature_high);
parse_num_param_(request, ESPHOME_F("target_temperature_low"), call, &decltype(call)::set_target_temperature_low);
parse_num_param_(request, ESPHOME_F("target_temperature"), call, &decltype(call)::set_target_temperature);
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1725,7 +1724,7 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
return;
}
parse_float_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
parse_num_param_(request, ESPHOME_F("position"), call, &decltype(call)::set_position);
DEFER_ACTION(call, call.perform());
request->send(200);
@@ -1869,12 +1868,12 @@ void WebServer::handle_water_heater_request(AsyncWebServerRequest *request, cons
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_num_param_(request, ESPHOME_F("target_temperature"), base_call,
&water_heater::WaterHeaterCall::set_target_temperature);
parse_num_param_(request, ESPHOME_F("target_temperature_low"), base_call,
&water_heater::WaterHeaterCall::set_target_temperature_low);
parse_num_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);
@@ -1978,7 +1977,7 @@ void WebServer::handle_infrared_request(AsyncWebServerRequest *request, const Ur
auto call = obj->make_call();
// Parse carrier frequency (optional)
if (request->hasArg(ESPHOME_F("carrier_frequency"))) {
{
auto value = parse_number<uint32_t>(request->arg(ESPHOME_F("carrier_frequency")).c_str());
if (value.has_value()) {
call.set_carrier_frequency(*value);
@@ -1986,7 +1985,7 @@ void WebServer::handle_infrared_request(AsyncWebServerRequest *request, const Ur
}
// Parse repeat count (optional, defaults to 1)
if (request->hasArg(ESPHOME_F("repeat_count"))) {
{
auto value = parse_number<uint32_t>(request->arg(ESPHOME_F("repeat_count")).c_str());
if (value.has_value()) {
call.set_repeat_count(*value);
@@ -1995,17 +1994,12 @@ void WebServer::handle_infrared_request(AsyncWebServerRequest *request, const Ur
// Parse base64url-encoded raw timings (required)
// Base64url is URL-safe: uses A-Za-z0-9-_ (no special characters needing escaping)
if (!request->hasArg(ESPHOME_F("data"))) {
request->send(400, ESPHOME_F("text/plain"), ESPHOME_F("Missing 'data' parameter"));
return;
}
// .c_str() is required for Arduino framework where arg() returns Arduino String instead of std::string
std::string encoded = request->arg(ESPHOME_F("data")).c_str(); // NOLINT(readability-redundant-string-cstr)
// Validate base64url is not empty
// Validate base64url is not empty (also catches missing parameter since arg() returns empty string)
if (encoded.empty()) {
request->send(400, ESPHOME_F("text/plain"), ESPHOME_F("Empty 'data' parameter"));
request->send(400, ESPHOME_F("text/plain"), ESPHOME_F("Missing or empty 'data' parameter"));
return;
}

View File

@@ -513,11 +513,9 @@ class WebServer : public Controller,
template<typename T, typename Ret>
void parse_light_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(float),
float scale = 1.0f) {
if (request->hasArg(param_name)) {
auto value = parse_number<float>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value / scale);
}
auto value = parse_number<float>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value / scale);
}
}
@@ -525,34 +523,19 @@ class WebServer : public Controller,
template<typename T, typename Ret>
void parse_light_param_uint_(AsyncWebServerRequest *request, ParamNameType param_name, T &call,
Ret (T::*setter)(uint32_t), uint32_t scale = 1) {
if (request->hasArg(param_name)) {
auto value = parse_number<uint32_t>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value * scale);
}
auto value = parse_number<uint32_t>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value * scale);
}
}
#endif
// Generic helper to parse and apply a float parameter
template<typename T, typename Ret>
void parse_float_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(float)) {
if (request->hasArg(param_name)) {
auto value = parse_number<float>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value);
}
}
}
// Generic helper to parse and apply an int parameter
template<typename T, typename Ret>
void parse_int_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(int)) {
if (request->hasArg(param_name)) {
auto value = parse_number<int>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value);
}
// Generic helper to parse and apply a numeric parameter
template<typename NumT, typename T, typename Ret>
void parse_num_param_(AsyncWebServerRequest *request, ParamNameType param_name, T &call, Ret (T::*setter)(NumT)) {
auto value = parse_number<NumT>(request->arg(param_name).c_str());
if (value.has_value()) {
(call.*setter)(*value);
}
}
@@ -573,8 +556,8 @@ class WebServer : public Controller,
// 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->hasArg(param_name)) {
const auto &param_value = request->arg(param_name);
const auto &param_value = request->arg(param_name);
if (!param_value.empty()) {
// First check on/off (default), then true/false (custom)
auto val = parse_on_off(param_value.c_str());
if (val == PARSE_NONE) {

View File

@@ -412,7 +412,7 @@ AsyncWebParameter *AsyncWebServerRequest::getParam(const char *name) {
return param;
}
optional<std::string> AsyncWebServerRequest::find_query_value_(const char *name) {
optional<std::string> AsyncWebServerRequest::find_query_value_(const char *name) const {
auto val = query_key_value(this->post_query_.c_str(), this->post_query_.size(), name);
if (val.has_value()) {
return val;

View File

@@ -186,7 +186,7 @@ class AsyncWebServerRequest {
// is faster than tree/hash overhead. AsyncWebParameter stores both name and value to avoid
// duplicate storage. Only successful lookups are cached to prevent cache pollution when
// handlers check for optional parameters that don't exist.
optional<std::string> find_query_value_(const char *name);
optional<std::string> find_query_value_(const char *name) const;
std::vector<AsyncWebParameter *> params_;
std::string post_query_;
AsyncWebServerRequest(httpd_req_t *req) : req_(req) {}