Socket Consumption API
When developing components that use network sockets on ESP32 with ESP-IDF, you must register your socket requirements using the Socket Consumption API. This ensures ESPHome automatically configures CONFIG_LWIP_MAX_SOCKETS with sufficient capacity for all components in a configuration.
Background
Section titled “Background”On ESP32 with ESP-IDF, the CONFIG_LWIP_MAX_SOCKETS setting limits how many sockets can be open simultaneously. If this limit is too low, components fail to create sockets with errors like:
E (3555) httpd: httpd_server_init: error in creating msg socket (23)The Socket Consumption API solves this by having components declare their socket needs during configuration validation. The ESP32 platform then automatically calculates and configures the required limit based on the total needs of all components.
When to Register Socket Usage
Section titled “When to Register Socket Usage”Register socket consumption if your component:
- Creates listening sockets (TCP/UDP servers)
- Establishes outbound connections (HTTP clients, MQTT, etc.)
- Uses multicast sockets (mDNS, discovery protocols)
- Wraps system services that consume sockets
How to Register Socket Usage
Section titled “How to Register Socket Usage”1. Add Socket Dependency
Section titled “1. Add Socket Dependency”In your component’s __init__.py, add socket to AUTO_LOAD:
AUTO_LOAD = ["socket"]This ensures the socket component is automatically loaded without requiring users to add it to their configuration.
2. Import and Register Sockets
Section titled “2. Import and Register Sockets”Create a validator function that registers your socket needs:
from esphome.components import socketimport esphome.config_validation as cv
def _consume_sockets(config): """Register socket needs for this component.""" # Example: 1 listening socket + 2 concurrent client connections socket.consume_sockets(3, "my_component")(config) return config
CONFIG_SCHEMA = cv.All( cv.Schema({ # Your component schema here }).extend(cv.COMPONENT_SCHEMA), _consume_sockets, # Register socket usage during validation)3. Calculate Your Socket Requirements
Section titled “3. Calculate Your Socket Requirements”Count all sockets your component uses:
Listening sockets: Each server/listener typically needs 1 socket:
# Web server with one listenersocket.consume_sockets(1, "my_server")Client connections: Add expected concurrent connections:
# API: 1 listener + 3 typical concurrent clientssocket.consume_sockets(4, "api")Multicast sockets: Count IPv4 and IPv6 separately:
# mDNS: separate sockets for IPv4 and IPv6socket.consume_sockets(2, "mdns")Multiple instances: Register per-instance if MULTI_CONF is enabled:
def _consume_camera_sockets(config): # Each camera instance needs 3 sockets (1 listener + 2 clients) socket.consume_sockets(3, f"esp32_camera_web_server_{config[CONF_ID]}")(config) return configExamples from Core Components
Section titled “Examples from Core Components”Simple Client (MQTT)
Section titled “Simple Client (MQTT)”def _consume_mqtt_sockets(config): """MQTT needs one socket for broker connection.""" from esphome.components import socket socket.consume_sockets(1, "mqtt")(config) return config
CONFIG_SCHEMA = cv.All( cv.Schema({ # MQTT configuration }).extend(cv.COMPONENT_SCHEMA), _consume_mqtt_sockets,)Server with Multiple Clients (Web Server)
Section titled “Server with Multiple Clients (Web Server)”def _consume_web_server_sockets(config): """Web server needs 1 listener + 2 concurrent clients.""" from esphome.components import socket socket.consume_sockets(3, "web_server")(config) return config
CONFIG_SCHEMA = cv.All( cv.Schema({ # Web server configuration }).extend(cv.COMPONENT_SCHEMA), _consume_web_server_sockets,)Multi-Instance Component (Camera)
Section titled “Multi-Instance Component (Camera)”def _consume_camera_sockets(config): """Each camera web server needs 3 sockets.""" from esphome.components import socket # Use unique consumer name per instance socket.consume_sockets(3, f"camera_{config[CONF_ID]}")(config) return config
CONFIG_SCHEMA = cv.All( cv.Schema({ cv.GenerateID(): cv.declare_id(ESP32Camera), # Camera configuration }).extend(cv.COMPONENT_SCHEMA), _consume_camera_sockets,)How It Works
Section titled “How It Works”-
Registration Phase: During configuration validation, each component calls
socket.consume_sockets(count, name)to register its socket needs. -
Accumulation: ESPHome stores these registrations in
CORE.data[KEY_SOCKET_CONSUMERS], accumulating the total across all components. -
Auto-Configuration: The ESP32 platform’s
_configure_lwip_max_sockets()function reads the total and setsCONFIG_LWIP_MAX_SOCKETSin sdkconfig. -
User Overrides: Manual user settings via
sdkconfig_optionsare respected. ESPHome validates that manual values are sufficient and warns if too low.
Platform Support
Section titled “Platform Support”The Socket Consumption API is currently used by:
- ESP32 (ESP-IDF framework only)
Other platforms (ESP8266, RP2040, etc.) ignore socket registrations as they don’t have configurable socket limits.
Validation and Warnings
Section titled “Validation and Warnings”If a user manually sets CONFIG_LWIP_MAX_SOCKETS too low, ESPHome will issue a warning:
esp32: framework: type: esp-idf sdkconfig_options: CONFIG_LWIP_MAX_SOCKETS: "8" # Too low!
# Warning: CONFIG_LWIP_MAX_SOCKETS is set to 8 but components need 16 sockets:# - api: 4# - web_server: 3# - mdns: 2# - ota: 1# - mqtt: 1# - camera_cam1: 3# - camera_cam2: 3Best Practices
Section titled “Best Practices”-
Count accurately: Include all sockets your component creates, including hidden ones (like multicast).
-
Document assumptions: Comment your socket count calculation for maintainability.
-
Use descriptive names: The consumer name appears in validation warnings, so make it clear what component is using sockets.
-
Test socket exhaustion: Verify your component handles socket exhaustion gracefully if the limit is insufficient.
-
Consider scaling: If your component creates variable numbers of sockets based on configuration, calculate dynamically:
def _consume_sockets(config):from esphome.components import socket# 1 listener + configured max_clientscount = 1 + config.get(CONF_MAX_CLIENTS, 5)socket.consume_sockets(count, "my_component")(config)return config
Troubleshooting
Section titled “Troubleshooting”“error in creating socket (23)” - ENFILE error indicates socket exhaustion. Component isn’t registering socket usage or count is too low.
Component not auto-loading socket - Ensure AUTO_LOAD = ["socket"] or DEPENDENCIES = ["socket"] is set.
Sockets not counted - Verify _consume_sockets is in the cv.All() validator chain and returns the config.
Manual override ignored - User sdkconfig settings take precedence. Check for warnings about insufficient limits.
See Also
Section titled “See Also”- Advanced Component Topics
- Socket Consumption API: PR #11378
Copyright © 2026 ESPHome - A project from the Open Home Foundation