Extend the ESP32 lwip_select() replacement (direct rcvevent reads +
FreeRTOS task notifications) to all LibreTiny platforms (bk72xx,
rtl87xx, ln882h).
All LibreTiny platforms have LwIP >= 2.1.3 with
lwip_socket_dbg_get_socket() and FreeRTOS task notifications. The
thread safety argument is actually stronger on LibreTiny since all
platforms are single-core ARM Cortex-M, eliminating cross-core
memory ordering concerns entirely.
Introduces USE_LWIP_FAST_SELECT feature define (set from Python
codegen for ESP32 and LibreTiny) replacing per-platform USE_ESP32
guards. The only platform-specific difference is FreeRTOS header
paths (freertos/FreeRTOS.h on ESP-IDF vs FreeRTOS.h on LibreTiny).
Expected impact on LibreTiny (same as ESP32):
- ~17x faster socket polling (direct rcvevent vs lwip_select)
- ~3.5 KB flash savings (dead code elimination of lwip_select)
- ~56 bytes static RAM savings (fd_set members excluded)
- ~200-300 bytes heap savings (UDP wake socket eliminated)
Move tests that use make_us_central(), set_global_tz(), ParsedTimezone,
and DSTRuleType into esphome::time::testing namespace where those symbols
are declared.
Remove the runtime POSIX TZ string parser and all associated bridge code
now that timezone data is sent as pre-parsed structs via protobuf.
Removed:
- parse_posix_tz() and internal parsing helpers (skip_tz_name, parse_offset,
parse_dst_rule, parse_uint, parse_transition_time)
- RealTimeClock::set_timezone() overloads and apply_timezone_()
- API connection fallback path for string-based timezone
Kept:
- All conversion functions (epoch_to_local_tm, is_in_dst, calculate_dst_transition)
- Internal helpers used by conversion functions
- localtime_r/localtime overrides
- Tests for all permanent functions
On ESP8266, .rodata is mapped to DRAM (RAM), not flash. When
StructInitializer is used with all compile-time constant fields,
the compiler places the entire struct as a const blob in .rodata,
silently consuming ~20 bytes of RAM.
Switch to field-by-field assignment on ESP8266 so the IP address
values are encoded as immediate operands in flash instructions
instead of a .rodata blob. Other platforms continue to use the
aggregate initializer since their .rodata is flash-mapped.
Water heater was the only entity type that directly called
encode_message_to_buffer() instead of fill_and_encode_entity_state().
This meant device_id was never set on WaterHeaterStateResponse,
causing entities with device_id to show as unknown in Home Assistant.
Expand the device_id integration test to cover all entity types:
cover, fan, lock, number, select, text, valve, water_heater,
alarm_control_panel, date, time, datetime, and event.
Closes https://github.com/esphome/esphome/issues/14206
Replace the heap-allocated tx_buffer_ (new char[]) with a compile-time
sized inline array using ESPHOME_LOGGER_TX_BUFFER_SIZE define. This
eliminates a heap allocation during Logger construction, saving ~513
bytes of heap on memory-constrained devices like BK72xx.
Changes:
- Add ESPHOME_LOGGER_TX_BUFFER_SIZE define set from Python config
- Change tx_buffer_ from char* to char[ESPHOME_LOGGER_TX_BUFFER_SIZE+1]
- Remove tx_buffer_size_ member field
- Update constructor to no longer take tx_buffer_size parameter
- Update all references to use the compile-time constant
The Beken/RTL SDKs ship lwIP defaults tuned for a general-purpose WiFi
SoC: TCP_SND_BUF=10*MSS (14.6KB), MEM_SIZE=32KB, 12 TCP + 22 UDP
sockets. These waste significant RAM on memory-constrained chips.
ESPAsyncWebServer allocates malloc(tcp_sndbuf()) per response chunk,
and at 14.6KB this causes OOM on BK7231N.
This tunes lwIP to match ESP32/ESP8266 ranges:
- TCP_SND_BUF/TCP_WND: 4*MSS (was 10*MSS)
- MEM_SIZE: 12KB BK72XX / 16KB RTL,LN (was 32KB)
- Socket counts: dynamic from component registrations
- All derived pool sizes adjusted accordingly
Also splits socket consumer tracking into TCP/UDP, adds
get_socket_counts() API, and updates ESP32 to use it.
Closes https://github.com/esphome/esphome/issues/14095
Tracks heap usage per component during both construction and setup() phases.
Logs deltas inline as components are registered and set up, then prints a
sorted summary after setup() completes. Storage is freed after the summary.
This is a diagnostic tool - not intended for production use. It was used to
discover the logger's unused UART event queue allocation (#14168).