[espnow, ethernet, network, openthread, wifi] centralize network initialization for ESP32 (#14012)

Co-authored-by: kbx81 <kbx81x@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
This commit is contained in:
Rodrigo Martín
2026-05-24 07:27:31 +02:00
committed by GitHub
parent 5f860ff5bd
commit a37f27ee7f
9 changed files with 69 additions and 31 deletions

View File

@@ -17,7 +17,7 @@ from esphome.core import HexInt
from esphome.types import ConfigType
CODEOWNERS = ["@jesserockz"]
AUTO_LOAD = ["network"]
byte_vector = cg.std_vector.template(cg.uint8)
peer_address_t = cg.std_ns.class_("array").template(cg.uint8, 6)

View File

@@ -149,12 +149,6 @@ bool ESPNowComponent::is_wifi_enabled() {
}
void ESPNowComponent::setup() {
#ifndef USE_WIFI
// Initialize LwIP stack for wake_loop_threadsafe() socket support
// When WiFi component is present, it handles esp_netif_init()
ESP_ERROR_CHECK(esp_netif_init());
#endif
if (this->enable_on_boot_) {
this->enable_();
} else {
@@ -174,8 +168,6 @@ void ESPNowComponent::enable() {
void ESPNowComponent::enable_() {
if (!this->is_wifi_enabled()) {
esp_event_loop_create_default();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));

View File

@@ -164,11 +164,7 @@ void EthernetComponent::setup() {
err = spi_bus_initialize(host, &buscfg, SPI_DMA_CH_AUTO);
ESPHL_ERROR_CHECK(err, "SPI bus initialize error");
#endif
err = esp_netif_init();
ESPHL_ERROR_CHECK(err, "ETH netif init error");
err = esp_event_loop_create_default();
ESPHL_ERROR_CHECK(err, "ETH event loop error");
// Network interface setup handled by network component
esp_netif_config_t cfg = ESP_NETIF_DEFAULT_ETH();
this->eth_netif_ = esp_netif_new(&cfg);

View File

@@ -5,8 +5,9 @@ import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option
from esphome.components.psram import is_guaranteed as psram_is_guaranteed
import esphome.config_validation as cv
from esphome.const import CONF_ENABLE_IPV6, CONF_MIN_IPV6_ADDR_COUNT
from esphome.const import CONF_ENABLE_IPV6, CONF_ID, CONF_MIN_IPV6_ADDR_COUNT
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.types import ConfigType
CODEOWNERS = ["@esphome/core"]
AUTO_LOAD = ["mdns"]
@@ -19,6 +20,7 @@ KEY_HIGH_PERFORMANCE_NETWORKING = "high_performance_networking"
CONF_ENABLE_HIGH_PERFORMANCE = "enable_high_performance"
network_ns = cg.esphome_ns.namespace("network")
NetworkComponent = network_ns.class_("NetworkComponent", cg.Component)
IPAddress = network_ns.class_("IPAddress")
@@ -107,6 +109,7 @@ def has_high_performance_networking() -> bool:
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(NetworkComponent),
cv.SplitDefault(
CONF_ENABLE_IPV6,
bk72xx=False,
@@ -224,3 +227,15 @@ async def to_code(config):
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_LWIP2_IPV6_LOW_MEMORY")
if CORE.is_rp2040:
cg.add_build_flag("-DPIO_FRAMEWORK_ARDUINO_ENABLE_IPV6")
# Pvariable creation lives in a separate coroutine at NETWORK_SERVICES so it
# emits after wifi/ethernet at COMMUNICATION. This keeps compile-time config
# (above) separate from C++ object lifecycle and allows wiring in interface
# pointers via get_variable().
if CORE.is_esp32:
CORE.add_job(network_component_to_code, config)
@coroutine_with_priority(CoroPriority.NETWORK_SERVICES)
async def network_component_to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)

View File

@@ -0,0 +1,33 @@
#include "network_component.h"
#include "esphome/core/defines.h"
#if defined(USE_NETWORK) && defined(USE_ESP32)
#include "esphome/core/log.h"
#include "esp_err.h"
#include "esp_netif.h"
#include "esp_event.h"
namespace esphome::network {
static const char *const TAG = "network";
void NetworkComponent::setup() {
// Initialize ESP-IDF network interfaces and ensure the default event loop exists
esp_err_t err;
err = esp_netif_init();
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_netif_init failed: (%d) %s", err, esp_err_to_name(err));
this->mark_failed();
return;
}
err = esp_event_loop_create_default();
// ESP_ERR_INVALID_STATE is returned if the default loop already exists,
// which is fine since we just want to make sure it exists
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(TAG, "esp_event_loop_create_default failed: (%d) %s", err, esp_err_to_name(err));
this->mark_failed();
return;
}
}
} // namespace esphome::network
#endif

View File

@@ -0,0 +1,14 @@
#pragma once
#include "esphome/core/defines.h"
#if defined(USE_NETWORK) && defined(USE_ESP32)
#include "esphome/core/component.h"
namespace esphome::network {
class NetworkComponent : public Component {
public:
void setup() override;
// AFTER_BLUETOOTH: BLE controller must initialize before esp_netif_init per IDF guidance.
float get_setup_priority() const override { return setup_priority::AFTER_BLUETOOTH; }
};
} // namespace esphome::network
#endif

View File

@@ -35,9 +35,8 @@ void OpenThreadComponent::setup() {
esp_vfs_eventfd_config_t eventfd_config = {
.max_fds = 3,
};
// Network interface setup handled by network component
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
xTaskCreate(

View File

@@ -634,9 +634,6 @@ void WiFiComponent::setup() {
if (this->enable_on_boot_) {
this->start();
} else {
#ifdef USE_ESP32
esp_netif_init();
#endif
this->state_ = WIFI_COMPONENT_STATE_DISABLED;
}
}

View File

@@ -145,23 +145,15 @@ void WiFiComponent::wifi_pre_setup_() {
get_mac_address_raw(mac);
set_mac_address(mac);
}
esp_err_t err = esp_netif_init();
if (err != ERR_OK) {
ESP_LOGE(TAG, "esp_netif_init failed: %s", esp_err_to_name(err));
return;
}
// Network interface setup handled by network component
s_wifi_event_group = xEventGroupCreate();
if (s_wifi_event_group == nullptr) {
ESP_LOGE(TAG, "xEventGroupCreate failed");
return;
}
err = esp_event_loop_create_default();
if (err != ERR_OK) {
ESP_LOGE(TAG, "esp_event_loop_create_default failed: %s", esp_err_to_name(err));
return;
}
esp_event_handler_instance_t instance_wifi_id, instance_ip_id;
err = esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, nullptr, &instance_wifi_id);
esp_err_t err =
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, nullptr, &instance_wifi_id);
if (err != ERR_OK) {
ESP_LOGE(TAG, "esp_event_handler_instance_register failed: %s", esp_err_to_name(err));
return;