1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-28 13:43:54 +00:00

Merge branch 'ethernet_pin_validate' into integration

This commit is contained in:
J. Nick Koston
2025-10-22 16:14:41 -10:00

View File

@@ -60,7 +60,7 @@ DEPENDENCIES = ["esp32"]
AUTO_LOAD = ["network"] AUTO_LOAD = ["network"]
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
# RMII pins that are hardcoded on ESP32 and cannot be changed # RMII pins that are hardcoded on ESP32 classic and cannot be changed
# These pins are used by the internal Ethernet MAC when using RMII PHYs # These pins are used by the internal Ethernet MAC when using RMII PHYs
ESP32_RMII_FIXED_PINS = { ESP32_RMII_FIXED_PINS = {
19: "EMAC_TXD0", 19: "EMAC_TXD0",
@@ -71,6 +71,18 @@ ESP32_RMII_FIXED_PINS = {
27: "EMAC_RX_CRS_DV", 27: "EMAC_RX_CRS_DV",
} }
# RMII default pins for ESP32-P4
# These are the default pins used by ESP-IDF and are configurable in principle,
# but ESPHome's ethernet component currently has no way to change them
ESP32P4_RMII_DEFAULT_PINS = {
34: "EMAC_TXD0",
35: "EMAC_TXD1",
28: "EMAC_RX_CRS_DV",
29: "EMAC_RXD0",
30: "EMAC_RXD1",
49: "EMAC_TX_EN",
}
ethernet_ns = cg.esphome_ns.namespace("ethernet") ethernet_ns = cg.esphome_ns.namespace("ethernet")
PHYRegister = ethernet_ns.struct("PHYRegister") PHYRegister = ethernet_ns.struct("PHYRegister")
CONF_PHY_ADDR = "phy_addr" CONF_PHY_ADDR = "phy_addr"
@@ -286,7 +298,7 @@ CONFIG_SCHEMA = cv.All(
) )
def _final_validate(config): def _final_validate_spi(config):
if config[CONF_TYPE] not in SPI_ETHERNET_TYPES: if config[CONF_TYPE] not in SPI_ETHERNET_TYPES:
return return
if spi_configs := fv.full_config.get().get(CONF_SPI): if spi_configs := fv.full_config.get().get(CONF_SPI):
@@ -305,9 +317,6 @@ def _final_validate(config):
) )
FINAL_VALIDATE_SCHEMA = _final_validate
def manual_ip(config): def manual_ip(config):
return cg.StructInitializer( return cg.StructInitializer(
ManualIP, ManualIP,
@@ -405,28 +414,46 @@ def _final_validate_rmii_pins(config: ConfigType) -> None:
return # SPI and OPENETH don't use RMII return # SPI and OPENETH don't use RMII
variant = get_esp32_variant() variant = get_esp32_variant()
if variant not in (VARIANT_ESP32, VARIANT_ESP32P4): if variant == VARIANT_ESP32:
return # Only ESP32 classic and P4 have RMII rmii_pins = ESP32_RMII_FIXED_PINS
is_configurable = False
elif variant == VARIANT_ESP32P4:
rmii_pins = ESP32P4_RMII_DEFAULT_PINS
is_configurable = True
else:
return # No RMII validation needed for other variants
# Check all used pins against RMII reserved pins # Check all used pins against RMII reserved pins
for pin_list in pins.PIN_SCHEMA_REGISTRY.pins_used.values(): for pin_list in pins.PIN_SCHEMA_REGISTRY.pins_used.values():
for pin_path, _, pin_config in pin_list: for pin_path, _, pin_config in pin_list:
pin_num = pin_config.get(CONF_NUMBER) pin_num = pin_config.get(CONF_NUMBER)
if pin_num not in ESP32_RMII_FIXED_PINS: if pin_num not in rmii_pins:
continue continue
# Found a conflict - show helpful error message # Found a conflict - show helpful error message
pin_function = ESP32_RMII_FIXED_PINS[pin_num] pin_function = rmii_pins[pin_num]
component_path = ".".join(str(p) for p in pin_path) component_path = ".".join(str(p) for p in pin_path)
raise cv.Invalid( if is_configurable:
f"GPIO{pin_num} is reserved for Ethernet RMII ({pin_function}) and cannot be used. " error_msg = (
f"This pin is hardcoded by ESP-IDF and cannot be changed when using RMII Ethernet PHYs. " f"GPIO{pin_num} is used by Ethernet RMII "
f"Please choose a different GPIO pin for '{component_path}'.", f"({pin_function}) with the current default "
path=pin_path, f"configuration. This conflicts with '{component_path}'. "
) f"Please choose a different GPIO pin for "
f"'{component_path}'."
)
else:
error_msg = (
f"GPIO{pin_num} is reserved for Ethernet RMII "
f"({pin_function}) and cannot be used. This pin is "
f"hardcoded by ESP-IDF and cannot be changed when using "
f"RMII Ethernet PHYs. Please choose a different GPIO pin "
f"for '{component_path}'."
)
raise cv.Invalid(error_msg, path=pin_path)
def _final_validate(config: ConfigType) -> ConfigType: def _final_validate(config: ConfigType) -> ConfigType:
"""Final validation for Ethernet component.""" """Final validation for Ethernet component."""
_final_validate_spi(config)
_final_validate_rmii_pins(config) _final_validate_rmii_pins(config)
return config return config