[esp32] Fix strapping pin validation for P4 and H2 (#9980)

This commit is contained in:
Clyde Stubbs 2025-08-01 09:48:25 +10:00 committed by GitHub
parent da0c47629a
commit 161f51e1f4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 48 additions and 42 deletions

View File

@ -2,6 +2,7 @@ import logging
import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin
_ESP32H2_SPI_FLASH_PINS = {6, 7, 15, 16, 17, 18, 19, 20, 21}
@ -15,13 +16,6 @@ _LOGGER = logging.getLogger(__name__)
def esp32_h2_validate_gpio_pin(value):
if value < 0 or value > 27:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-27)")
if value in _ESP32H2_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in _ESP32H2_SPI_FLASH_PINS:
_LOGGER.warning(
"GPIO%d is reserved for SPI Flash communication on some ESP32-H2 chip variants.\n"
@ -49,4 +43,5 @@ def esp32_h2_validate_supports(value):
if is_input:
# All ESP32 pins support input mode
pass
check_strapping_pin(value, _ESP32H2_STRAPPING_PINS, _LOGGER)
return value

View File

@ -2,6 +2,7 @@ import logging
import esphome.config_validation as cv
from esphome.const import CONF_INPUT, CONF_MODE, CONF_NUMBER
from esphome.pins import check_strapping_pin
_ESP32P4_USB_JTAG_PINS = {24, 25}
@ -13,13 +14,6 @@ _LOGGER = logging.getLogger(__name__)
def esp32_p4_validate_gpio_pin(value):
if value < 0 or value > 54:
raise cv.Invalid(f"Invalid pin number: {value} (must be 0-54)")
if value in _ESP32P4_STRAPPING_PINS:
_LOGGER.warning(
"GPIO%d is a Strapping PIN and should be avoided.\n"
"Attaching external pullup/down resistors to strapping pins can cause unexpected failures.\n"
"See https://esphome.io/guides/faq.html#why-am-i-getting-a-warning-about-strapping-pins",
value,
)
if value in _ESP32P4_USB_JTAG_PINS:
_LOGGER.warning(
"GPIO%d is reserved for the USB-Serial-JTAG interface.\n"
@ -40,4 +34,5 @@ def esp32_p4_validate_supports(value):
if is_input:
# All ESP32 pins support input mode
pass
check_strapping_pin(value, _ESP32P4_STRAPPING_PINS, _LOGGER)
return value

View File

@ -0,0 +1,43 @@
"""Tests for mpip_spi configuration validation."""
from collections.abc import Callable, Generator
import pytest
from esphome import config_validation as cv
from esphome.components.esp32 import KEY_ESP32, KEY_VARIANT, VARIANTS
from esphome.components.esp32.gpio import validate_gpio_pin
from esphome.const import CONF_INPUT, CONF_OUTPUT
from esphome.core import CORE
from esphome.pins import gpio_pin_schema
@pytest.fixture
def choose_variant_with_pins() -> Generator[Callable[[list], None]]:
"""
Set the ESP32 variant for the given model based on pins. For ESP32 only since the other platforms
do not have variants.
"""
def chooser(pins: list) -> None:
for v in VARIANTS:
try:
CORE.data[KEY_ESP32][KEY_VARIANT] = v
for pin in pins:
if pin is not None:
pin = gpio_pin_schema(
{
CONF_INPUT: True,
CONF_OUTPUT: True,
},
internal=True,
)(pin)
validate_gpio_pin(pin)
return
except cv.Invalid:
continue
raise cv.Invalid(
f"No compatible variant found for pins: {', '.join(map(str, pins))}"
)
yield chooser

View File

@ -9,13 +9,10 @@ import pytest
from esphome import config_validation as cv
from esphome.components.esp32 import (
KEY_BOARD,
KEY_ESP32,
KEY_VARIANT,
VARIANT_ESP32,
VARIANT_ESP32S3,
VARIANTS,
)
from esphome.components.esp32.gpio import validate_gpio_pin
from esphome.components.mipi import CONF_NATIVE_HEIGHT
from esphome.components.mipi_spi.display import (
CONF_BUS_MODE,
@ -32,8 +29,6 @@ from esphome.const import (
CONF_WIDTH,
PlatformFramework,
)
from esphome.core import CORE
from esphome.pins import internal_gpio_pin_number
from esphome.types import ConfigType
from tests.component_tests.types import SetCoreConfigCallable
@ -43,28 +38,6 @@ def run_schema_validation(config: ConfigType) -> None:
FINAL_VALIDATE_SCHEMA(CONFIG_SCHEMA(config))
@pytest.fixture
def choose_variant_with_pins() -> Callable[..., None]:
"""
Set the ESP32 variant for the given model based on pins. For ESP32 only since the other platforms
do not have variants.
"""
def chooser(*pins: int | str | None) -> None:
for v in VARIANTS:
try:
CORE.data[KEY_ESP32][KEY_VARIANT] = v
for pin in pins:
if pin is not None:
pin = internal_gpio_pin_number(pin)
validate_gpio_pin(pin)
return
except cv.Invalid:
continue
return chooser
@pytest.mark.parametrize(
("config", "error_match"),
[
@ -315,7 +288,7 @@ def test_custom_model_with_all_options(
def test_all_predefined_models(
set_core_config: SetCoreConfigCallable,
set_component_config: Callable[[str, Any], None],
choose_variant_with_pins: Callable[..., None],
choose_variant_with_pins: Callable[[list], None],
) -> None:
"""Test all predefined display models validate successfully with appropriate defaults."""
set_core_config(