[web_server] Skip setters that pass the default port, log and include internal values (#19226)

This commit is contained in:
J. Nick Koston
2026-09-16 12:00:03 +12:00
committed by Jesse Hills
parent 8c999d3152
commit 6582c618f1
6 changed files with 93 additions and 6 deletions
+15 -5
View File
@@ -56,6 +56,10 @@ CONF_SORTING_GROUPS = "sorting_groups"
CONF_SORTING_WEIGHT = "sorting_weight"
CONF_ALLOWED_ORIGINS = "allowed_origins"
# Schema default that also matches the C++ initializer in web_server_base.h; codegen
# skips the setter when the config equals it.
DEFAULT_PORT = 80
web_server_ns = cg.esphome_ns.namespace("web_server")
WebServer = web_server_ns.class_("WebServer", cg.Component, cg.Controller)
@@ -251,7 +255,7 @@ CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.declare_id(WebServer),
cv.Optional(CONF_PORT, default=80): cv.port,
cv.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
cv.Optional(CONF_VERSION, default=2): cv.one_of(1, 2, 3, int=True),
cv.Optional(CONF_CSS_URL): cv.string,
cv.Optional(CONF_CSS_INCLUDE): cv.file_,
@@ -379,9 +383,11 @@ async def to_code(config: ConfigType) -> None:
version = config[CONF_VERSION]
cg.add(paren.set_port(config[CONF_PORT]))
# Skip the setter when the config matches the C++ initializer (DEFAULT_PORT).
if (port := config[CONF_PORT]) != DEFAULT_PORT:
cg.add(paren.set_port(port))
cg.add_define("USE_WEBSERVER")
cg.add_define("USE_WEBSERVER_PORT", config[CONF_PORT])
cg.add_define("USE_WEBSERVER_PORT", port)
cg.add_define("USE_WEBSERVER_VERSION", version)
if version >= 2:
# Don't compress the index HTML as the data sizes are almost the same.
@@ -395,9 +401,11 @@ async def to_code(config: ConfigType) -> None:
# Captive portal will still be able to perform OTA updates even when this is set
if config.get(CONF_OTA) is False:
cg.add_define("USE_WEBSERVER_OTA_DISABLED")
cg.add(var.set_expose_log(config[CONF_LOG]))
# expose_log_ is true in C++; only emit the setter to turn it off.
if config[CONF_LOG]:
request_log_listener() # Request a log listener slot for web server log streaming
else:
cg.add(var.set_expose_log(False))
if config[CONF_ENABLE_PRIVATE_NETWORK_ACCESS]:
cg.add_define("USE_WEBSERVER_PRIVATE_NETWORK_ACCESS")
if (allowed_origins := config.get(CONF_ALLOWED_ORIGINS)) is not None:
@@ -433,7 +441,9 @@ async def to_code(config: ConfigType) -> None:
path = CORE.relative_config_path(config[CONF_JS_INCLUDE])
with path.open(encoding="utf-8") as js_file:
add_resource_as_progmem("JS_INCLUDE", js_file.read())
cg.add(var.set_include_internal(config[CONF_INCLUDE_INTERNAL]))
# include_internal_ is false in C++; only emit the setter to turn it on.
if config[CONF_INCLUDE_INTERNAL]:
cg.add(var.set_include_internal(True))
if CONF_LOCAL in config and config[CONF_LOCAL]:
cg.add_define("USE_WEBSERVER_LOCAL")
if config[CONF_COMPRESSION] == "gzip":
@@ -170,7 +170,7 @@ class WebServerBase final {
protected:
uint8_t initialized_{0};
uint16_t port_{80};
uint16_t port_{80}; // Keep in sync with DEFAULT_PORT in web_server/__init__.py
AsyncWebServer *server_{nullptr};
std::vector<AsyncWebHandler *> handlers_;
#ifdef USE_WEBSERVER_AUTH
@@ -0,0 +1,12 @@
---
esphome:
name: test
esp32:
board: esp32dev
wifi:
ssid: test
password: testtest
web_server:
@@ -0,0 +1,15 @@
---
esphome:
name: test
esp32:
board: esp32dev
wifi:
ssid: test
password: testtest
web_server:
port: 8080
log: false
include_internal: true
@@ -0,0 +1,15 @@
---
esphome:
name: test
esp32:
board: esp32dev
wifi:
ssid: test
password: testtest
web_server:
port: 80
log: true
include_internal: false
@@ -0,0 +1,35 @@
"""Tests that web_server only emits setters for non default values."""
from collections.abc import Callable
from pathlib import Path
import pytest
@pytest.mark.parametrize("config_file", ["bare.yaml", "defaults.yaml"])
def test_default_values_are_not_emitted(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
config_file: str,
) -> None:
"""Port 80, log on and include_internal off already live in the C++ initializers.
Both the schema defaults and the same values written explicitly take the skip path.
"""
main_cpp = generate_main(component_config_path(config_file))
assert "set_port(" not in main_cpp
assert "set_expose_log(" not in main_cpp
assert "set_include_internal(" not in main_cpp
def test_custom_values_are_emitted(
generate_main: Callable[[str | Path], str],
component_config_path: Callable[[str], Path],
) -> None:
"""Non default values still reach the C++ setters."""
main_cpp = generate_main(component_config_path("custom.yaml"))
assert "set_port(8080);" in main_cpp
assert "set_expose_log(false);" in main_cpp
assert "set_include_internal(true);" in main_cpp