1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-21 11:13:46 +01:00

[web_server] Optimize handler methods with lookup tables to reduce flash usage

This commit is contained in:
J. Nick Koston
2025-09-30 11:08:48 +02:00
parent 96868aa754
commit 950310e49a

View File

@@ -829,15 +829,28 @@ void WebServer::handle_cover_request(AsyncWebServerRequest *request, const UrlMa
} }
auto call = obj->make_call(); auto call = obj->make_call();
if (match.method_equals("open")) {
call.set_command_open(); // Lookup table for cover methods
} else if (match.method_equals("close")) { static const struct {
call.set_command_close(); const char *name;
} else if (match.method_equals("stop")) { cover::CoverCall &(cover::CoverCall::*action)();
call.set_command_stop(); } METHODS[] = {
} else if (match.method_equals("toggle")) { {"open", &cover::CoverCall::set_command_open},
call.set_command_toggle(); {"close", &cover::CoverCall::set_command_close},
} else if (!match.method_equals("set")) { {"stop", &cover::CoverCall::set_command_stop},
{"toggle", &cover::CoverCall::set_command_toggle},
};
bool found = false;
for (const auto &method : METHODS) {
if (match.method_equals(method.name)) {
(call.*method.action)();
found = true;
break;
}
}
if (!found && !match.method_equals("set")) {
request->send(404); request->send(404);
return; return;
} }
@@ -1483,15 +1496,28 @@ void WebServer::handle_valve_request(AsyncWebServerRequest *request, const UrlMa
} }
auto call = obj->make_call(); auto call = obj->make_call();
if (match.method_equals("open")) {
call.set_command_open(); // Lookup table for valve methods
} else if (match.method_equals("close")) { static const struct {
call.set_command_close(); const char *name;
} else if (match.method_equals("stop")) { valve::ValveCall &(valve::ValveCall::*action)();
call.set_command_stop(); } METHODS[] = {
} else if (match.method_equals("toggle")) { {"open", &valve::ValveCall::set_command_open},
call.set_command_toggle(); {"close", &valve::ValveCall::set_command_close},
} else if (!match.method_equals("set")) { {"stop", &valve::ValveCall::set_command_stop},
{"toggle", &valve::ValveCall::set_command_toggle},
};
bool found = false;
for (const auto &method : METHODS) {
if (match.method_equals(method.name)) {
(call.*method.action)();
found = true;
break;
}
}
if (!found && !match.method_equals("set")) {
request->send(404); request->send(404);
return; return;
} }
@@ -1555,17 +1581,28 @@ void WebServer::handle_alarm_control_panel_request(AsyncWebServerRequest *reques
auto call = obj->make_call(); auto call = obj->make_call();
parse_string_param_(request, "code", call, &decltype(call)::set_code); parse_string_param_(request, "code", call, &decltype(call)::set_code);
if (match.method_equals("disarm")) { // Lookup table for alarm control panel methods
call.disarm(); static const struct {
} else if (match.method_equals("arm_away")) { const char *name;
call.arm_away(); alarm_control_panel::AlarmControlPanelCall &(alarm_control_panel::AlarmControlPanelCall::*action)();
} else if (match.method_equals("arm_home")) { } METHODS[] = {
call.arm_home(); {"disarm", &alarm_control_panel::AlarmControlPanelCall::disarm},
} else if (match.method_equals("arm_night")) { {"arm_away", &alarm_control_panel::AlarmControlPanelCall::arm_away},
call.arm_night(); {"arm_home", &alarm_control_panel::AlarmControlPanelCall::arm_home},
} else if (match.method_equals("arm_vacation")) { {"arm_night", &alarm_control_panel::AlarmControlPanelCall::arm_night},
call.arm_vacation(); {"arm_vacation", &alarm_control_panel::AlarmControlPanelCall::arm_vacation},
} else { };
bool found = false;
for (const auto &method : METHODS) {
if (match.method_equals(method.name)) {
(call.*method.action)();
found = true;
break;
}
}
if (!found) {
request->send(404); request->send(404);
return; return;
} }
@@ -1731,24 +1768,24 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
const auto &url = request->url(); const auto &url = request->url();
const auto method = request->method(); const auto method = request->method();
// Simple URL checks // Static URL checks
if (url == "/") static const char *const STATIC_URLS[] = {
return true; "/",
#ifdef USE_ARDUINO #ifdef USE_ARDUINO
if (url == "/events") "/events",
return true;
#endif #endif
#ifdef USE_WEBSERVER_CSS_INCLUDE #ifdef USE_WEBSERVER_CSS_INCLUDE
if (url == "/0.css") "/0.css",
return true;
#endif #endif
#ifdef USE_WEBSERVER_JS_INCLUDE #ifdef USE_WEBSERVER_JS_INCLUDE
if (url == "/0.js") "/0.js",
return true;
#endif #endif
};
for (const auto &static_url : STATIC_URLS) {
if (url == static_url)
return true;
}
#ifdef USE_WEBSERVER_PRIVATE_NETWORK_ACCESS #ifdef USE_WEBSERVER_PRIVATE_NETWORK_ACCESS
if (method == HTTP_OPTIONS && request->hasHeader(HEADER_CORS_REQ_PNA)) if (method == HTTP_OPTIONS && request->hasHeader(HEADER_CORS_REQ_PNA))
@@ -1768,92 +1805,87 @@ bool WebServer::canHandle(AsyncWebServerRequest *request) const {
if (!is_get_or_post) if (!is_get_or_post)
return false; return false;
// GET-only components // Use lookup tables for domain checks
if (is_get) { static const char *const GET_ONLY_DOMAINS[] = {
#ifdef USE_SENSOR #ifdef USE_SENSOR
if (match.domain_equals("sensor")) "sensor",
return true;
#endif #endif
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
if (match.domain_equals("binary_sensor")) "binary_sensor",
return true;
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
if (match.domain_equals("text_sensor")) "text_sensor",
return true;
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
if (match.domain_equals("event")) "event",
return true;
#endif #endif
} };
// GET+POST components static const char *const GET_POST_DOMAINS[] = {
if (is_get_or_post) {
#ifdef USE_SWITCH #ifdef USE_SWITCH
if (match.domain_equals("switch")) "switch",
return true;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
if (match.domain_equals("button")) "button",
return true;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
if (match.domain_equals("fan")) "fan",
return true;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
if (match.domain_equals("light")) "light",
return true;
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
if (match.domain_equals("cover")) "cover",
return true;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
if (match.domain_equals("number")) "number",
return true;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
if (match.domain_equals("date")) "date",
return true;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
if (match.domain_equals("time")) "time",
return true;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
if (match.domain_equals("datetime")) "datetime",
return true;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
if (match.domain_equals("text")) "text",
return true;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
if (match.domain_equals("select")) "select",
return true;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
if (match.domain_equals("climate")) "climate",
return true;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
if (match.domain_equals("lock")) "lock",
return true;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
if (match.domain_equals("valve")) "valve",
return true;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
if (match.domain_equals("alarm_control_panel")) "alarm_control_panel",
return true;
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
if (match.domain_equals("update")) "update",
return true;
#endif #endif
};
// Check GET-only domains
if (is_get) {
for (const auto &domain : GET_ONLY_DOMAINS) {
if (match.domain_equals(domain))
return true;
}
}
// Check GET+POST domains
if (is_get_or_post) {
for (const auto &domain : GET_POST_DOMAINS) {
if (match.domain_equals(domain))
return true;
}
} }
return false; return false;