mirror of
https://github.com/esphome/esphome.git
synced 2026-05-10 05:37:55 +08:00
[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:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user