[wifi/rp2040] Add stable wifi-capability helpers for device-builder

Add public helpers so the device-builder dashboard backend
(esphome/device-builder) doesn't have to import the internal
NO_WIFI_VARIANTS list / BOARDS dict to decide whether its basic-
setup wizard should emit a wifi: block:

- esphome.components.wifi.has_native_wifi(*, platform, board=None,
  variant=None) - central dispatcher that takes whichever
  platform-relevant fields the caller has and routes to the right
  per-platform check internally. As ESPHome adds new platforms
  (5-6 planned), this is the single place to teach them about
  Wi-Fi capability - external tooling does not have to grow a
  parallel per-platform switch.
- esphome.components.wifi.variant_has_wifi(variant) - building
  block for the ESP32 branch (False for H2 / P4 which require
  esp32_hosted).
- esphome.components.rp2040.board_id_has_wifi(board_id) - building
  block for the RP2040 branch (existing no-arg board_has_wifi()
  unchanged, now delegates to the new helper). New name (rather
  than overloading board_has_wifi) so device-builder can feature-
  detect ESPHome support via try/except ImportError on the new
  symbol - an older ESPHome would import board_has_wifi
  successfully but raise TypeError on the explicit-arg call,
  defeating the fallback.

All three wrap implementation-detail tables (NO_WIFI_VARIANTS,
the generated BOARDS dict) with explicit-arg signatures + tests,
so device-builder pins against a stable surface and a future
refactor of the underlying tables doesn't silently break the
wizard.

