[ethernet] Add interface configuration variable for esp-idf (#10285)

Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Ross Tyler
2026-04-05 13:57:41 -07:00
committed by GitHub
parent ae9068a4c4
commit c7a163441e
4 changed files with 70 additions and 30 deletions
+38 -23
View File
@@ -104,6 +104,8 @@ CONF_CLK_MODE = "clk_mode"
CONF_POWER_PIN = "power_pin"
CONF_PHY_REGISTERS = "phy_registers"
CONF_INTERFACE = "interface"
CONF_CLOCK_SPEED = "clock_speed"
EthernetType = ethernet_ns.enum("EthernetType")
@@ -191,6 +193,13 @@ CLK_MODES_DEPRECATED = {
"GPIO17_OUT": ("CLK_OUT", 17),
}
spi_host_device_t = cg.global_ns.enum("spi_host_device_t")
SPI_INTERFACE_MAP = {
"spi2": spi_host_device_t.SPI2_HOST,
"spi3": spi_host_device_t.SPI3_HOST,
}
MANUAL_IP_SCHEMA = cv.Schema(
{
cv.Required(CONF_STATIC_IP): cv.ipv4address,
@@ -225,6 +234,24 @@ def _is_framework_spi_polling_mode_supported() -> bool:
return False
def _validate_spi_interface(config: ConfigType) -> ConfigType:
"""Set default SPI interface or validate user choice against the variant."""
if not CORE.is_esp32:
return config
from esphome.components.esp32 import VARIANT_ESP32, get_esp32_variant
from esphome.components.spi import get_hw_interface_list
has_spi3 = "spi3" in sum(get_hw_interface_list(), [])
if CONF_INTERFACE not in config:
# Only classic ESP32 defaults to spi3; all others default to spi2
config[CONF_INTERFACE] = (
"spi3" if get_esp32_variant() == VARIANT_ESP32 else "spi2"
)
elif config[CONF_INTERFACE] == "spi3" and not has_spi3:
raise cv.Invalid("Interface 'spi3' is not available on this variant.")
return config
def _validate(config):
if CONF_USE_ADDRESS not in config:
if CONF_MANUAL_IP in config:
@@ -368,6 +395,10 @@ SPI_SCHEMA = cv.All(
cv.frequency,
cv.int_range(int(8e6), int(80e6)),
),
cv.Optional(CONF_INTERFACE): cv.All(
cv.only_on_esp32,
cv.one_of(*SPI_INTERFACE_MAP.keys(), lower=True),
),
# Set default value (SPI_ETHERNET_DEFAULT_POLLING_INTERVAL) at _validate()
cv.Optional(CONF_POLLING_INTERVAL): cv.All(
cv.only_on_esp32,
@@ -378,6 +409,7 @@ SPI_SCHEMA = cv.All(
),
),
cv.only_on([Platform.ESP32, Platform.RP2040]),
_validate_spi_interface,
)
CONFIG_SCHEMA = cv.All(
@@ -408,37 +440,18 @@ def _final_validate_spi(config):
return # SPI interface validation is ESP32-only
if config[CONF_TYPE] not in SPI_ETHERNET_TYPES:
return
from esphome.components.esp32 import (
VARIANT_ESP32C3,
VARIANT_ESP32C5,
VARIANT_ESP32C6,
VARIANT_ESP32C61,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
get_esp32_variant,
)
from esphome.components.spi import CONF_INTERFACE_INDEX, get_spi_interface
if spi_configs := fv.full_config.get().get(CONF_SPI):
variant = get_esp32_variant()
if variant in (
VARIANT_ESP32C3,
VARIANT_ESP32C5,
VARIANT_ESP32C6,
VARIANT_ESP32C61,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
):
spi_host = "SPI2_HOST"
else:
spi_host = "SPI3_HOST"
# get_spi_interface() returns strings like "SPI2_HOST"
spi_host = f"{config[CONF_INTERFACE].upper()}_HOST"
for spi_conf in spi_configs:
if (index := spi_conf.get(CONF_INTERFACE_INDEX)) is not None:
interface = get_spi_interface(index)
if interface == spi_host:
raise cv.Invalid(
f"`spi` component is using interface '{interface}'. "
f"To use {config[CONF_TYPE]}, you must change the `interface` on the `spi` component.",
f"The `ethernet` and `spi` components are both using interface '{interface}'. "
f"To use {config[CONF_TYPE]}, change the `interface` on either `ethernet:` or `spi:`."
)
@@ -528,6 +541,8 @@ async def _to_code_esp32(var: cg.Pvariable, config: ConfigType) -> None:
cg.add(var.set_clock_speed(config[CONF_CLOCK_SPEED]))
cg.add_define("USE_ETHERNET_SPI")
cg.add(var.set_interface(SPI_INTERFACE_MAP[config[CONF_INTERFACE]]))
add_idf_sdkconfig_option("CONFIG_ETH_USE_SPI_ETHERNET", True)
# CONFIG_ETH_SPI_ETHERNET_{TYPE} Kconfig options were removed in IDF 6.0
# ENC28J60 was never built-in to IDF, so it has no Kconfig option
@@ -11,6 +11,9 @@
#ifdef USE_ESP32
#include "esp_eth.h"
#ifdef USE_ETHERNET_SPI
#include "hal/spi_types.h"
#endif
#include "esp_eth_mac.h"
#include "esp_eth_mac_esp.h"
#include "esp_netif.h"
@@ -135,6 +138,7 @@ class EthernetComponent final : public Component {
void set_interrupt_pin(uint8_t interrupt_pin);
void set_reset_pin(uint8_t reset_pin);
void set_clock_speed(int clock_speed);
void set_interface(spi_host_device_t interface);
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
void set_polling_interval(uint32_t polling_interval);
#endif
@@ -201,6 +205,7 @@ class EthernetComponent final : public Component {
int reset_pin_{-1};
int phy_addr_spi_{-1};
int clock_speed_;
spi_host_device_t interface_{SPI3_HOST};
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
uint32_t polling_interval_{0};
#endif
@@ -158,12 +158,7 @@ void EthernetComponent::setup() {
.intr_flags = 0,
};
#if defined(USE_ESP32_VARIANT_ESP32C3) || defined(USE_ESP32_VARIANT_ESP32C5) || defined(USE_ESP32_VARIANT_ESP32C6) || \
defined(USE_ESP32_VARIANT_ESP32C61) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
auto host = SPI2_HOST;
#else
auto host = SPI3_HOST;
#endif
auto host = this->interface_;
err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
ESPHL_ERROR_CHECK(err, "SPI bus initialize error");
@@ -458,6 +453,11 @@ void EthernetComponent::dump_config() {
" MOSI Pin: %u\n"
" CS Pin: %u",
this->clk_pin_, this->miso_pin_, this->mosi_pin_, this->cs_pin_);
const char *spi_interface = "spi3";
if (this->interface_ == SPI2_HOST) {
spi_interface = "spi2";
}
ESP_LOGCONFIG(TAG, " Interface: %s", spi_interface);
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
if (this->polling_interval_ != 0) {
ESP_LOGCONFIG(TAG, " Polling Interval: %" PRIu32 " ms", this->polling_interval_);
@@ -760,6 +760,7 @@ void EthernetComponent::set_cs_pin(uint8_t cs_pin) { this->cs_pin_ = cs_pin; }
void EthernetComponent::set_interrupt_pin(uint8_t interrupt_pin) { this->interrupt_pin_ = interrupt_pin; }
void EthernetComponent::set_reset_pin(uint8_t reset_pin) { this->reset_pin_ = reset_pin; }
void EthernetComponent::set_clock_speed(int clock_speed) { this->clock_speed_ = clock_speed; }
void EthernetComponent::set_interface(spi_host_device_t interface) { this->interface_ = interface; }
#ifdef USE_ETHERNET_SPI_POLLING_SUPPORT
void EthernetComponent::set_polling_interval(uint32_t polling_interval) { this->polling_interval_ = polling_interval; }
#endif
@@ -1 +1,20 @@
<<: !include common-w5500.yaml
ethernet:
type: W5500
clk_pin: 19
mosi_pin: 21
miso_pin: 23
cs_pin: 18
interrupt_pin: 36
reset_pin: 22
clock_speed: 10Mhz
manual_ip:
static_ip: 192.168.178.56
gateway: 192.168.178.1
subnet: 255.255.255.0
domain: .local
mac_address: "02:AA:BB:CC:DD:01"
interface: spi2
on_connect:
- logger.log: "Ethernet connected!"
on_disconnect:
- logger.log: "Ethernet disconnected!"