Skip to content

Listener StaticVector Migration: WiFi and Logger

WiFi and Logger components now use StaticVector for listener storage, eliminating heap allocation and STL overhead. External components that register listeners must now call request functions during code generation.

This is a breaking change for external components in ESPHome 2026.1.0 and later.

What changed

Previously, listener vectors were dynamically allocated with std::vector. Now they use compile-time-sized StaticVector based on how many components request listener slots.

If the appropriate request_*_listener() is not called, add_*_listener() will silently fail - your listener will never receive callbacks.

WiFi Listeners

Four independent listener types now require separate request functions:

# In your component's __init__.py
from esphome.components import wifi

async def to_code(config):
    # Request the specific listener type(s) you need
    wifi.request_wifi_ip_state_listener()        # For IP/DNS state changes
    wifi.request_wifi_connect_state_listener()   # For SSID/BSSID changes
    wifi.request_wifi_scan_results_listener()    # For scan results
    wifi.request_wifi_power_save_listener()      # For power save mode changes

WiFi Listener C++ Registration

These use interface classes, not lambdas:

// Your component implements the listener interface
class MyComponent : public Component, public wifi::WiFiIPStateListener {
 public:
  void setup() override {
    wifi::global_wifi_component->add_ip_state_listener(this);
  }
  void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
                   const network::IPAddress &dns2) override {
    // Handle IP state change
  }
};

Available listener interfaces:

Interface Method Signature
WiFiIPStateListener on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1, const network::IPAddress &dns2)
WiFiConnectStateListener on_wifi_connect_state(StringRef ssid, std::span<const uint8_t, 6> bssid)
WiFiScanResultsListener on_wifi_scan_results(const wifi_scan_vector_t<WiFiScanResult> &results)
WiFiPowerSaveListener on_wifi_power_save(WiFiPowerSaveMode mode)

Logger Listeners

Components implementing LogListener must request a listener slot:

# In your component's __init__.py
from esphome.components.logger import request_log_listener

async def to_code(config):
    request_log_listener()
    # ... rest of code generation

Logger Listener C++ Registration

class MyComponent : public Component, public logger::LogListener {
 public:
  void setup() override {
    if (logger::global_logger != nullptr)
      logger::global_logger->add_log_listener(this);
  }
  void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override {
    // Handle log message
  }
};

Compilation

External components will compile successfully but listeners will silently fail if the request function is not called. There is no compile-time error - the listener simply won't receive callbacks.

Finding code that needs updates

# Find WiFi listener registrations
grep -rn "add_ip_state_listener\|add_connect_state_listener" your_component/
grep -rn "add_scan_results_listener\|add_power_save_listener" your_component/

# Find log listener registrations
grep -rn "add_log_listener" your_component/

Why this change

  • Flash savings: 1,048 bytes on ESP8266 (WiFi), 268 bytes (Logger)
  • Unused code elimination: Only requested listener types are compiled
  • Exact sizing: StaticVectors sized precisely for actual component count
  • No heap fragmentation: Compile-time allocation instead of runtime

Reference Pull Requests

Questions?

If you have questions about migrating your external component, please ask in:

Comments

Feel free to leave a comment here to discuss this post wth others. You can ask questions, share your experience, or suggest improvements. If you have a question about a specific feature or issue, please consider using the ESPHome Discord. Stick to English and follow ESPHome's code of conduct. These comments exist on a discussion on GitHub, so you can also comment there directly if you prefer.