Merge branch 'esp32-proxy-flip' into gatt-consumer-support

This commit is contained in:
J. Nick Koston
2026-08-09 01:01:25 -05:00
3 changed files with 25 additions and 23 deletions
@@ -117,31 +117,31 @@ _PLATFORM_BACKENDS: dict[str, _PlatformBackend] = {
GATT_CLIENT_PLATFORMS = list(_PLATFORM_BACKENDS)
def _backend_entry() -> _PlatformBackend:
if (entry := _PLATFORM_BACKENDS.get(CORE.target_platform)) is None:
raise cv.Invalid(
f"no GATT client backend is registered for {CORE.target_platform}"
)
def _backend_entry(platform: str | None = None) -> _PlatformBackend:
key = platform if platform is not None else CORE.target_platform
if (entry := _PLATFORM_BACKENDS.get(key)) is None:
raise cv.Invalid(f"no GATT client backend is registered for {key}")
return entry
def gatt_client_schema() -> cv.Schema:
def gatt_client_schema(platform: str | None = None) -> cv.Schema:
"""Schema fragment for one GATT backend instance: its generated id plus
the platform-stack reference new_gatt_backend() resolves. Platform
dispatch happens at call time, so call this from inside a validator or a
per-platform schema builder, never at module import.
the platform-stack reference new_gatt_backend() resolves.
Defaults to the platform being validated; pass `platform` explicitly when
building a schema outside validation (the language-schema dumper calls
per-platform builders under arbitrary CORE platforms).
"""
entry = _backend_entry()
entry = _backend_entry(platform)
return entry.schema_fragment().extend(
{cv.GenerateID(CONF_BACKEND_ID): cv.declare_id(entry.backend_class)}
)
def hub_connection_schema() -> cv.Schema:
def hub_connection_schema(platform: str | None = None) -> cv.Schema:
"""Per-slot schema for the proxy's connection wrappers: the wrapper id on
top of the backend fragment. Same call-time constraint as
gatt_client_schema()."""
return gatt_client_schema().extend(
top of the backend fragment. Same platform rules as gatt_client_schema()."""
return gatt_client_schema(platform).extend(
{cv.GenerateID(): cv.declare_id(HubBluetoothConnection)}
)
@@ -4,7 +4,13 @@ import logging
import esphome.codegen as cg
from esphome.components import ble_device_base, bluetooth_connection
import esphome.config_validation as cv
from esphome.const import CONF_ACTIVE, CONF_ID, PLATFORM_LN882X, PLATFORM_RP2
from esphome.const import (
CONF_ACTIVE,
CONF_ID,
PLATFORM_ESP32,
PLATFORM_LN882X,
PLATFORM_RP2,
)
from esphome.core import CORE
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
from esphome.types import ConfigType
@@ -84,7 +90,7 @@ def _esp32_config_schema() -> cv.All:
f"update _IDF_MAX_CONNECTIONS in bluetooth_proxy/__init__.py"
)
CONNECTION_SCHEMA = bluetooth_connection.hub_connection_schema()
CONNECTION_SCHEMA = bluetooth_connection.hub_connection_schema(PLATFORM_ESP32)
def validate_connections(config):
if CONF_CONNECTIONS in config:
@@ -147,7 +153,7 @@ def _rp2_config_schema() -> cv.All:
"""Full proxy on the rp2 BLE hub: active connections through the BTstack
GATT client backend in bluetooth_connection. The slot limit comes from the
prebuilt BTstack library (one connection today); the code is built for N."""
connection_schema = bluetooth_connection.hub_connection_schema()
connection_schema = bluetooth_connection.hub_connection_schema(PLATFORM_RP2)
def populate_connections(config: ConfigType) -> ConfigType:
# One wrapper + backend pair per slot, declared during validation so
@@ -14,15 +14,11 @@ import voluptuous as vol
from esphome import config_validation as cv
from esphome.components.bluetooth_proxy import CONFIG_SCHEMA, _esp32_config_schema
from esphome.const import KEY_CORE, KEY_TARGET_PLATFORM, PLATFORM_ESP32
from esphome.core import CORE
def _esp32_schema_keys() -> dict[str, object]:
# The builder resolves the backend schema through the platform-dispatched
# bluetooth_connection.gatt_client_schema(), so the platform must be set
# (conftest's autouse reset restores CORE after each test).
CORE.data.setdefault(KEY_CORE, {})[KEY_TARGET_PLATFORM] = PLATFORM_ESP32
# The builder names its platform explicitly, so no CORE state is needed
# (this also mirrors how the language-schema dumper calls it).
return _keys(_schema_of(_esp32_config_schema()))