mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 13:27:14 +00:00
[esp32] Consolidate network/coexistence sdkconfig into a single reconciler (#17008)
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
ethernet:
|
||||
type: W5500
|
||||
clk_pin: 19
|
||||
mosi_pin: 21
|
||||
miso_pin: 23
|
||||
cs_pin: 18
|
||||
interrupt_pin: 36
|
||||
reset_pin: 22
|
||||
clock_speed: 10Mhz
|
||||
@@ -0,0 +1,14 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
password: "test_password"
|
||||
|
||||
esp32_ble_tracker:
|
||||
software_coexistence: true
|
||||
11
tests/component_tests/esp32/config/network_wifi_only.yaml
Normal file
11
tests/component_tests/esp32/config/network_wifi_only.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
wifi:
|
||||
ssid: "test_ssid"
|
||||
password: "test_password"
|
||||
@@ -2,14 +2,25 @@
|
||||
Test ESP32 configuration
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.esp32 import VARIANT_ESP32, VARIANTS
|
||||
from esphome.components.esp32.const import KEY_ESP32, KEY_SDKCONFIG_OPTIONS, KEY_VARIANT
|
||||
from esphome.components.esp32 import (
|
||||
VARIANT_ESP32,
|
||||
VARIANTS,
|
||||
NetworkSdkconfigData,
|
||||
_reconcile_network_sdkconfig,
|
||||
)
|
||||
from esphome.components.esp32.const import (
|
||||
KEY_ESP32,
|
||||
KEY_NETWORK_SDKCONFIG,
|
||||
KEY_SDKCONFIG_OPTIONS,
|
||||
KEY_VARIANT,
|
||||
)
|
||||
from esphome.components.esp32.gpio import validate_gpio_pin
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -343,3 +354,183 @@ def test_flash_mode_unset_leaves_defaults(
|
||||
assert not any(key.startswith("CONFIG_ESPTOOLPY_FLASHFREQ_") for key in sdkconfig)
|
||||
assert "board_build.flash_mode" not in CORE.platformio_options
|
||||
assert "board_build.f_flash" not in CORE.platformio_options
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("framework", "net", "preset", "expected"),
|
||||
[
|
||||
# --- IDF: single-interface cases (must match pre-refactor behavior) ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(wifi=True),
|
||||
{},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_SOFTAP_SUPPORT": False,
|
||||
"CONFIG_LWIP_DHCPS": False,
|
||||
},
|
||||
id="idf_wifi_no_ap",
|
||||
),
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(wifi=True, wifi_ap=True),
|
||||
{},
|
||||
{},
|
||||
id="idf_wifi_ap_leaves_softap_dhcps",
|
||||
),
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(ethernet=True),
|
||||
{},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_ENABLED": False,
|
||||
"CONFIG_SW_COEXIST_ENABLE": False,
|
||||
},
|
||||
id="idf_ethernet_only",
|
||||
),
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(
|
||||
wifi=True, bluetooth=True, ble_42=True, software_coexistence=True
|
||||
),
|
||||
{},
|
||||
{
|
||||
"CONFIG_BT_ENABLED": True,
|
||||
"CONFIG_BT_BLE_42_FEATURES_SUPPORTED": True,
|
||||
"CONFIG_SW_COEXIST_ENABLE": True,
|
||||
"CONFIG_ESP_WIFI_SOFTAP_SUPPORT": False,
|
||||
"CONFIG_LWIP_DHCPS": False,
|
||||
},
|
||||
id="idf_wifi_ble_tracker_coexistence",
|
||||
),
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(bluetooth=True),
|
||||
{},
|
||||
{"CONFIG_BT_ENABLED": True},
|
||||
id="idf_ble_server_only_no_ble42",
|
||||
),
|
||||
# --- IDF: user sdkconfig_options always win ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(wifi=True),
|
||||
{"CONFIG_ESP_WIFI_SOFTAP_SUPPORT": True},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_SOFTAP_SUPPORT": True,
|
||||
"CONFIG_LWIP_DHCPS": False,
|
||||
},
|
||||
id="idf_user_override_wins",
|
||||
),
|
||||
# --- IDF: user advanced enable_lwip_dhcp_server: false, even with AP ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(
|
||||
wifi=True, wifi_ap=True, enable_lwip_dhcp_server=False
|
||||
),
|
||||
{},
|
||||
{"CONFIG_LWIP_DHCPS": False},
|
||||
id="idf_user_disables_dhcps_with_ap",
|
||||
),
|
||||
# --- IDF: WiFi + Ethernet coexist (the multi-interface unlock) ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
NetworkSdkconfigData(wifi=True, ethernet=True),
|
||||
{},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_SOFTAP_SUPPORT": False,
|
||||
"CONFIG_LWIP_DHCPS": False,
|
||||
},
|
||||
id="idf_wifi_and_ethernet_keeps_wifi_enabled",
|
||||
),
|
||||
# --- Arduino: SoftAP/DHCPS disable is IDF-only ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_ARDUINO,
|
||||
NetworkSdkconfigData(wifi=True),
|
||||
{},
|
||||
{},
|
||||
id="arduino_wifi_no_ap_untouched",
|
||||
),
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_ARDUINO,
|
||||
NetworkSdkconfigData(ethernet=True),
|
||||
{},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_ENABLED": False,
|
||||
"CONFIG_SW_COEXIST_ENABLE": False,
|
||||
},
|
||||
id="arduino_ethernet_only_disables_wifi",
|
||||
),
|
||||
# --- Arduino + Ethernet: DHCPS stays available even if user disabled it ---
|
||||
pytest.param(
|
||||
PlatformFramework.ESP32_ARDUINO,
|
||||
NetworkSdkconfigData(ethernet=True, enable_lwip_dhcp_server=False),
|
||||
{},
|
||||
{
|
||||
"CONFIG_ESP_WIFI_ENABLED": False,
|
||||
"CONFIG_SW_COEXIST_ENABLE": False,
|
||||
},
|
||||
id="arduino_ethernet_dhcps_exclusion",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_reconcile_network_sdkconfig(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
framework: PlatformFramework,
|
||||
net: NetworkSdkconfigData,
|
||||
preset: dict[str, Any],
|
||||
expected: dict[str, Any],
|
||||
) -> None:
|
||||
"""The FINAL-priority reconciler resolves WiFi/Ethernet/Bluetooth/coexistence
|
||||
sdkconfig flags from the requests recorded in NetworkSdkconfigData."""
|
||||
set_core_config(framework)
|
||||
CORE.data[KEY_ESP32] = {
|
||||
KEY_SDKCONFIG_OPTIONS: dict(preset),
|
||||
KEY_NETWORK_SDKCONFIG: net,
|
||||
}
|
||||
|
||||
asyncio.run(_reconcile_network_sdkconfig())
|
||||
|
||||
assert CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS] == expected
|
||||
|
||||
|
||||
def test_network_wifi_only_reconciles_end_to_end(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""End-to-end: codegen for an ESP-IDF WiFi (no AP) config runs the reconciler
|
||||
after wifi's request_wifi(), disabling SoftAP support and the DHCP server."""
|
||||
generate_main(component_config_path("network_wifi_only.yaml"))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert sdkconfig.get("CONFIG_ESP_WIFI_SOFTAP_SUPPORT") is False
|
||||
assert sdkconfig.get("CONFIG_LWIP_DHCPS") is False
|
||||
# WiFi stack stays enabled (no ethernet) and no Bluetooth requested.
|
||||
assert "CONFIG_ESP_WIFI_ENABLED" not in sdkconfig
|
||||
assert "CONFIG_BT_ENABLED" not in sdkconfig
|
||||
|
||||
|
||||
def test_network_ethernet_only_reconciles_end_to_end(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""End-to-end: ethernet's request_ethernet() makes the reconciler disable the
|
||||
WiFi stack and coexistence when WiFi is absent."""
|
||||
generate_main(component_config_path("network_ethernet_only.yaml"))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert sdkconfig.get("CONFIG_ESP_WIFI_ENABLED") is False
|
||||
assert sdkconfig.get("CONFIG_SW_COEXIST_ENABLE") is False
|
||||
|
||||
|
||||
def test_network_wifi_ble_coexistence_reconciles_end_to_end(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
component_config_path: Callable[[str], Path],
|
||||
) -> None:
|
||||
"""End-to-end: WiFi + esp32_ble_tracker software_coexistence resolves to
|
||||
BT enabled and coexistence on, with SoftAP/DHCP server dropped (no AP)."""
|
||||
generate_main(component_config_path("network_wifi_ble_coexistence.yaml"))
|
||||
sdkconfig = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
assert sdkconfig.get("CONFIG_BT_ENABLED") is True
|
||||
assert sdkconfig.get("CONFIG_BT_BLE_42_FEATURES_SUPPORTED") is True
|
||||
assert sdkconfig.get("CONFIG_SW_COEXIST_ENABLE") is True
|
||||
assert sdkconfig.get("CONFIG_ESP_WIFI_SOFTAP_SUPPORT") is False
|
||||
assert sdkconfig.get("CONFIG_LWIP_DHCPS") is False
|
||||
# WiFi present alongside BT -> WiFi stack must stay enabled.
|
||||
assert "CONFIG_ESP_WIFI_ENABLED" not in sdkconfig
|
||||
|
||||
Reference in New Issue
Block a user