Merge remote-tracking branch 'origin/integration' into integration

This commit is contained in:
J. Nick Koston
2026-02-21 22:10:16 -06:00
3 changed files with 47 additions and 40 deletions
+11 -18
View File
@@ -1265,15 +1265,8 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
# CONFIG_LWIP_MAX_SOCKETS is a single VFS socket pool shared by all socket
# types (TCP clients, TCP listeners, and UDP). Include all three counts.
(
tcp_sockets,
udp_sockets,
tcp_listen,
tcp_details,
udp_details,
tcp_listen_details,
) = get_socket_counts()
total_sockets = tcp_sockets + udp_sockets + tcp_listen
sc = get_socket_counts()
total_sockets = sc.tcp + sc.udp + sc.tcp_listen
# User specified their own value - respect it but warn if insufficient
if user_max_sockets is not None:
@@ -1294,9 +1287,9 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
"at least %d.",
user_sockets_int,
total_sockets,
tcp_sockets,
udp_sockets,
tcp_listen,
sc.tcp,
sc.udp,
sc.tcp_listen,
total_sockets,
)
# User's value already added via sdkconfig_options processing
@@ -1314,12 +1307,12 @@ def _configure_lwip_max_sockets(conf: dict) -> None:
"(TCP=%d [%s], UDP=%d [%s], TCP_LISTEN=%d [%s])",
max_sockets,
sock_min,
tcp_sockets,
tcp_details,
udp_sockets,
udp_details,
tcp_listen,
tcp_listen_details,
sc.tcp,
sc.tcp_details,
sc.udp,
sc.udp_details,
sc.tcp_listen,
sc.tcp_listen_details,
)
add_idf_sdkconfig_option("CONFIG_LWIP_MAX_SOCKETS", max_sockets)
+14 -15
View File
@@ -290,7 +290,7 @@ def _configure_lwip(config: dict) -> None:
Setting ESP8266 ESP32 BK SDK RTL SDK LN SDK New
────────────────────────────────────────────────────────────────────────────
TCP_SND_BUF 2×MSS 4×MSS 10×MSS 5×MSS 7×MSS 4×MSS
TCP_WND 4×MSS 4×MSS 10×MSS 2×MSS 3×MSS 4×MSS
TCP_WND 4×MSS 4×MSS 3/10×MSS 2×MSS 3×MSS 4×MSS
MEM_LIBC_MALLOC 1 1 0 0 1 1
MEMP_MEM_MALLOC 1 1 0 0 0 1
MEM_SIZE N/A* N/A* 16/32KB 5KB N/A* N/A* BK
@@ -313,23 +313,22 @@ def _configure_lwip(config: dict) -> None:
**** RTL/LN LT overlay overrides to flat 7.
***** Not defined in RTL SDK — lwIP opt.h defaults shown.
"dynamic" = auto-calculated from component socket registrations via
socket.get_socket_counts() with minimums of 10 TCP / 8 UDP.
socket.get_socket_counts() with minimums of 8 TCP / 6 UDP.
"""
from esphome.components.socket import (
MIN_TCP_LISTEN_SOCKETS,
MIN_TCP_SOCKETS,
MIN_UDP_SOCKETS,
get_socket_counts,
)
raw_tcp, raw_udp, raw_tcp_listen, tcp_details, udp_details, tcp_listen_details = (
get_socket_counts()
)
sc = get_socket_counts()
# Apply platform minimums — ensure headroom for ESPHome's needs
tcp_sockets = max(MIN_TCP_SOCKETS, raw_tcp)
udp_sockets = max(MIN_UDP_SOCKETS, raw_udp)
tcp_sockets = max(MIN_TCP_SOCKETS, sc.tcp)
udp_sockets = max(MIN_UDP_SOCKETS, sc.udp)
# Listening sockets — registered by components (api, ota, web_server_base, etc.)
# Not all components register yet, so ensure a minimum of 2 (api + ota baseline).
listening_tcp = max(raw_tcp_listen, 2)
# Not all components register yet, so ensure a minimum for baseline operation.
listening_tcp = max(MIN_TCP_LISTEN_SOCKETS, sc.tcp_listen)
# TCP_SND_BUF: ESPAsyncWebServer allocates malloc(tcp_sndbuf()) per
# response chunk. At 10×MSS=14.6KB (BK default) this causes OOM (#14095).
@@ -398,20 +397,20 @@ def _configure_lwip(config: dict) -> None:
if CORE.is_bk72xx:
lwip_opts.append("PBUF_POOL_SIZE=10")
tcp_min = " (min)" if tcp_sockets > raw_tcp else ""
udp_min = " (min)" if udp_sockets > raw_udp else ""
listen_min = " (min)" if listening_tcp > raw_tcp_listen else ""
tcp_min = " (min)" if tcp_sockets > sc.tcp else ""
udp_min = " (min)" if udp_sockets > sc.udp else ""
listen_min = " (min)" if listening_tcp > sc.tcp_listen else ""
_LOGGER.info(
"Configuring lwIP: TCP=%d%s [%s], UDP=%d%s [%s], TCP_LISTEN=%d%s [%s]",
tcp_sockets,
tcp_min,
tcp_details,
sc.tcp_details,
udp_sockets,
udp_min,
udp_details,
sc.udp_details,
listening_tcp,
listen_min,
tcp_listen_details,
sc.tcp_listen_details,
)
cg.add_platformio_option("custom_options.lwip", lwip_opts)
+22 -7
View File
@@ -1,4 +1,5 @@
from collections.abc import Callable, MutableMapping
from dataclasses import dataclass
from enum import StrEnum
import logging
@@ -21,12 +22,14 @@ KEY_SOCKET_CONSUMERS_TCP = "socket_consumers_tcp"
KEY_SOCKET_CONSUMERS_UDP = "socket_consumers_udp"
KEY_SOCKET_CONSUMERS_TCP_LISTEN = "socket_consumers_tcp_listen"
# Recommended minimum socket counts to ensure headroom.
# Recommended minimum socket counts.
# Platforms should apply these (or their own) on top of get_socket_counts().
# TCP: api(3) = 3 base, +5 headroom for ota-transfer/web_server/other.
# UDP: dhcp(1) + dns(1) + mdns(2) + wake_loop(1) = 5 base, +1 headroom.
# These cover minimal configs (e.g. api-only without web_server).
# When web_server is present, its 5 registered sockets push past the TCP minimum.
MIN_TCP_SOCKETS = 8
MIN_UDP_SOCKETS = 6
# Minimum listening sockets — at least api + ota baseline.
MIN_TCP_LISTEN_SOCKETS = 2
# Wake loop threadsafe support tracking
KEY_WAKE_LOOP_THREADSAFE_REQUIRED = "wake_loop_threadsafe_required"
@@ -75,10 +78,20 @@ def _format_consumers(consumers: dict[str, int]) -> str:
return ", ".join(f"{name}={count}" for name, count in sorted(consumers.items()))
def get_socket_counts() -> tuple[int, int, int, str, str, str]:
"""Return socket counts and component details for platform configuration.
@dataclass(frozen=True)
class SocketCounts:
"""Socket counts and component details for platform configuration."""
Returns (tcp, udp, tcp_listen, tcp_details, udp_details, tcp_listen_details).
tcp: int
udp: int
tcp_listen: int
tcp_details: str
udp_details: str
tcp_listen_details: str
def get_socket_counts() -> SocketCounts:
"""Return socket counts and component details for platform configuration.
Platforms call this during code generation to configure lwIP socket limits.
All components will have registered their needs by then.
@@ -104,7 +117,9 @@ def get_socket_counts() -> tuple[int, int, int, str, str, str]:
tcp_listen,
tcp_listen_details,
)
return tcp, udp, tcp_listen, tcp_details, udp_details, tcp_listen_details
return SocketCounts(
tcp, udp, tcp_listen, tcp_details, udp_details, tcp_listen_details
)
def require_wake_loop_threadsafe() -> None: