mirror of
https://github.com/esphome/esphome.git
synced 2026-06-24 11:07:33 +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:
@@ -69,6 +69,7 @@ from .const import (
|
||||
KEY_FLASH_SIZE,
|
||||
KEY_FULL_CERT_BUNDLE,
|
||||
KEY_IDF_VERSION,
|
||||
KEY_NETWORK_SDKCONFIG,
|
||||
KEY_PATH,
|
||||
KEY_REF,
|
||||
KEY_REPO,
|
||||
@@ -597,6 +598,59 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType):
|
||||
CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS][name] = value
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkSdkconfigData:
|
||||
"""Inputs for the network-related esp32 sdkconfig flags, reconciled at FINAL.
|
||||
|
||||
Components call the request_*() helpers below (and esp32's own to_code fills
|
||||
in enable_lwip_dhcp_server) instead of setting the WiFi/Ethernet/Bluetooth
|
||||
sdkconfig flags directly; the single _reconcile_network_sdkconfig() coroutine
|
||||
then decides the final values so they no longer depend on call order.
|
||||
"""
|
||||
|
||||
wifi: bool = False # WiFi component active (STA and/or AP)
|
||||
wifi_ap: bool = False # WiFi AP mode configured
|
||||
ethernet: bool = False # Ethernet component active
|
||||
bluetooth: bool = False # any BLE component active
|
||||
ble_42: bool = False # BLE 4.2 features needed
|
||||
software_coexistence: bool = False # WiFi/BT software coexistence requested
|
||||
# esp32 advanced enable_lwip_dhcp_server option (True/False/None=unset)
|
||||
enable_lwip_dhcp_server: bool | None = None
|
||||
|
||||
|
||||
def _network_sdkconfig() -> NetworkSdkconfigData:
|
||||
data = CORE.data[KEY_ESP32]
|
||||
if KEY_NETWORK_SDKCONFIG not in data:
|
||||
data[KEY_NETWORK_SDKCONFIG] = NetworkSdkconfigData()
|
||||
return data[KEY_NETWORK_SDKCONFIG]
|
||||
|
||||
|
||||
def request_wifi(ap: bool = False) -> None:
|
||||
"""Request the WiFi stack. Pass ap=True when AP mode is configured."""
|
||||
net = _network_sdkconfig()
|
||||
net.wifi = True
|
||||
if ap:
|
||||
net.wifi_ap = True
|
||||
|
||||
|
||||
def request_ethernet() -> None:
|
||||
"""Request the Ethernet stack."""
|
||||
_network_sdkconfig().ethernet = True
|
||||
|
||||
|
||||
def request_bluetooth(ble_42: bool = False) -> None:
|
||||
"""Request the Bluetooth controller. Pass ble_42=True for 4.2 features."""
|
||||
net = _network_sdkconfig()
|
||||
net.bluetooth = True
|
||||
if ble_42:
|
||||
net.ble_42 = True
|
||||
|
||||
|
||||
def request_software_coexistence() -> None:
|
||||
"""Request WiFi/BT software coexistence (only valid alongside WiFi)."""
|
||||
_network_sdkconfig().software_coexistence = True
|
||||
|
||||
|
||||
def add_idf_component(
|
||||
*,
|
||||
name: str,
|
||||
@@ -1847,6 +1901,61 @@ async def _set_libc_picolibc_newlib_compat() -> None:
|
||||
)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _reconcile_network_sdkconfig() -> None:
|
||||
"""Reconcile WiFi/Ethernet/Bluetooth/coexistence sdkconfig flags.
|
||||
|
||||
Single decision point for flags that multiple components used to set
|
||||
directly (and sometimes with conflicting values). Runs at FINAL priority so
|
||||
every request_*() call (made from the various components' to_code at their
|
||||
own priorities) is seen first. A user-supplied sdkconfig_options value
|
||||
always takes precedence.
|
||||
"""
|
||||
net = CORE.data[KEY_ESP32].get(KEY_NETWORK_SDKCONFIG, NetworkSdkconfigData())
|
||||
opts = CORE.data[KEY_ESP32][KEY_SDKCONFIG_OPTIONS]
|
||||
is_arduino = CORE.using_arduino
|
||||
|
||||
def set_opt(name: str, value: SdkconfigValueType) -> None:
|
||||
# User sdkconfig_options (applied during to_code) win.
|
||||
if name not in opts:
|
||||
add_idf_sdkconfig_option(name, value)
|
||||
|
||||
# Bluetooth: only ever enable when requested. The IDF default is off and
|
||||
# nothing sets these False today, so never write False here.
|
||||
if net.bluetooth:
|
||||
set_opt("CONFIG_BT_ENABLED", True)
|
||||
if net.ble_42:
|
||||
set_opt("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
|
||||
|
||||
# WiFi stack: disable only when Ethernet is present and WiFi is not. WiFi
|
||||
# relies on the IDF default (enabled), so it is never written True here.
|
||||
wifi_disabled = net.ethernet and not net.wifi
|
||||
if wifi_disabled:
|
||||
set_opt("CONFIG_ESP_WIFI_ENABLED", False)
|
||||
|
||||
# Software coexistence: enable when requested (the schema only allows it
|
||||
# alongside WiFi). Disable only in the Ethernet-without-WiFi case.
|
||||
if net.software_coexistence:
|
||||
set_opt("CONFIG_SW_COEXIST_ENABLE", True)
|
||||
elif wifi_disabled:
|
||||
set_opt("CONFIG_SW_COEXIST_ENABLE", False)
|
||||
|
||||
# SoftAP support: drop it when WiFi is used without AP mode (IDF only).
|
||||
if not is_arduino and net.wifi and not net.wifi_ap:
|
||||
set_opt("CONFIG_ESP_WIFI_SOFTAP_SUPPORT", False)
|
||||
|
||||
# LWIP DHCP server: a WiFi-AP-mode / enable_lwip_dhcp_server concern (not
|
||||
# coexistence). Disable when WiFi has no AP (IDF) or the enable_lwip_dhcp_server
|
||||
# option is set to false, unless Arduino+Ethernet needs the symbols to compile.
|
||||
wifi_wants_dhcps_off = not is_arduino and net.wifi and not net.wifi_ap
|
||||
dhcp_server_disabled_by_option = net.enable_lwip_dhcp_server is False
|
||||
arduino_eth_exclusion = is_arduino and net.ethernet
|
||||
if (
|
||||
wifi_wants_dhcps_off or dhcp_server_disabled_by_option
|
||||
) and not arduino_eth_exclusion:
|
||||
set_opt("CONFIG_LWIP_DHCPS", False)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.FINAL)
|
||||
async def _add_yaml_idf_components(components: list[ConfigType]):
|
||||
"""Add IDF components from YAML config with final priority to override code-added components."""
|
||||
@@ -2171,14 +2280,12 @@ async def to_code(config):
|
||||
for component_name in advanced.get(CONF_INCLUDE_BUILTIN_IDF_COMPONENTS, []):
|
||||
include_builtin_idf_component(component_name)
|
||||
|
||||
# DHCP server: only disable if explicitly set to false
|
||||
# WiFi component handles its own optimization when AP mode is not used
|
||||
# When using Arduino with Ethernet, DHCP server functions must be available
|
||||
# for the Network library to compile, even if not actively used
|
||||
if advanced.get(CONF_ENABLE_LWIP_DHCP_SERVER) is False and not (
|
||||
conf[CONF_TYPE] == FRAMEWORK_ARDUINO and "ethernet" in CORE.loaded_integrations
|
||||
):
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
|
||||
# DHCP server (CONFIG_LWIP_DHCPS) is reconciled in _reconcile_network_sdkconfig
|
||||
# together with the WiFi component's own AP-mode optimization; record the user's
|
||||
# advanced tristate (True/False/None) for it to consume at FINAL priority.
|
||||
_network_sdkconfig().enable_lwip_dhcp_server = advanced.get(
|
||||
CONF_ENABLE_LWIP_DHCP_SERVER
|
||||
)
|
||||
if not advanced[CONF_ENABLE_LWIP_MDNS_QUERIES]:
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES", False)
|
||||
if not advanced[CONF_ENABLE_LWIP_BRIDGE_INTERFACE]:
|
||||
@@ -2397,6 +2504,9 @@ async def to_code(config):
|
||||
# FINAL priority: runs after every require_libc_picolibc_newlib_compat() call
|
||||
CORE.add_job(_set_libc_picolibc_newlib_compat)
|
||||
|
||||
# FINAL priority: runs after every network/coexistence request_*() call
|
||||
CORE.add_job(_reconcile_network_sdkconfig)
|
||||
|
||||
# Disable regi2c control functions in IRAM
|
||||
# Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled
|
||||
if advanced[CONF_DISABLE_REGI2C_IN_IRAM]:
|
||||
|
||||
@@ -16,6 +16,7 @@ KEY_SUBMODULES = "submodules"
|
||||
KEY_EXTRA_BUILD_FILES = "extra_build_files"
|
||||
KEY_FULL_CERT_BUNDLE = "full_cert_bundle"
|
||||
KEY_IDF_VERSION = "idf_version"
|
||||
KEY_NETWORK_SDKCONFIG = "network_sdkconfig"
|
||||
|
||||
VARIANT_ESP32 = "ESP32"
|
||||
VARIANT_ESP32C2 = "ESP32C2"
|
||||
|
||||
@@ -8,7 +8,12 @@ from typing import Any
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const import CONF_USE_PSRAM
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
||||
from esphome.components.esp32 import (
|
||||
add_idf_sdkconfig_option,
|
||||
const,
|
||||
get_esp32_variant,
|
||||
request_bluetooth,
|
||||
)
|
||||
from esphome.components.esp32.const import VARIANT_ESP32C2
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -599,8 +604,7 @@ async def to_code(config):
|
||||
max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
|
||||
cg.add_define("USE_ESP32_BLE_MAX_CONNECTIONS", max_connections)
|
||||
|
||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
|
||||
request_bluetooth(ble_42=True)
|
||||
|
||||
# When PSRAM and BT are used together, Bluedroid should prefer SPIRAM for
|
||||
# heap allocations and use dynamic (heap-based) environment memory tables
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_ble
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||
from esphome.components.esp32 import request_bluetooth
|
||||
from esphome.components.esp32_ble import CONF_BLE_ID
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_TX_POWER, CONF_TYPE, CONF_UUID
|
||||
@@ -86,5 +86,4 @@ async def to_code(config):
|
||||
|
||||
cg.add_define("USE_ESP32_BLE_ADVERTISING")
|
||||
|
||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
|
||||
request_bluetooth(ble_42=True)
|
||||
|
||||
@@ -3,7 +3,7 @@ import encodings
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_ble
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||
from esphome.components.esp32 import request_bluetooth
|
||||
from esphome.components.esp32_ble import BTLoggers, bt_uuid
|
||||
import esphome.config_validation as cv
|
||||
from esphome.config_validation import UNDEFINED
|
||||
@@ -632,7 +632,7 @@ async def to_code(config):
|
||||
)
|
||||
cg.add_define("USE_ESP32_BLE_SERVER")
|
||||
cg.add_define("USE_ESP32_BLE_ADVERTISING")
|
||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||
request_bluetooth()
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
|
||||
@@ -6,7 +6,11 @@ import logging
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import esp32_ble, ota
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option
|
||||
from esphome.components.esp32 import (
|
||||
add_idf_sdkconfig_option,
|
||||
request_bluetooth,
|
||||
request_software_coexistence,
|
||||
)
|
||||
from esphome.components.esp32_ble import (
|
||||
IDF_MAX_CONNECTIONS,
|
||||
BTLoggers,
|
||||
@@ -315,9 +319,9 @@ async def to_code(config):
|
||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||
await automation.build_automation(trigger, [], conf)
|
||||
|
||||
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
||||
request_bluetooth()
|
||||
if config.get(CONF_SOFTWARE_COEXISTENCE):
|
||||
add_idf_sdkconfig_option("CONFIG_SW_COEXIST_ENABLE", True)
|
||||
request_software_coexistence()
|
||||
# https://github.com/espressif/esp-idf/issues/4101
|
||||
# https://github.com/espressif/esp-idf/issues/2503
|
||||
# Match arduino CONFIG_BTU_TASK_STACK_SIZE
|
||||
|
||||
@@ -540,6 +540,7 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
add_idf_sdkconfig_option,
|
||||
idf_version,
|
||||
include_builtin_idf_component,
|
||||
request_ethernet,
|
||||
)
|
||||
|
||||
if config[CONF_TYPE] in SPI_ETHERNET_TYPES:
|
||||
@@ -586,10 +587,9 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
|
||||
)
|
||||
cg.add(var.add_phy_register(reg))
|
||||
|
||||
# Disable WiFi when using Ethernet to save memory
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_ENABLED", False)
|
||||
# Also disable WiFi/BT coexistence since WiFi is disabled
|
||||
add_idf_sdkconfig_option("CONFIG_SW_COEXIST_ENABLE", False)
|
||||
# Register Ethernet with the esp32 sdkconfig reconciler, which disables the
|
||||
# WiFi stack and WiFi/BT coexistence when Ethernet is used without WiFi.
|
||||
request_ethernet()
|
||||
|
||||
# Re-enable ESP-IDF's Ethernet driver (excluded by default to save compile time)
|
||||
include_builtin_idf_component("esp_eth")
|
||||
|
||||
@@ -10,6 +10,7 @@ from esphome.components.esp32 import (
|
||||
const,
|
||||
get_esp32_variant,
|
||||
only_on_variant,
|
||||
request_wifi,
|
||||
)
|
||||
from esphome.components.network import (
|
||||
has_high_performance_networking,
|
||||
@@ -594,9 +595,11 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_ap_timeout(conf[CONF_AP_TIMEOUT]))
|
||||
cg.add_define("USE_WIFI_AP")
|
||||
elif CORE.is_esp32 and not CORE.using_arduino:
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_SOFTAP_SUPPORT", False)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
|
||||
|
||||
# ESP32: register the WiFi stack with the esp32 sdkconfig reconciler, which
|
||||
# drops SoftAP support / the LWIP DHCP server when AP mode is unused.
|
||||
if CORE.is_esp32:
|
||||
request_wifi(ap=CONF_AP in config)
|
||||
|
||||
# Disable Enterprise WiFi support if no EAP is configured
|
||||
if CORE.is_esp32:
|
||||
|
||||
@@ -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