Same shape as the device-builder API stabilisation in #16206
and #16290.
This commit is contained in:
J. Nick Koston
2026-05-07 14:59:39 -05:00
parent 06bd92c388
commit d143df3c49
4 changed files with 199 additions and 3 deletions
+15 -1
View File
@@ -48,7 +48,21 @@ def board_has_wifi() -> bool:
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())
return board_id_has_wifi(get_board())
def board_id_has_wifi(board_id: str) -> bool:
"""Return True if *board_id* has WiFi (CYW43 wireless chip).
Returns True for unknown/custom boards to avoid rejecting valid
configurations for boards not in the generated list.
Used by device-builder (esphome/device-builder) — separate
explicit-arg helper so callers outside the compile pipeline
don't need ``CORE`` set up to query the board map. Please keep
the signature stable.
"""
board_info = boards.BOARDS.get(board_id)
if board_info is None:
return True
return board_info.get("wifi", False)
+59 -2
View File
@@ -67,9 +67,66 @@ _LOGGER = logging.getLogger(__name__)
AUTO_LOAD = ["network"]
_LOGGER = logging.getLogger(__name__)
NO_WIFI_VARIANTS = [const.VARIANT_ESP32H2, const.VARIANT_ESP32P4]
def variant_has_wifi(variant: str) -> bool:
"""Return True if *variant* has a native WiFi PHY.
Variants without a native PHY (ESP32-H2, ESP32-P4) need the
``esp32_hosted`` co-processor to use ``wifi:``.
Used by device-builder (esphome/device-builder) to decide whether
its basic-setup wizard emits a ``wifi:`` block — please keep the
signature stable.
"""
return variant not in NO_WIFI_VARIANTS
_WIFI_FIRST_PLATFORMS: frozenset[str] = frozenset(
{
Platform.ESP8266,
Platform.BK72XX,
Platform.RTL87XX,
Platform.LN882X,
# Legacy umbrella key for the LibreTiny families (bk72xx /
# rtl87xx / ln882x); still produced by older configs that
# haven't migrated to the per-family keys.
Platform.LIBRETINY_OLDSTYLE,
}
)
def has_native_wifi(
*, platform: str, board: str | None = None, variant: str | None = None
) -> bool:
"""Return True when the given platform/board/variant has native WiFi.
Single dispatch entry point for tooling that needs to decide
whether emitting a ``wifi:`` block produces a compilable
config. Caller passes whichever platform-relevant fields they
have (``variant`` for ESP32, ``board`` for RP2040), and this
function routes to the right per-platform check internally.
Allowlist-based: unknown / Wi-Fi-less platforms (``host``,
``nrf52``) return False so a future platform added to ESPHome
fails closed in external tooling rather than silently emitting
a ``wifi:`` block the new platform's component would reject.
Used by device-builder (esphome/device-builder)'s basic-setup
wizard. Centralised here so callers don't have to special-case
each platform — as ESPHome adds new platforms, this dispatcher
is the one place to teach them about Wi-Fi capability.
"""
if platform == Platform.ESP32:
return variant_has_wifi(variant) if variant else True
if platform == Platform.RP2040:
from esphome.components.rp2040 import board_id_has_wifi
return board_id_has_wifi(board) if board else True
return platform in _WIFI_FIRST_PLATFORMS
CONF_SAVE = "save"
CONF_BAND_MODE = "band_mode"
CONF_MIN_AUTH_MODE = "min_auth_mode"
@@ -0,0 +1,29 @@
"""Tests for RP2040 component public helpers."""
from esphome.components.rp2040 import board_id_has_wifi
def test_board_id_has_wifi_for_known_wifi_board() -> None:
"""``rpipicow`` is the canonical Pico W → True."""
assert board_id_has_wifi("rpipicow") is True
def test_board_id_has_wifi_for_known_non_wifi_board() -> None:
"""Plain ``rpipico`` has no CYW43 → False."""
assert board_id_has_wifi("rpipico") is False
def test_board_id_has_wifi_for_rp2350_w_variant() -> None:
"""``rpipico2w`` is the RP2350 Pico 2 W → True."""
assert board_id_has_wifi("rpipico2w") is True
def test_board_id_has_wifi_for_unknown_board_returns_true() -> None:
"""Unknown ids fail open so a custom board is not rejected.
The validator falls back to ESPHome's compile-time check; the
helper returning True here means the wizard emits a ``wifi:``
block and any genuinely-unsupported config trips the existing
"no CYW43" guard at compile time.
"""
assert board_id_has_wifi("not-a-real-board-id") is True
+96
View File
@@ -0,0 +1,96 @@
"""Tests for WiFi component public helpers."""
import pytest
from esphome.components.esp32 import const
from esphome.components.wifi import has_native_wifi, variant_has_wifi
from esphome.const import Platform
@pytest.mark.parametrize(
"variant",
[
const.VARIANT_ESP32,
const.VARIANT_ESP32S2,
const.VARIANT_ESP32S3,
const.VARIANT_ESP32C3,
const.VARIANT_ESP32C6,
],
)
def test_variant_has_wifi_for_native_phy_variants(variant: str) -> None:
"""Variants with a native WiFi PHY → True."""
assert variant_has_wifi(variant) is True
@pytest.mark.parametrize(
"variant",
[
const.VARIANT_ESP32H2,
const.VARIANT_ESP32P4,
],
)
def test_variant_has_wifi_for_no_phy_variants(variant: str) -> None:
"""Variants that need ``esp32_hosted`` → False."""
assert variant_has_wifi(variant) is False
def test_has_native_wifi_dispatches_esp32_to_variant_check() -> None:
"""ESP32 platform routes through ``variant_has_wifi``."""
assert (
has_native_wifi(platform=Platform.ESP32, variant=const.VARIANT_ESP32C3) is True
)
assert (
has_native_wifi(platform=Platform.ESP32, variant=const.VARIANT_ESP32H2) is False
)
def test_has_native_wifi_dispatches_rp2040_to_board_check() -> None:
"""RP2040 platform routes through ``rp2040.board_id_has_wifi``."""
assert has_native_wifi(platform=Platform.RP2040, board="rpipicow") is True
assert has_native_wifi(platform=Platform.RP2040, board="rpipico") is False
def test_has_native_wifi_returns_false_for_nrf52() -> None:
"""nRF52 family is BLE-only — no Wi-Fi PHY in the platform."""
assert has_native_wifi(platform=Platform.NRF52) is False
def test_has_native_wifi_returns_false_for_host() -> None:
"""``host`` platform compiles ESPHome to a host binary — no radio at all."""
assert has_native_wifi(platform=Platform.HOST) is False
def test_has_native_wifi_returns_false_for_unknown_platform() -> None:
"""Unknown platform string fails closed.
A future platform added to ESPHome that's missed here returns
False rather than silently emitting a ``wifi:`` block external
tooling would have to compile and reject — fail-closed surfaces
the gap as an obvious "needs wifi support added" signal.
"""
assert has_native_wifi(platform="not-a-real-platform") is False
@pytest.mark.parametrize(
"platform",
[
Platform.ESP8266,
Platform.BK72XX,
Platform.RTL87XX,
Platform.LN882X,
Platform.LIBRETINY_OLDSTYLE,
],
)
def test_has_native_wifi_returns_true_for_wifi_first_platforms(platform: str) -> None:
"""Catch-all Wi-Fi-first platforms → True regardless of board / variant."""
assert has_native_wifi(platform=platform) is True
def test_has_native_wifi_esp32_without_variant_assumes_wifi() -> None:
"""ESP32 without a variant id falls open to True (the chip family default)."""
assert has_native_wifi(platform=Platform.ESP32) is True
def test_has_native_wifi_rp2040_without_board_assumes_wifi() -> None:
"""RP2040 without a board id falls open to True (custom-board default)."""
assert has_native_wifi(platform=Platform.RP2040) is True