mirror of
https://github.com/esphome/esphome.git
synced 2025-11-12 12:55:46 +00:00
Compare commits
11 Commits
wifi_pass_
...
beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d71b6b93e | ||
|
|
298813d4fa | ||
|
|
56d141c741 | ||
|
|
47a7f729dd | ||
|
|
7806eb980f | ||
|
|
a59888224c | ||
|
|
58ad4759f0 | ||
|
|
87f79290ba | ||
|
|
9326d78439 | ||
|
|
a93887a790 | ||
|
|
d7fa131a8a |
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2025.11.0-dev
|
||||
PROJECT_NUMBER = 2025.11.0b1
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import ipaddress
|
||||
import logging
|
||||
|
||||
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.core import CORE, CoroPriority, coroutine_with_priority
|
||||
@@ -9,6 +11,13 @@ from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
AUTO_LOAD = ["mdns"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
# High performance networking tracking infrastructure
|
||||
# Components can request high performance networking and this configures lwip and WiFi settings
|
||||
KEY_HIGH_PERFORMANCE_NETWORKING = "high_performance_networking"
|
||||
CONF_ENABLE_HIGH_PERFORMANCE = "enable_high_performance"
|
||||
|
||||
network_ns = cg.esphome_ns.namespace("network")
|
||||
IPAddress = network_ns.class_("IPAddress")
|
||||
|
||||
@@ -47,6 +56,55 @@ def ip_address_literal(ip: str | int | None) -> cg.MockObj:
|
||||
return IPAddress(str(ip))
|
||||
|
||||
|
||||
def require_high_performance_networking() -> None:
|
||||
"""Request high performance networking for network and WiFi.
|
||||
|
||||
Call this from components that need optimized network performance for streaming
|
||||
or high-throughput data transfer. This enables high performance mode which
|
||||
configures both lwip TCP settings and WiFi driver settings for improved
|
||||
network performance.
|
||||
|
||||
Settings applied (ESP-IDF only):
|
||||
- lwip: Larger TCP buffers, windows, and mailbox sizes
|
||||
- WiFi: Increased RX/TX buffers, AMPDU aggregation, PSRAM allocation (set by wifi component)
|
||||
|
||||
Configuration is PSRAM-aware:
|
||||
- With PSRAM guaranteed: Aggressive settings (512 RX buffers, 512KB TCP windows)
|
||||
- Without PSRAM: Conservative optimized settings (64 buffers, 65KB TCP windows)
|
||||
|
||||
Example:
|
||||
from esphome.components import network
|
||||
|
||||
def _request_high_performance_networking(config):
|
||||
network.require_high_performance_networking()
|
||||
return config
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
...,
|
||||
_request_high_performance_networking,
|
||||
)
|
||||
"""
|
||||
# Only set up once (idempotent - multiple components can call this)
|
||||
if not CORE.data.get(KEY_HIGH_PERFORMANCE_NETWORKING, False):
|
||||
CORE.data[KEY_HIGH_PERFORMANCE_NETWORKING] = True
|
||||
|
||||
|
||||
def has_high_performance_networking() -> bool:
|
||||
"""Check if high performance networking mode is enabled.
|
||||
|
||||
Returns True when high performance networking has been requested by a
|
||||
component or explicitly enabled in the network configuration. This indicates
|
||||
that lwip and WiFi will use optimized buffer sizes and settings.
|
||||
|
||||
This function should be called during code generation (to_code phase) by
|
||||
components that need to apply performance-related settings.
|
||||
|
||||
Returns:
|
||||
bool: True if high performance networking is enabled, False otherwise
|
||||
"""
|
||||
return CORE.data.get(KEY_HIGH_PERFORMANCE_NETWORKING, False)
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.SplitDefault(
|
||||
@@ -71,6 +129,7 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
),
|
||||
),
|
||||
cv.Optional(CONF_MIN_IPV6_ADDR_COUNT, default=0): cv.positive_int,
|
||||
cv.Optional(CONF_ENABLE_HIGH_PERFORMANCE): cv.All(cv.boolean, cv.only_on_esp32),
|
||||
}
|
||||
)
|
||||
|
||||
@@ -80,6 +139,70 @@ async def to_code(config):
|
||||
cg.add_define("USE_NETWORK")
|
||||
if CORE.using_arduino and CORE.is_esp32:
|
||||
cg.add_library("Networking", None)
|
||||
|
||||
# Apply high performance networking settings
|
||||
# Config can explicitly enable/disable, or default to component-driven behavior
|
||||
enable_high_perf = config.get(CONF_ENABLE_HIGH_PERFORMANCE)
|
||||
component_requested = CORE.data.get(KEY_HIGH_PERFORMANCE_NETWORKING, False)
|
||||
|
||||
# Explicit config overrides component request
|
||||
should_enable = (
|
||||
enable_high_perf if enable_high_perf is not None else component_requested
|
||||
)
|
||||
|
||||
# Log when user explicitly disables but a component requested it
|
||||
if enable_high_perf is False and component_requested:
|
||||
_LOGGER.info(
|
||||
"High performance networking disabled by user configuration (overriding component request)"
|
||||
)
|
||||
|
||||
if CORE.is_esp32 and CORE.using_esp_idf and should_enable:
|
||||
# Check if PSRAM is guaranteed (set by psram component during final validation)
|
||||
psram_guaranteed = psram_is_guaranteed()
|
||||
|
||||
if psram_guaranteed:
|
||||
_LOGGER.info(
|
||||
"Applying high-performance lwip settings (PSRAM guaranteed): 512KB TCP windows, 512 mailbox sizes"
|
||||
)
|
||||
# PSRAM is guaranteed - use aggressive settings
|
||||
# Higher maximum values are allowed because CONFIG_LWIP_WND_SCALE is set to true
|
||||
# CONFIG_LWIP_WND_SCALE can only be enabled if CONFIG_SPIRAM_IGNORE_NOTFOUND isn't set
|
||||
# Based on https://github.com/espressif/esp-adf/issues/297#issuecomment-783811702
|
||||
|
||||
# Enable window scaling for much larger TCP windows
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_WND_SCALE", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RCV_SCALE", 3)
|
||||
|
||||
# Large TCP buffers and windows (requires PSRAM)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT", 65534)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_WND_DEFAULT", 512000)
|
||||
|
||||
# Large mailboxes for high throughput
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 512)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 512)
|
||||
|
||||
# TCP connection limits
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_MAX_ACTIVE_TCP", 16)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_MAX_LISTENING_TCP", 16)
|
||||
|
||||
# TCP optimizations
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_MAXRTX", 12)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_SYNMAXRTX", 6)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_MSS", 1436)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_MSL", 60000)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_OVERSIZE_MSS", True)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_QUEUE_OOSEQ", True)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"Applying optimized lwip settings: 65KB TCP windows, 64 mailbox sizes"
|
||||
)
|
||||
# PSRAM not guaranteed - use more conservative, but still optimized settings
|
||||
# Based on https://github.com/espressif/esp-idf/blob/release/v5.4/examples/wifi/iperf/sdkconfig.defaults.esp32
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT", 65534)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_WND_DEFAULT", 65534)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 64)
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 64)
|
||||
|
||||
if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None:
|
||||
cg.add_define("USE_NETWORK_IPV6", enable_ipv6)
|
||||
if enable_ipv6:
|
||||
|
||||
@@ -35,6 +35,9 @@ DOMAIN = "psram"
|
||||
|
||||
DEPENDENCIES = [PLATFORM_ESP32]
|
||||
|
||||
# PSRAM availability tracking for cross-component coordination
|
||||
KEY_PSRAM_GUARANTEED = "psram_guaranteed"
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
psram_ns = cg.esphome_ns.namespace(DOMAIN)
|
||||
@@ -71,6 +74,23 @@ def supported() -> bool:
|
||||
return variant in SPIRAM_MODES
|
||||
|
||||
|
||||
def is_guaranteed() -> bool:
|
||||
"""Check if PSRAM is guaranteed to be available.
|
||||
|
||||
Returns True when PSRAM is configured with both 'disabled: false' and
|
||||
'ignore_not_found: false', meaning the device will fail to boot if PSRAM
|
||||
is not found. This ensures safe use of high buffer configurations that
|
||||
depend on PSRAM.
|
||||
|
||||
This function should be called during code generation (to_code phase) by
|
||||
components that need to know PSRAM availability for configuration decisions.
|
||||
|
||||
Returns:
|
||||
bool: True if PSRAM is guaranteed, False otherwise
|
||||
"""
|
||||
return CORE.data.get(KEY_PSRAM_GUARANTEED, False)
|
||||
|
||||
|
||||
def validate_psram_mode(config):
|
||||
esp32_config = fv.full_config.get()[PLATFORM_ESP32]
|
||||
if config[CONF_SPEED] == "120MHZ":
|
||||
@@ -131,7 +151,22 @@ def get_config_schema(config):
|
||||
|
||||
CONFIG_SCHEMA = get_config_schema
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = validate_psram_mode
|
||||
|
||||
def _store_psram_guaranteed(config):
|
||||
"""Store PSRAM guaranteed status in CORE.data for other components.
|
||||
|
||||
PSRAM is "guaranteed" when it will fail if not found, ensuring safe use
|
||||
of high buffer configurations in network/wifi components.
|
||||
|
||||
Called during final validation to ensure the flag is available
|
||||
before any to_code() functions run.
|
||||
"""
|
||||
psram_guaranteed = not config[CONF_DISABLED] and not config[CONF_IGNORE_NOT_FOUND]
|
||||
CORE.data[KEY_PSRAM_GUARANTEED] = psram_guaranteed
|
||||
return config
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = cv.All(validate_psram_mode, _store_psram_guaranteed)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
|
||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
||||
|
||||
from esphome import automation, external_files
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import audio, esp32, media_player, psram, speaker
|
||||
from esphome.components import audio, esp32, media_player, network, psram, speaker
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_BUFFER_SIZE,
|
||||
@@ -32,6 +32,7 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
AUTO_LOAD = ["audio"]
|
||||
DEPENDENCIES = ["network"]
|
||||
|
||||
CODEOWNERS = ["@kahrendt", "@synesthesiam"]
|
||||
DOMAIN = "media_player"
|
||||
@@ -280,6 +281,18 @@ PIPELINE_SCHEMA = cv.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _request_high_performance_networking(config):
|
||||
"""Request high performance networking for streaming media.
|
||||
|
||||
Speaker media player streams audio data, so it always benefits from
|
||||
optimized WiFi and lwip settings regardless of codec support.
|
||||
Called during config validation to ensure flags are set before to_code().
|
||||
"""
|
||||
network.require_high_performance_networking()
|
||||
return config
|
||||
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
media_player.media_player_schema(SpeakerMediaPlayer).extend(
|
||||
{
|
||||
@@ -304,6 +317,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.only_with_esp_idf,
|
||||
_validate_repeated_speaker,
|
||||
_request_high_performance_networking,
|
||||
)
|
||||
|
||||
|
||||
@@ -321,28 +335,10 @@ FINAL_VALIDATE_SCHEMA = cv.All(
|
||||
|
||||
async def to_code(config):
|
||||
if CORE.data[DOMAIN][config[CONF_ID].id][CONF_CODEC_SUPPORT_ENABLED]:
|
||||
# Compile all supported audio codecs and optimize the wifi settings
|
||||
|
||||
# Compile all supported audio codecs
|
||||
cg.add_define("USE_AUDIO_FLAC_SUPPORT", True)
|
||||
cg.add_define("USE_AUDIO_MP3_SUPPORT", True)
|
||||
|
||||
# Based on https://github.com/espressif/esp-idf/blob/release/v5.4/examples/wifi/iperf/sdkconfig.defaults.esp32
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM", 16)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM", 64)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM", 64)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_TX_ENABLED", True)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_TX_BA_WIN", 32)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_RX_ENABLED", True)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_ESP_WIFI_RX_BA_WIN", 32)
|
||||
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_LWIP_TCP_SND_BUF_DEFAULT", 65534)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_LWIP_TCP_WND_DEFAULT", 65534)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 64)
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 64)
|
||||
|
||||
# Allocate wifi buffers in PSRAM
|
||||
esp32.add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True)
|
||||
|
||||
var = await media_player.new_media_player(config)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
|
||||
@@ -5,7 +5,11 @@ from esphome.automation import Condition
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.const import CONF_USE_PSRAM
|
||||
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
|
||||
from esphome.components.network import ip_address_literal
|
||||
from esphome.components.network import (
|
||||
has_high_performance_networking,
|
||||
ip_address_literal,
|
||||
)
|
||||
from esphome.components.psram import is_guaranteed as psram_is_guaranteed
|
||||
from esphome.config_helpers import filter_source_files_from_platform
|
||||
import esphome.config_validation as cv
|
||||
from esphome.config_validation import only_with_esp_idf
|
||||
@@ -56,6 +60,8 @@ _LOGGER = logging.getLogger(__name__)
|
||||
|
||||
AUTO_LOAD = ["network"]
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
NO_WIFI_VARIANTS = [const.VARIANT_ESP32H2, const.VARIANT_ESP32P4]
|
||||
CONF_SAVE = "save"
|
||||
CONF_MIN_AUTH_MODE = "min_auth_mode"
|
||||
@@ -496,6 +502,56 @@ async def to_code(config):
|
||||
|
||||
if config.get(CONF_USE_PSRAM):
|
||||
add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True)
|
||||
|
||||
# Apply high performance WiFi settings if high performance networking is enabled
|
||||
if CORE.is_esp32 and CORE.using_esp_idf and has_high_performance_networking():
|
||||
# Check if PSRAM is guaranteed (set by psram component during final validation)
|
||||
psram_guaranteed = psram_is_guaranteed()
|
||||
|
||||
# Always allocate WiFi buffers in PSRAM if available
|
||||
add_idf_sdkconfig_option("CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP", True)
|
||||
|
||||
if psram_guaranteed:
|
||||
_LOGGER.info(
|
||||
"Applying high-performance WiFi settings (PSRAM guaranteed): 512 RX buffers, 32 TX buffers"
|
||||
)
|
||||
# PSRAM is guaranteed - use aggressive settings
|
||||
# Higher maximum values are allowed because CONFIG_LWIP_WND_SCALE is set to true in networking component
|
||||
# Based on https://github.com/espressif/esp-adf/issues/297#issuecomment-783811702
|
||||
|
||||
# Large dynamic RX buffers (requires PSRAM)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM", 16)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM", 512)
|
||||
|
||||
# Static TX buffers for better performance
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_STATIC_TX_BUFFER", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_TX_BUFFER_TYPE", 0)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_CACHE_TX_BUFFER_NUM", 32)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_STATIC_TX_BUFFER_NUM", 8)
|
||||
|
||||
# AMPDU settings optimized for PSRAM
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_TX_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_TX_BA_WIN", 16)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_RX_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_RX_BA_WIN", 32)
|
||||
else:
|
||||
_LOGGER.info(
|
||||
"Applying optimized WiFi settings: 64 RX buffers, 64 TX buffers"
|
||||
)
|
||||
# PSRAM not guaranteed - use more conservative, but still optimized settings
|
||||
# Based on https://github.com/espressif/esp-idf/blob/release/v5.4/examples/wifi/iperf/sdkconfig.defaults.esp32
|
||||
|
||||
# Standard buffer counts
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM", 16)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM", 64)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM", 64)
|
||||
|
||||
# Standard AMPDU settings
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_TX_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_TX_BA_WIN", 32)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_AMPDU_RX_ENABLED", True)
|
||||
add_idf_sdkconfig_option("CONFIG_ESP_WIFI_RX_BA_WIN", 32)
|
||||
|
||||
cg.add_define("USE_WIFI")
|
||||
|
||||
# must register before OTA safe mode check
|
||||
|
||||
@@ -4,7 +4,7 @@ from enum import Enum
|
||||
|
||||
from esphome.enum import StrEnum
|
||||
|
||||
__version__ = "2025.11.0-dev"
|
||||
__version__ = "2025.11.0b1"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
||||
@@ -1 +1,4 @@
|
||||
<<: !include common.yaml
|
||||
|
||||
network:
|
||||
enable_high_performance: true
|
||||
|
||||
Reference in New Issue
Block a user