[wifi] Defer esp_wifi_init() to lazy-init so enable_on_boot: false actually saves RAM (#16606)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Keith Burzinski
2026-06-01 14:18:29 -05:00
committed by GitHub
parent 805aa252d5
commit 4e48682468
4 changed files with 54 additions and 3 deletions

View File

@@ -632,6 +632,9 @@ void WiFiComponent::setup() {
#endif
if (this->enable_on_boot_) {
#ifdef USE_ESP32
this->wifi_lazy_init_();
#endif
this->start();
} else {
this->state_ = WIFI_COMPONENT_STATE_DISABLED;
@@ -1275,6 +1278,11 @@ void WiFiComponent::enable() {
ESP_LOGD(TAG, "Enabling");
this->state_ = WIFI_COMPONENT_STATE_OFF;
#ifdef USE_ESP32
// Idempotent — only allocates DMA buffers + netifs on the first call. After this,
// start() can safely run.
this->wifi_lazy_init_();
#endif
this->start();
}

View File

@@ -694,6 +694,12 @@ class WiFiComponent final : public Component {
bool wifi_apply_hostname_();
bool wifi_sta_connect_(const WiFiAP &ap);
void wifi_pre_setup_();
#ifdef USE_ESP32
// ESP-IDF only: defers esp_wifi_init() + netif creation (which allocate ~15-30KB of
// DMA-capable internal SRAM) until wifi actually needs to come up. Idempotent.
// Called from setup() only when enable_on_boot_=true, and from enable() on first use.
void wifi_lazy_init_();
#endif
WiFiSTAConnectStatus wifi_sta_connect_status_() const;
bool is_connected_() const {
return this->state_ == WIFI_COMPONENT_STATE_STA_CONNECTED &&
@@ -889,6 +895,12 @@ class WiFiComponent final : public Component {
bool rrm_{false};
#endif
bool enable_on_boot_{true};
#ifdef USE_ESP32
// Tracks whether esp_wifi_init() + netif creation has happened. Allows enable()
// to be called at runtime without re-allocating, and ensures the heavy init is
// skipped entirely when enable_on_boot_ is false until first enable().
bool wifi_initialized_{false};
#endif
bool got_ipv4_address_{false};
bool keep_scan_results_{false};
bool has_completed_scan_after_captive_portal_start_{

View File

@@ -163,11 +163,26 @@ void WiFiComponent::wifi_pre_setup_() {
ESP_LOGE(TAG, "esp_event_handler_instance_register failed: %s", esp_err_to_name(err));
return;
}
// NOTE: netif creation + esp_wifi_init() used to live here. They allocate ~15-30KB of
// DMA-capable internal SRAM, which competes with W5500 SPI DMA and I2S DMA on
// memory-tight devices. They are now deferred to wifi_lazy_init_(), called from
// setup() when enable_on_boot_ is true, or from enable() on first runtime enable.
// This makes enable_on_boot:false genuinely skip the wifi DMA allocation.
}
s_sta_netif = esp_netif_create_default_wifi_sta();
void WiFiComponent::wifi_lazy_init_() {
if (this->wifi_initialized_)
return;
// Guard each creation so partial init (e.g. a failed esp_wifi_init() below)
// followed by a retry via enable() does not leak the existing netif handle
// nor re-register the default WiFi handlers.
if (s_sta_netif == nullptr)
s_sta_netif = esp_netif_create_default_wifi_sta();
#ifdef USE_WIFI_AP
s_ap_netif = esp_netif_create_default_wifi_ap();
if (s_ap_netif == nullptr)
s_ap_netif = esp_netif_create_default_wifi_ap();
#endif // USE_WIFI_AP
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
@@ -175,7 +190,7 @@ void WiFiComponent::wifi_pre_setup_() {
ESP_LOGW(TAG, "starting wifi without nvs");
cfg.nvs_enable = false;
}
err = esp_wifi_init(&cfg);
esp_err_t err = esp_wifi_init(&cfg);
if (err != ERR_OK) {
ESP_LOGE(TAG, "esp_wifi_init failed: %s", esp_err_to_name(err));
return;
@@ -185,6 +200,7 @@ void WiFiComponent::wifi_pre_setup_() {
ESP_LOGE(TAG, "esp_wifi_set_storage failed: %s", esp_err_to_name(err));
return;
}
this->wifi_initialized_ = true;
}
bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {

View File

@@ -0,0 +1,15 @@
wifi:
ssid: MySSID
password: password1
enable_on_boot: false
esphome:
on_boot:
priority: 200
then:
- if:
condition:
not:
wifi.enabled:
then:
- wifi.enable: