[wifi] Reject WiFi config on RP2040/RP2350 boards without CYW43 chip (#14990)

This commit is contained in:
J. Nick Koston
2026-03-19 18:40:33 -10:00
committed by GitHub
parent 6e87f8eb4e
commit 02ada93ea5
5 changed files with 84 additions and 5 deletions

View File

@@ -24,6 +24,7 @@ from esphome.const import (
from esphome.core import CORE, CoroPriority, EsphomeError, coroutine_with_priority
from esphome.helpers import copy_file_if_changed, read_file, write_file_if_changed
from . import boards
from .const import KEY_BOARD, KEY_PIO_FILES, KEY_RP2040, rp2040_ns
# force import gpio to register pin schema
@@ -35,6 +36,23 @@ AUTO_LOAD = ["preferences"]
IS_TARGET_PLATFORM = True
def get_board() -> str:
"""Return the configured board name."""
return CORE.data[KEY_RP2040][KEY_BOARD]
def board_has_wifi() -> bool:
"""Return True if the configured board has WiFi (CYW43 wireless chip).
Returns True for unknown/custom boards to avoid rejecting valid
configurations for boards not in the generated list.
"""
board_info = boards.BOARDS.get(get_board())
if board_info is None:
return True
return board_info.get("wifi", False)
def set_core_data(config):
CORE.data[KEY_RP2040] = {}
CORE.data[KEY_CORE][KEY_TARGET_PLATFORM] = PLATFORM_RP2040

View File

@@ -1910,6 +1910,7 @@ BOARDS = {
"name": "Pimoroni PicoPlus2W",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
"max_virtual_pin": 64,
},
"pimoroni_plasma2040": {
@@ -1926,6 +1927,7 @@ BOARDS = {
"name": "Pimoroni Plasma2350W",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
},
"pimoroni_servo2040": {
"name": "Pimoroni Servo2040",
@@ -1976,12 +1978,14 @@ BOARDS = {
"name": "Raspberry Pi Pico 2W",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
"max_virtual_pin": 64,
},
"rpipicow": {
"name": "Raspberry Pi Pico W",
"mcu": "rp2040",
"max_pin": 29,
"wifi": True,
"max_virtual_pin": 64,
},
"sea_picro": {
@@ -2013,6 +2017,7 @@ BOARDS = {
"name": "Soldered Electronics NULA RP2350",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
},
"solderparty_rp2040_stamp": {
"name": "Solder Party RP2040 Stamp",
@@ -2038,6 +2043,7 @@ BOARDS = {
"name": "SparkFun IoT RedBoard RP2350",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
},
"sparkfun_micromodrp2040": {
"name": "SparkFun MicroMod RP2040",
@@ -2063,18 +2069,21 @@ BOARDS = {
"name": "SparkFun Thing Plus RP2350",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
"max_virtual_pin": 64,
},
"sparkfun_xrp_controller": {
"name": "SparkFun XRP Controller",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
"max_virtual_pin": 64,
},
"sparkfun_xrp_controller_beta": {
"name": "SparkFun XRP Controller (Beta)",
"mcu": "rp2040",
"max_pin": 29,
"wifi": True,
"max_virtual_pin": 64,
},
"upesy_rp2040_devkit": {
@@ -2161,6 +2170,7 @@ BOARDS = {
"name": "Waveshare RP2350B Plus W",
"mcu": "rp2350",
"max_pin": 47,
"wifi": True,
},
"wiznet_5100s_evb_pico": {
"name": "WIZnet W5100S-EVB-Pico",

View File

@@ -78,11 +78,17 @@ def load_boards(arduino_pico_path: Path) -> tuple[dict, dict]:
display_name = f"{vendor} {name}".strip() if vendor else name
boards[board_name] = {
extra_flags = build.get("extra_flags", "")
has_wifi = "PICO_CYW43_SUPPORTED=1" in extra_flags
board_entry: dict = {
"name": display_name,
"mcu": mcu,
"max_pin": MCU_MAX_PIN.get(mcu, DEFAULT_MAX_PIN),
}
if has_wifi:
board_entry["wifi"] = True
boards[board_name] = board_entry
# Get pins for this variant
if variant not in variant_pins_cache:

View File

@@ -235,6 +235,14 @@ def validate_variant(_):
variant = get_esp32_variant()
if variant in NO_WIFI_VARIANTS and "esp32_hosted" not in fv.full_config.get():
raise cv.Invalid(f"WiFi requires component esp32_hosted on {variant}")
if CORE.is_rp2040:
from esphome.components.rp2040 import board_has_wifi, get_board
if not board_has_wifi():
raise cv.Invalid(
f"Board '{get_board()}' does not have WiFi support (no CYW43 wireless chip). "
f"Use a WiFi-capable board like 'rpipicow' or 'rpipico2w'."
)
def _apply_min_auth_mode_default(config):

View File

@@ -59,6 +59,7 @@ def _add_board(
vendor: str = "",
name: str | None = None,
pins_header: str | None = None,
extra_flags: str = "",
) -> None:
"""Add a board JSON and variant to the fake arduino-pico tree."""
if variant is None:
@@ -69,11 +70,15 @@ def _add_board(
json_dir = arduino_pico / "tools" / "json"
variants_dir = arduino_pico / "variants"
build: dict = {
"mcu": mcu,
"variant": variant,
}
if extra_flags:
build["extra_flags"] = extra_flags
board_json = {
"build": {
"mcu": mcu,
"variant": variant,
},
"build": build,
"name": name,
"vendor": vendor,
}
@@ -271,3 +276,35 @@ def test_placeholder_pins_not_treated_as_virtual(arduino_pico: Path) -> None:
assert "MISO" not in board_pins["badpin"]
assert boards["badpin"]["max_virtual_pin"] == 64
def test_cyw43_supported_flag_sets_wifi(arduino_pico: Path) -> None:
"""Boards with PICO_CYW43_SUPPORTED=1 in extra_flags should have wifi=True."""
_add_board(
arduino_pico,
"rpipicow",
vendor="Raspberry Pi",
name="Pico W",
pins_header=PICOW_PINS_HEADER,
extra_flags="-DARDUINO_RASPBERRY_PI_PICO_W -DPICO_CYW43_SUPPORTED=1 -DCYW43_PIN_WL_DYNAMIC=1",
)
_, boards = load_boards(arduino_pico)
assert boards["rpipicow"]["wifi"] is True
def test_board_without_cyw43_has_no_wifi(arduino_pico: Path) -> None:
"""Boards without PICO_CYW43_SUPPORTED should not have wifi field."""
_add_board(
arduino_pico,
"rpipico",
vendor="Raspberry Pi",
name="Pico",
pins_header=PICO_PINS_HEADER,
extra_flags="-DARDUINO_RASPBERRY_PI_PICO",
)
_, boards = load_boards(arduino_pico)
assert "wifi" not in boards["rpipico"]