Compare commits

...

2405 Commits

Author SHA1 Message Date
J. Nick Koston
484a12e3e7 Merge remote-tracking branch 'upstream/lazy_callbacks_cleanup' into integration 2026-01-19 22:43:19 -10:00
J. Nick Koston
6eeaca2020 bot 2026-01-19 22:36:28 -10:00
J. Nick Koston
7f8e7c15fa Merge branch 'lazy_callbacks_cleanup' into integration 2026-01-19 22:21:15 -10:00
J. Nick Koston
7bc142ad02 [core] Simplify LazyCallbackManager memory management 2026-01-19 22:20:43 -10:00
J. Nick Koston
36159b09b6 Merge branch 'component_vectors' into integration 2026-01-19 22:09:39 -10:00
J. Nick Koston
4293f8fe89 [core] Eliminate global constructor overhead for component vectors 2026-01-19 22:09:08 -10:00
J. Nick Koston
67b845aaca Merge branch 'wifi_info_fix' into integration 2026-01-19 19:24:17 -10:00
J. Nick Koston
3a3275e90e [wifi_info] Fix missing state when both IP+DNS or SSID+BSSID configure 2026-01-19 19:20:13 -10:00
Jonathan Swoboda
ed4ebffa74 [x9c] Fix potentiometer unable to decrement (#13382)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 22:57:54 -05:00
J. Nick Koston
9ecc7602d0 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-19 17:50:52 -10:00
J. Nick Koston
76758addf7 Merge branch 'ard_debug_no_heap' into integration 2026-01-19 17:50:18 -10:00
J. Nick Koston
c213de4861 [mapping] Use stack buffers for numeric key error logging (#13299) 2026-01-19 17:42:08 -10:00
J. Nick Koston
6cf320fd60 [mqtt] Eliminate per-entity loop overhead and heap churn (#13356) 2026-01-19 17:41:55 -10:00
J. Nick Koston
aeea340bc6 [cs5460a] Remove unnecessary empty loop override (#13357) 2026-01-19 17:41:03 -10:00
J. Nick Koston
d0e50ed030 [lock] Extract set_state_ helper to reduce code duplication (#13359) 2026-01-19 17:40:51 -10:00
J. Nick Koston
280d460025 [statsd] Use direct appends and stack buffer instead of str_sprintf (#13223)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-19 17:40:20 -10:00
J. Nick Koston
4d37ddb778 Merge branch 'dev' into ard_debug_no_heap 2026-01-19 17:39:34 -10:00
J. Nick Koston
ea70faf642 [debug] Use shared buf_append_printf helper from core (#13260) 2026-01-19 17:38:56 -10:00
J. Nick Koston
5d7b38b261 [ezo_pmp] Replace sprintf with bounds-checked snprintf (#13304) 2026-01-19 17:38:22 -10:00
J. Nick Koston
e88093ca60 [am43][lightwaverf][rf_bridge][spi_led_strip] Replace sprintf with safe alternatives (#13302) 2026-01-19 17:38:08 -10:00
J. Nick Koston
b48d4ab785 [mqtt] Reduce heap allocations in publish path (#13372) 2026-01-19 17:37:54 -10:00
J. Nick Koston
8ade9dfc10 [shtcx] Use LogString for type to_string to save RAM on ESP8266 (#13370) 2026-01-19 17:37:33 -10:00
J. Nick Koston
4e0e7796de [mqtt] Remove unnecessary defer in ESP8266 on_message callback (#13373) 2026-01-19 17:37:19 -10:00
J. Nick Koston
62b6c9bf7c [esp32_ble] Deprecate ESPBTUUID::to_string() in favor of heap-free to_str() (#13376) 2026-01-19 17:37:03 -10:00
J. Nick Koston
b5fe271d6b [sprinkler] Disable loops when idle to reduce CPU overhead (#13381) 2026-01-19 17:36:47 -10:00
J. Nick Koston
5d787e2512 [sprinkler] Eliminate std::string heap allocations (#13379) 2026-01-19 17:35:58 -10:00
J. Nick Koston
8998ef0bc3 [network] Deprecate IPAddress::str() in favor of heap-free str_to() (#13378) 2026-01-19 17:35:32 -10:00
J. Nick Koston
8ec31dd769 [voice_assistant] Deprecate Timer::to_string() in favor of heap-free to_str() (#13377) 2026-01-19 17:35:19 -10:00
J. Nick Koston
0193464f92 [dsmr] Avoid std::string allocation for decryption key (#13375) 2026-01-19 17:34:49 -10:00
J. Nick Koston
af2f1f3ec9 Merge branch 'sprinker_loops_reduce' into integration 2026-01-19 16:07:48 -10:00
J. Nick Koston
acdd0d85b1 [sprinkler] Disable loops when idle to reduce CPU overhead 2026-01-19 16:05:37 -10:00
J. Nick Koston
4d82fd3019 bot comments 2026-01-19 15:30:24 -10:00
J. Nick Koston
99fecf9c75 Merge branch 'sprinker_followup_cleanups' into integration 2026-01-19 15:28:28 -10:00
J. Nick Koston
916d802a9e [sprinkler] Eliminate std::string heap allocations 2026-01-19 15:26:57 -10:00
J. Nick Koston
dd851509a5 [sprinkler] Eliminate std::string heap allocations 2026-01-19 15:23:49 -10:00
J. Nick Koston
27ea65ae7c Merge branch 'ipaddress_small_string_no_heap' into integration 2026-01-19 15:16:59 -10:00
J. Nick Koston
077517b0b3 [network] Deprecate IPAddress::str() in favor of heap-free str_to() 2026-01-19 15:16:12 -10:00
J. Nick Koston
4af1afa852 Merge branch 'sprintf_group_2' into integration 2026-01-19 15:13:07 -10:00
J. Nick Koston
61f9dff8ab Merge remote-tracking branch 'upstream/sprintf_group_2' into sprintf_group_2 2026-01-19 15:11:34 -10:00
J. Nick Koston
8f4ca0c6d2 simplify 2026-01-19 15:11:21 -10:00
J. Nick Koston
365bd036d2 Merge branch 'dev' into sprintf_group_2 2026-01-19 15:10:32 -10:00
J. Nick Koston
a80e6a6467 Merge branch 'voice_assist_to_string' into integration 2026-01-19 15:04:44 -10:00
J. Nick Koston
ff61248224 [voice_assistant] Deprecate Timer::to_string() in favor of heap-free to_str() 2026-01-19 15:03:45 -10:00
J. Nick Koston
1e233d1443 Merge branch 'ESPBTUUID_to_string' into integration 2026-01-19 14:56:37 -10:00
J. Nick Koston
bff4276697 [esp32_ble] Deprecate ESPBTUUID::to_string() in favor of heap-free to_str() 2026-01-19 14:55:34 -10:00
J. Nick Koston
6fdba73576 Merge branch 'dsmr_store_key_rodata' into integration 2026-01-19 14:49:48 -10:00
J. Nick Koston
cc3a16a8bf tweak 2026-01-19 14:47:31 -10:00
J. Nick Koston
2be26ee6b0 Merge branch 'dsmr_store_key_rodata' into integration 2026-01-19 14:39:21 -10:00
J. Nick Koston
fe7038cd37 [dsmr] Avoid std::string allocation for decryption key 2026-01-19 14:38:08 -10:00
J. Nick Koston
01783e0c61 Merge branch 'mqtt_less_alloc' into integration 2026-01-19 14:27:29 -10:00
J. Nick Koston
fcebfe6f48 cleanup 2026-01-19 14:26:19 -10:00
J. Nick Koston
2c10ebe16a tweaks 2026-01-19 14:24:57 -10:00
J. Nick Koston
0eb30f4c1d Merge branch 'mqtt_defer_8266' into integration 2026-01-19 14:19:17 -10:00
J. Nick Koston
f89c082bd3 [mqtt] Remove unnecessary defer in ESP8266 on_message callback 2026-01-19 14:18:11 -10:00
J. Nick Koston
98db7c3757 Merge branch 'mqtt_less_alloc' into integration 2026-01-19 14:14:27 -10:00
J. Nick Koston
2970d3d54f [mqtt] Reduce heap allocations in publish path 2026-01-19 14:05:32 -10:00
J. Nick Koston
38e7dd5f29 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-19 12:48:51 -10:00
Jonathan Swoboda
1996bc425f [core] Fix state leakage and module caching when processing multiple configurations (#13368)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 14:46:24 -05:00
Clyde Stubbs
a0d3d54d69 [mipi_spi] Add variants of ESP32-2432S028 displays (#13340) 2026-01-20 05:13:36 +11:00
J. Nick Koston
ee264d0fd4 [anova] Replace sprintf with bounds-checked alternatives (#13303) 2026-01-18 23:57:42 -10:00
J. Nick Koston
892e9b006f [api] Use MAX_STATE_LEN constant for Home Assistant state buffer (#13278) 2026-01-18 23:57:27 -10:00
J. Nick Koston
5f88ab80f4 Merge branch 'set_time_string_literals' into integration 2026-01-18 23:29:14 -10:00
J. Nick Koston
48e7e7aeb3 hdr 2026-01-18 23:18:38 -10:00
J. Nick Koston
54a4d60f5d [datetime] Add const char * overloads for string parsing to avoid heap allocation 2026-01-18 23:09:24 -10:00
J. Nick Koston
d41980d0d2 [datetime] Add const char * overloads for string parsing to avoid heap allocation 2026-01-18 23:06:17 -10:00
J. Nick Koston
cc03168c22 Merge branch 'dev' into sprintf_group_2 2026-01-18 22:42:55 -10:00
J. Nick Koston
f8bd4ef57d [template][event] Use StringRef for set_action and on_event triggers (#13328) 2026-01-18 22:22:57 -10:00
J. Nick Koston
bfcc0e26a3 [dfrobot_sen0395][pipsolar][sim800l][wl_134] Replace sprintf with snprintf/buf_append_printf (#13301)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 22:22:44 -10:00
J. Nick Koston
d85702bf32 Merge remote-tracking branch 'origin/mqtt_reduce_heap_alloc' into integration 2026-01-18 22:13:51 -10:00
J. Nick Koston
2e3e61f464 Update esphome/components/mqtt/mqtt_component.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 22:13:34 -10:00
J. Nick Koston
115e17e95b Merge branch 'mqtt_reduce_heap_alloc' into integration 2026-01-18 22:12:28 -10:00
J. Nick Koston
43f0dd091a tweak 2026-01-18 22:12:07 -10:00
J. Nick Koston
64bf247f7b Merge branch 'mqtt_reduce_heap_alloc' into integration 2026-01-18 22:11:00 -10:00
J. Nick Koston
0117519c81 [mqtt] Reduce heap allocations in hot paths 2026-01-18 22:10:48 -10:00
J. Nick Koston
d83457bbe1 [mqtt] Reduce heap allocations in hot paths 2026-01-18 22:02:36 -10:00
J. Nick Koston
a26d01f536 Merge branch 'mqtt_resend' into integration 2026-01-18 21:36:40 -10:00
J. Nick Koston
90e67d72a5 fix 2026-01-18 21:11:36 -10:00
J. Nick Koston
994e8970f5 Revert "[logger] Optimize ESP8266 UART write path with direct FIFO register access"
This reverts commit 122e7ac01e.
2026-01-18 20:54:03 -10:00
J. Nick Koston
5ac917835e Revert "cleanup"
This reverts commit bac836d2a7.
2026-01-18 20:54:02 -10:00
J. Nick Koston
986caddb6c Merge branch 'logger_perf_8266' into integration 2026-01-18 20:38:49 -10:00
J. Nick Koston
bac836d2a7 cleanup 2026-01-18 20:37:34 -10:00
J. Nick Koston
72f71f59b3 Merge branch 'logger_perf_8266' into integration 2026-01-18 20:36:32 -10:00
J. Nick Koston
122e7ac01e [logger] Optimize ESP8266 UART write path with direct FIFO register access 2026-01-18 20:34:14 -10:00
J. Nick Koston
86a1b4cf69 [select][fan] Use StringRef for on_value/on_preset_set triggers to avoid heap allocation (#13324) 2026-01-18 19:51:11 -10:00
J. Nick Koston
207b59fe16 Merge branch 'lock_dupe_code' into integration 2026-01-18 19:50:38 -10:00
J. Nick Koston
83c68e246d [lock] Extract set_state_ helper to reduce code duplication 2026-01-18 19:49:20 -10:00
J. Nick Koston
c629e88f4b Merge branch 'alarm_control_panel_reduce_heap_alloc_code' into integration 2026-01-18 19:36:10 -10:00
J. Nick Koston
b078eb8523 [alarm_control_panel] Reduce heap allocations in arm/disarm methods 2026-01-18 19:34:31 -10:00
J. Nick Koston
98e0a82e66 Merge branch 'cs5460a_loop' into integration 2026-01-18 19:16:10 -10:00
J. Nick Koston
b4e0a0a15a [cs5460a] Remove unnecessary empty loop override 2026-01-18 19:13:48 -10:00
J. Nick Koston
d0869fbc67 Merge branch 'sprintf_group' into integration 2026-01-18 19:06:45 -10:00
J. Nick Koston
a3d926dc54 Merge remote-tracking branch 'upstream/dev' into sprintf_group
# Conflicts:
#	esphome/components/pipsolar/output/pipsolar_output.cpp
2026-01-18 18:56:11 -10:00
J. Nick Koston
5e75e66a01 Merge branch 'dev' into ard_debug_no_heap 2026-01-18 18:55:55 -10:00
J. Nick Koston
d8a28f6fba [scheduler] Replace resize() with erase() to save ~ 436 bytes flash (#13214) 2026-01-18 18:54:30 -10:00
J. Nick Koston
e80a940222 [gdk101] Use stack buffer to eliminate heap allocation for firmware version (#13224) 2026-01-18 18:52:49 -10:00
J. Nick Koston
e99dbe05f7 [toshiba] Replace to_string with stack buffer in debug logging (#13296) 2026-01-18 18:52:34 -10:00
J. Nick Koston
f453a8d9a1 [dfrobot_sen0395] Reduce heap allocations in command building (#13219) 2026-01-18 18:44:56 -10:00
J. Nick Koston
126190d26a [ezo] Replace str_sprintf with stack-based formatting (#13218)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 18:44:41 -10:00
J. Nick Koston
e40201a98d [cse7766] Use stack buffer for verbose debug logging (#13217) 2026-01-18 18:44:27 -10:00
J. Nick Koston
8142f5db44 [zephyr] Avoid heap allocation in preferences key formatting (#13215) 2026-01-18 18:43:50 -10:00
J. Nick Koston
98ccab87a7 [tormatic] Use stack buffers instead of str_sprintf in debug methods (#13225) 2026-01-18 18:43:36 -10:00
J. Nick Koston
b9e72a8774 [daikin_arc] Fix undefined behavior in sprintf calls (#13279)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 18:43:19 -10:00
J. Nick Koston
d9fc625c6a [web_server] Simplify datetime formatting with buf_append_printf (#13281) 2026-01-18 18:43:05 -10:00
J. Nick Koston
dfbf79d6d6 [homeassistant] Use buf_append_printf for ESP8266 flash optimization (#13284) 2026-01-18 18:42:19 -10:00
J. Nick Koston
ea0fac96cb [core][mqtt] Add str_sanitize_to(), soft-deprecate str_sanitize() (#13233) 2026-01-18 18:42:04 -10:00
J. Nick Koston
3182222d60 [esp32_hosted] Use stack buffer instead of str_sprintf for version string (#13226) 2026-01-18 18:41:47 -10:00
J. Nick Koston
d8849b16f2 [gpio] Use buf_append_printf in dump_summary for ESP8266 flash optimization (#13283) 2026-01-18 18:41:34 -10:00
J. Nick Koston
635983f163 [uptime] Use buf_append_printf for ESP8266 flash optimization (#13282) 2026-01-18 18:41:19 -10:00
J. Nick Koston
6cbe672004 [tuya] Use buf_append_printf for ESP8266 flash optimization (#13287) 2026-01-18 18:41:07 -10:00
J. Nick Koston
226867b05c [esp8266] Use direct SDK calls instead of Arduino ESP class wrappers (#13353) 2026-01-18 18:40:53 -10:00
J. Nick Koston
67871a1683 [ccs811] Use buf_append_printf for buffer safety and ESP8266 flash optimization (#13300) 2026-01-18 18:40:14 -10:00
J. Nick Koston
f60c03e350 [syslog] Use buf_append_printf for ESP8266 flash optimization (#13286) 2026-01-18 18:39:53 -10:00
J. Nick Koston
eb66429144 [sml] Use stack buffers instead of str_sprintf (#13222)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 18:39:23 -10:00
J. Nick Koston
0f3bac5dd6 [nextion] Replace to_string with stack buffer and fix unsafe sprintf (#13295) 2026-01-18 18:37:29 -10:00
J. Nick Koston
5b92d0b89e [wiegand] Replace heap-allocating to_string with stack buffers (#13294) 2026-01-18 18:37:14 -10:00
J. Nick Koston
052b05df56 [tuya] Replace unsafe sprintf with snprintf in light color formatting (#13292) 2026-01-18 18:37:02 -10:00
J. Nick Koston
7b0db659d1 [rc522_spi] Replace unsafe sprintf with buf_append_printf (#13291) 2026-01-18 18:36:46 -10:00
J. Nick Koston
2f7270cf8f [uart] Replace unsafe sprintf with buf_append_printf in debugger (#13288) 2026-01-18 18:36:32 -10:00
J. Nick Koston
b44727aee6 [socket] Eliminate heap allocations in set_sockaddr() (#13228) 2026-01-18 18:29:31 -10:00
J. Nick Koston
1a55254258 [status] Convert to PollingComponent to reduce CPU usage (#13342) 2026-01-18 18:28:24 -10:00
J. Nick Koston
baf2b0e3c9 [api] Fix truncation of Home Assistant attributes longer than 255 characters (#13348) 2026-01-18 18:23:11 -10:00
J. Nick Koston
88fadb242c [mqtt] Eliminate per-component loop overhead for MQTT entities 2026-01-18 17:54:51 -10:00
J. Nick Koston
326fd4fe68 Merge branch 'libretiny_heap' into integration 2026-01-18 14:43:07 -10:00
J. Nick Koston
76b1201c96 [wifi] LibreTiny: Eliminate heap allocations in WiFi scan path 2026-01-18 14:40:48 -10:00
J. Nick Koston
7efb72c511 Merge branch 'ard_debug_no_heap' into integration 2026-01-18 14:02:44 -10:00
J. Nick Koston
07a731b97d missed some 2026-01-18 14:02:33 -10:00
J. Nick Koston
db37ae0e3c Merge branch 'esp8266_sdk' into integration 2026-01-18 14:01:08 -10:00
J. Nick Koston
d2bf991bfb Merge branch 'ard_debug_no_heap' into integration 2026-01-18 14:01:02 -10:00
J. Nick Koston
f8b33562c1 cleanup messy 2026-01-18 14:00:14 -10:00
J. Nick Koston
cf17a079b7 cleanup messy 2026-01-18 13:57:52 -10:00
J. Nick Koston
a451625120 cleanup messy 2026-01-18 13:57:07 -10:00
J. Nick Koston
c180d0c49c [esp8266] Use direct SDK calls instead of Arduino ESP class wrappers 2026-01-18 13:50:46 -10:00
J. Nick Koston
bacc4ed4e5 Merge branch 'ard_debug_no_heap' into integration 2026-01-18 13:46:49 -10:00
J. Nick Koston
7acde0ab60 [debug] ESP8266: Eliminate heap allocations from Arduino String functions 2026-01-18 13:45:49 -10:00
J. Nick Koston
98c8142f86 Merge branch 'esp8266_wifi_reduce_heap_alloc' into integration 2026-01-18 12:18:37 -10:00
J. Nick Koston
4ed68c6884 [wifi] ESP8266: Use direct SDK calls to reduce flash and heap allocation 2026-01-18 12:16:18 -10:00
J. Nick Koston
680e92a226 [core] Add str_endswith_ignore_case to avoid heap allocation in audio file type detection (#13313) 2026-01-18 08:36:56 -10:00
J. Nick Koston
6ab321db1a Merge branch 'globals_polling' into integration 2026-01-18 00:40:47 -10:00
J. Nick Koston
c1cba269b3 [globals] Convert restoring globals to PollingComponent to reduce CPU usage 2026-01-18 00:35:17 -10:00
J. Nick Koston
0e2f0bae21 Merge branch 'status_binary_sensor' into integration 2026-01-17 22:47:57 -10:00
J. Nick Koston
7175299cae [status] Convert to PollingComponent to reduce CPU usage 2026-01-17 22:40:15 -10:00
J. Nick Koston
db0b32bfc9 [network] Fix IPAddress::str_to() to lowercase IPv6 hex digits (#13325) 2026-01-17 18:06:54 -10:00
J. Nick Koston
21794e28e5 [modbus_controller] Use stack buffers instead of heap-allocating string helpers (#13221)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-01-17 17:26:51 -10:00
J. Nick Koston
42ad20c231 Merge branch 'esp32_ble_tracker_opt' into integration 2026-01-17 16:52:46 -10:00
J. Nick Koston
ae5a3e616a improve comment 2026-01-17 16:26:18 -10:00
J. Nick Koston
59eeeb5fe5 Merge branch 'esp32_ble_tracker_opt' into integration 2026-01-17 16:23:37 -10:00
J. Nick Koston
759278191b simpler 2026-01-17 16:23:30 -10:00
J. Nick Koston
03eaec853a Merge branch 'esp32_ble_tracker_opt' into integration 2026-01-17 16:17:19 -10:00
J. Nick Koston
4549e375c1 adjust 2026-01-17 16:16:58 -10:00
J. Nick Koston
a8b07af2a3 fixes 2026-01-17 16:12:51 -10:00
J. Nick Koston
f011dc658d Merge branch 'esp32_ble_tracker_opt' into integration 2026-01-17 15:56:41 -10:00
J. Nick Koston
728236270c [weikai] Replace bitset to_string with format_bin_to (#13297) 2026-01-17 15:53:01 -10:00
J. Nick Koston
01cdc4ed58 [core] Add fnv1_hash_extend() string overloads, use in atm90e32 (#13326) 2026-01-17 15:52:19 -10:00
J. Nick Koston
d6a0c8ffbb [template] Store alarm control panel codes in flash instead of heap (#13329) 2026-01-17 15:52:06 -10:00
J. Nick Koston
f003fac5d8 document, document, document 2026-01-17 15:51:45 -10:00
J. Nick Koston
4cc0f874f7 [wireguard] Store configuration strings in flash instead of heap (#13331) 2026-01-17 15:51:26 -10:00
J. Nick Koston
ed58b9372f [template] Store text initial_value in flash and avoid heap allocation in setup (#13332) 2026-01-17 15:51:12 -10:00
J. Nick Koston
ee2a81923b [sun] Store text sensor format string in flash (#13335) 2026-01-17 15:51:01 -10:00
J. Nick Koston
0a1e7ee50b [pipsolar] Store command strings in flash (#13336) 2026-01-17 15:50:42 -10:00
J. Nick Koston
4d4283bcfa [udp] Store addresses in flash instead of heap (#13330) 2026-01-17 15:50:23 -10:00
J. Nick Koston
6b02f5dfbd [esp32_ble_tracker] Optimize loop with state change tracking for ~85% CPU reduction 2026-01-17 15:47:37 -10:00
J. Nick Koston
e82cc8bbc5 Merge branch 'pipsolar_flash' into integration 2026-01-17 14:22:12 -10:00
J. Nick Koston
533d3e5184 [pipsolar] Store command strings in flash 2026-01-17 14:17:15 -10:00
J. Nick Koston
48dc1331a4 [pipsolar] Store command strings in flash 2026-01-17 14:16:27 -10:00
J. Nick Koston
9c2917e8ec [pipsolar] Store command strings in flash 2026-01-17 14:15:29 -10:00
J. Nick Koston
aa777ef42f Merge branch 'sun_text_sensor' into integration 2026-01-17 14:06:47 -10:00
J. Nick Koston
ece75593cf [sun] Store text sensor format string in flash 2026-01-17 14:06:06 -10:00
J. Nick Koston
0280e830c8 Merge branch 'template_text_init_string_flash' into integration 2026-01-17 13:54:31 -10:00
J. Nick Koston
04c5cc1225 [template] Store text initial_value in flash and avoid heap allocation in setup 2026-01-17 13:50:14 -10:00
J. Nick Koston
12972889eb Merge branch 'wireguard_flash' into integration 2026-01-17 13:38:04 -10:00
J. Nick Koston
e17602c386 [wireguard] Store configuration strings in flash instead of heap 2026-01-17 13:31:02 -10:00
J. Nick Koston
055b315360 Merge branch 'udp_flash_strings' into integration 2026-01-17 13:10:45 -10:00
J. Nick Koston
3ddf408f08 Merge branch 'move_template_alarm_control_panel_codes_to_flash' into integration 2026-01-17 13:10:28 -10:00
J. Nick Koston
c82cef3b64 [udp] Store addresses in flash instead of heap 2026-01-17 13:09:57 -10:00
J. Nick Koston
2ead1deb51 [template] Store alarm control panel codes in flash instead of heap 2026-01-17 12:47:48 -10:00
J. Nick Koston
13360a21e6 [template] Store alarm control panel codes in flash instead of heap 2026-01-17 12:46:28 -10:00
J. Nick Koston
e4fb6988ff [web_server] Use ESPHOME_F for canHandle domain checks to reduce ESP8266 RAM (#13315)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2026-01-17 22:29:29 +00:00
J. Nick Koston
0b5570d947 Merge branch 'string_ref_triggers_part_2' into integration 2026-01-17 12:12:52 -10:00
J. Nick Koston
56f5e14a02 [template][event] Use StringRef for set_action and on_event triggers 2026-01-17 12:10:56 -10:00
J. Nick Koston
d31b733dce [light] Store color mode JSON strings in flash on ESP8266 (#13314) 2026-01-17 16:06:25 -06:00
Keith Burzinski
b25a2f8d8e [infrared][web_server] Implement initial web_server support (#13202)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-17 16:01:13 -06:00
J. Nick Koston
e7f1dc14bb Merge branch 'fnv1_hash_extend' into integration 2026-01-17 11:47:21 -10:00
J. Nick Koston
cd9ed4fdf1 make fnv1a_etend 2026-01-17 11:46:54 -10:00
J. Nick Koston
46777ad4c9 Merge branch 'modbus_string' into integration 2026-01-17 11:45:17 -10:00
J. Nick Koston
7c7f805147 Merge remote-tracking branch 'upstream/dev' into modbus_string 2026-01-17 11:42:55 -10:00
J. Nick Koston
dd6712bdad missed a few 2026-01-17 11:42:00 -10:00
J. Nick Koston
0e63dc1891 Merge branch 'fnv1_hash_extend' into integration 2026-01-17 11:39:51 -10:00
J. Nick Koston
657978b416 [core] Add fnv1_hash_extend() string overloads, use in atm90e32 2026-01-17 11:38:29 -10:00
J. Nick Koston
8b1a6c2082 Merge branch 'ip_address_lower_fix' into integration 2026-01-17 11:26:39 -10:00
J. Nick Koston
338f5e1282 [network] Fix IPAddress::str_to() to lowercase IPv6 hex digits 2026-01-17 11:26:01 -10:00
J. Nick Koston
84b6a97a1b Merge branch 'string_ref_triggers' into integration 2026-01-17 11:12:39 -10:00
J. Nick Koston
e5e7aa41b1 fix nolint comments 2026-01-17 11:12:27 -10:00
J. Nick Koston
48c9380ec1 Merge branch 'string_ref_triggers' into integration 2026-01-17 11:11:32 -10:00
J. Nick Koston
b6ef8eed78 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-17 11:11:22 -10:00
J. Nick Koston
3f892711c7 [core][opentherm] Add format_bin_to(), soft-deprecate format_bin() (#13232) 2026-01-17 11:09:42 -10:00
J. Nick Koston
caa86a4701 adl tests 2026-01-17 11:07:26 -10:00
J. Nick Koston
d49295ab18 Merge branch 'string_ref_triggers' into integration 2026-01-17 11:05:58 -10:00
J. Nick Koston
05dbc0035b handle conversion failure 2026-01-17 11:03:04 -10:00
J. Nick Koston
36e9febba1 bot comments, tidy 2026-01-17 11:01:45 -10:00
J. Nick Koston
1a18462279 Merge branch 'string_ref_triggers' into integration 2026-01-17 10:58:54 -10:00
J. Nick Koston
1dc4a5432f adl 2026-01-17 10:55:48 -10:00
J. Nick Koston
451447b0fc adl 2026-01-17 10:54:13 -10:00
J. Nick Koston
3cfca5228c bot review 2026-01-17 08:45:10 -10:00
J. Nick Koston
620667f9d8 bot review 2026-01-17 08:44:43 -10:00
J. Nick Koston
f3226b108f make sure new stringref functions work 2026-01-17 08:42:56 -10:00
J. Nick Koston
83d164c213 make sure new stringref functions work 2026-01-17 08:42:16 -10:00
J. Nick Koston
1550a6af72 make sure new stringref functions work 2026-01-17 08:42:11 -10:00
J. Nick Koston
18c3dd8af7 make sure new stringref functions work 2026-01-17 08:35:46 -10:00
J. Nick Koston
65cdb97f06 avoid breaking 2026-01-17 08:32:31 -10:00
J. Nick Koston
37025d62e0 [select][fan] Use StringRef for on_value/on_preset_set triggers to avoid heap allocation 2026-01-17 08:28:40 -10:00
J. Nick Koston
46d9c0be17 Merge branch 'mqtt_formatting' into integration 2026-01-17 07:52:05 -10:00
J. Nick Koston
86e70c7e76 more 2026-01-17 07:38:51 -10:00
J. Nick Koston
40025bb277 tweaks to reduce RAM 2026-01-17 07:34:22 -10:00
J. Nick Koston
438bb96687 tweaks to reduce RAM 2026-01-17 07:28:44 -10:00
J. Nick Koston
c1e1325af2 Merge branch 'dev' into mqtt_formatting 2026-01-17 07:24:11 -10:00
J. Nick Koston
c256066d3b Merge branch 'light_json_str_flash' into integration 2026-01-16 23:48:25 -10:00
J. Nick Koston
cd16ea9020 tidy 2026-01-16 23:48:15 -10:00
J. Nick Koston
27a5e1d276 Merge branch 'domain_equals_now_supports_flash_str' into integration 2026-01-16 23:36:18 -10:00
J. Nick Koston
4a92148f87 [web_server] Use ESPHOME_F for canHandle domain checks to reduce ESP8266 RAM 2026-01-16 23:35:45 -10:00
J. Nick Koston
115296efc1 Merge branch 'light_json_str_flash' into integration 2026-01-16 23:26:02 -10:00
J. Nick Koston
c3ab3835e4 [light] Store color mode JSON strings in flash on ESP8266 2026-01-16 23:23:03 -10:00
J. Nick Koston
6c53369232 Merge branch 'str_endswith_ignore_case' into integration 2026-01-16 22:57:31 -10:00
J. Nick Koston
d45443d680 Merge branch 'str_equals_case_insensitive_overloads' into integration 2026-01-16 22:57:16 -10:00
J. Nick Koston
6882a82d23 [core] Add str_endswith_ignore_case to avoid heap allocation in audio file type detection 2026-01-16 22:52:49 -10:00
J. Nick Koston
7f5d3894ad remove 2026-01-16 22:49:00 -10:00
J. Nick Koston
1facf851b0 wip 2026-01-16 22:47:33 -10:00
J. Nick Koston
4f48d65700 Merge branch 'weikai_buf' into integration 2026-01-16 22:27:02 -10:00
J. Nick Koston
ee93e68c6f merge 2026-01-16 22:26:31 -10:00
J. Nick Koston
dd3ac71364 Merge branch 'dev' of https://github.com/esphome/esphome into weikai_buf 2026-01-16 22:26:19 -10:00
J. Nick Koston
efef4dad55 Merge branch 'weikai_buf' into integration 2026-01-16 22:25:03 -10:00
J. Nick Koston
fcccd1fc85 merge 2026-01-16 22:24:48 -10:00
J. Nick Koston
8b0b98653e Merge remote-tracking branch 'upstream/dev' into integration 2026-01-16 22:05:22 -10:00
Jonathan Swoboda
798d3bd956 Merge branch 'beta' into dev 2026-01-16 23:45:36 -05:00
Jonathan Swoboda
77df3933db Merge pull request #13309 from esphome/bump-2026.1.0b3
2026.1.0b3
2026-01-16 23:45:26 -05:00
Jonathan Swoboda
19514ccdf4 Bump version to 2026.1.0b3 2026-01-16 23:05:59 -05:00
Mike Ford
2947642ca5 [http_request] Unable to handle chunked responses (#7884)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-16 23:05:59 -05:00
Stuart Parmenter
60e333db08 [hub75] Bump esp-hub75 version to 0.3.0 (#13243) 2026-01-16 23:05:59 -05:00
J. Nick Koston
d8463f4813 [hmac_sha256] Replace unsafe sprintf with format_hex_to (#13290) 2026-01-16 23:05:59 -05:00
mrtoy-me
e1800d2fe2 [ntc, resistance] change log level to verbose (#13268) 2026-01-16 23:05:59 -05:00
J. Nick Koston
50aa4b1992 [esp32_ble_client] Reduce GATT data event logging to prevent firmware update failures (#13252) 2026-01-16 23:05:59 -05:00
J. Nick Koston
edb303e495 [api] Fix clock conflicts when multiple clients connected to homeassistant time (#13253) 2026-01-16 23:05:59 -05:00
J. Nick Koston
973fc4c5dc [dallas_temp] Use const char* for set_timeout to fix deprecation warning and heap churn (#13250) 2026-01-16 23:05:59 -05:00
J. Nick Koston
f88e8fc43b [sprinkler] Fix scheduler deprecation warnings and heap churn with FixedVector (#13251) 2026-01-16 23:05:59 -05:00
Jonathan Swoboda
d830787c71 Merge branch 'release' into dev 2026-01-16 22:49:39 -05:00
Jonathan Swoboda
c4c31a2e8e Merge branch 'release' into beta 2026-01-16 22:49:38 -05:00
Jonathan Swoboda
e6790f0042 Merge pull request #13308 from esphome/bump-2025.12.7
2025.12.7
2026-01-16 22:49:26 -05:00
Jonathan Swoboda
ec7f72e280 Bump version to 2025.12.7 2026-01-16 22:24:05 -05:00
J. Nick Koston
6f29dbd6f1 [api] Use subtraction for protobuf bounds checking (#13306) 2026-01-16 22:24:05 -05:00
Kevin Ahrendt
9caf78aa7e [i2s_audio] Bugfix: Buffer overflow in software volume control (#13190) 2026-01-16 22:24:05 -05:00
Mike Ford
1f4221abfa [http_request] Unable to handle chunked responses (#7884)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-16 22:18:48 -05:00
Stuart Parmenter
92808a09c7 [hub75] Bump esp-hub75 version to 0.3.0 (#13243) 2026-01-16 22:17:36 -05:00
J. Nick Koston
e54d5ee898 [hmac_sha256] Replace unsafe sprintf with format_hex_to (#13290) 2026-01-16 22:16:38 -05:00
J. Nick Koston
bbe1155518 [web_server] Skip defer on ESP8266 where callbacks already run in main loop (#13261) 2026-01-16 20:08:04 -06:00
J. Nick Koston
69d7b6e921 [api] Use subtraction for protobuf bounds checking (#13306) 2026-01-16 15:46:15 -10:00
Keith Burzinski
510c874061 [helpers] Remove base85 functions (#13266) 2026-01-17 01:23:41 +00:00
J. Nick Koston
666fdcfbdf Merge branch 'proto_bounds_check_fix' into integration 2026-01-16 15:15:13 -10:00
J. Nick Koston
1d61530a07 cast 2026-01-16 15:14:42 -10:00
J. Nick Koston
8d2f9f7696 [api] Use subtraction for protobuf bounds checking 2026-01-16 15:04:28 -10:00
J. Nick Koston
d2bece9521 Merge branch 'proto_bounds_check_fix' into integration 2026-01-16 14:59:59 -10:00
J. Nick Koston
20baa43aa2 fix 2026-01-16 14:49:16 -10:00
J. Nick Koston
bcc8351d65 proto 2026-01-16 14:42:47 -10:00
Keith Burzinski
f7ad324d81 [infrared, remote_base] Replace base85 with base64url for web server infrared transmissions (#13265) 2026-01-16 18:15:27 -06:00
J. Nick Koston
0c4a3c70de Merge branch 'ezo_pmp' into integration 2026-01-16 14:10:20 -10:00
J. Nick Koston
0390c3a8a6 [ezo_pmp] Replace sprintf with bounds-checked snprintf 2026-01-16 14:09:47 -10:00
J. Nick Koston
bcc53faaf3 Merge branch 'anova_safety' into integration 2026-01-16 14:07:18 -10:00
J. Nick Koston
8515658008 [anova] Replace sprintf with bounds-checked alternatives 2026-01-16 14:06:55 -10:00
J. Nick Koston
d274723a1d Merge branch 'sprintf_group_2' into integration 2026-01-16 14:02:25 -10:00
J. Nick Koston
b7983b4774 [am43][lightwaverf][rf_bridge][spi_led_strip] Replace sprintf with safe alternatives 2026-01-16 14:01:48 -10:00
J. Nick Koston
0d329f4f4d [am43][lightwaverf][rf_bridge][spi_led_strip] Replace sprintf with safe alternatives 2026-01-16 14:00:30 -10:00
J. Nick Koston
60d48d6a58 [am43][lightwaverf][rf_bridge][spi_led_strip] Replace sprintf with safe alternatives 2026-01-16 13:57:32 -10:00
J. Nick Koston
526bd58d1c Update esphome/components/sim800l/sim800l.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 13:57:09 -10:00
J. Nick Koston
1ed478fd5f Update esphome/components/pipsolar/output/pipsolar_output.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 13:57:04 -10:00
J. Nick Koston
04fc533b78 Merge branch 'sprintf_group' into integration 2026-01-16 13:52:51 -10:00
J. Nick Koston
f9d9136415 [dfrobot_sen0395][pipsolar][sim800l][wl_134] Replace sprintf with snprintf/buf_append_printf 2026-01-16 13:52:19 -10:00
J. Nick Koston
b259b6c428 Merge branch 'ccs811_sprintf' into integration 2026-01-16 13:48:39 -10:00
J. Nick Koston
84fa55376f [ccs811] Use buf_append_printf for buffer safety and ESP8266 flash optimization 2026-01-16 13:48:01 -10:00
J. Nick Koston
f4505c4353 Merge branch 'weikai_buf' into integration 2026-01-16 13:43:43 -10:00
J. Nick Koston
4ca66ec07f Merge branch 'mapping_debug' into integration 2026-01-16 13:33:41 -10:00
J. Nick Koston
befe5d3bd2 bot review 2026-01-16 13:32:31 -10:00
J. Nick Koston
bdabbdaaea bot review 2026-01-16 13:31:30 -10:00
J. Nick Koston
90989aa7cd bot review 2026-01-16 13:30:27 -10:00
J. Nick Koston
72ebee5267 bot review 2026-01-16 13:28:51 -10:00
J. Nick Koston
b4855deba2 Merge branch 'mapping_debug' into integration 2026-01-16 13:27:27 -10:00
J. Nick Koston
52bbd7b37d Merge branch 'tx20_heap_heap_heap' into integration 2026-01-16 13:27:23 -10:00
J. Nick Koston
4d26eeaf75 copilot found a bug, its not new though 2026-01-16 13:26:56 -10:00
J. Nick Koston
648a40de7b [mapping] Use stack buffers for numeric key error logging 2026-01-16 13:23:05 -10:00
J. Nick Koston
73fcaea393 Merge branch 'tx20_heap_heap_heap' into integration 2026-01-16 13:19:13 -10:00
J. Nick Koston
7d6b95f535 cleanup 2026-01-16 13:19:05 -10:00
J. Nick Koston
bea4bae4d6 Merge branch 'tx20_heap_heap_heap' into integration 2026-01-16 13:16:11 -10:00
J. Nick Koston
9c0eccd81b [tx20] Eliminate heap allocations in wind sensor 2026-01-16 13:15:31 -10:00
J. Nick Koston
97e1a58787 [weikai] Replace bitset to_string with format_bin_to 2026-01-16 13:05:27 -10:00
Keith Burzinski
58a9e30017 [helpers] Add base64_decode_int32_vector function (#13289)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-16 23:05:19 +00:00
J. Nick Koston
52ac9e1861 [remote_base] Replace unsafe sprintf with buf_append_printf; fix buffer overflow (#13257)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 16:56:47 -06:00
J. Nick Koston
99f0962665 Merge branch 'toshiba_strings' into integration 2026-01-16 12:51:47 -10:00
J. Nick Koston
94f4619101 weak 2026-01-16 12:50:39 -10:00
J. Nick Koston
0e0f6cc2c9 [toshiba] Replace to_string with stack buffer in debug logging 2026-01-16 12:49:15 -10:00
J. Nick Koston
ca9ea0187e Merge branch 'nextion_strings' into integration 2026-01-16 12:45:24 -10:00
J. Nick Koston
45dbbb215f [nextion] Replace to_string with stack buffer and fix unsafe sprintf 2026-01-16 12:44:29 -10:00
J. Nick Koston
bc9487aee5 Merge branch 'uart_debug' into integration 2026-01-16 12:40:04 -10:00
J. Nick Koston
3d6a4faf90 one more 2026-01-16 12:39:22 -10:00
J. Nick Koston
a9b0b0fe70 Merge branch 'wiegand_to_string' into integration 2026-01-16 12:37:38 -10:00
J. Nick Koston
bc2d37193a [wiegand] Replace heap-allocating to_string with stack buffers 2026-01-16 12:36:28 -10:00
J. Nick Koston
c1209313b4 Merge branch 'tuya_light_safe' into integration 2026-01-16 12:26:02 -10:00
J. Nick Koston
7ce5e2c734 [tuya] Replace unsafe sprintf with snprintf in light color formatting 2026-01-16 12:25:25 -10:00
J. Nick Koston
a033817ae9 Merge branch 'rc522_spi_sprintf' into integration 2026-01-16 12:21:42 -10:00
J. Nick Koston
705c8a3902 Merge branch 'hmac_sha256' into integration 2026-01-16 12:21:28 -10:00
J. Nick Koston
f9a605e60d fix merge 2026-01-16 12:17:59 -10:00
J. Nick Koston
3018849508 [rc522_spi] Replace unsafe sprintf with buf_append_printf 2026-01-16 12:16:30 -10:00
J. Nick Koston
12f88b877d Merge branch 'hmac_sha256' into integration 2026-01-16 12:12:51 -10:00
J. Nick Koston
44191ed41f [hmac_sha256] Replace unsafe sprintf with format_hex_to 2026-01-16 12:09:02 -10:00
J. Nick Koston
d3e684815f Merge branch 'uart_debug' into integration 2026-01-16 12:02:24 -10:00
J. Nick Koston
c28f68b6fa [uart] Replace unsafe sprintf with buf_append_printf in debugger 2026-01-16 12:01:59 -10:00
J. Nick Koston
04fc02a545 Merge branch 'tormatic' into integration 2026-01-16 11:57:01 -10:00
J. Nick Koston
cb023aad4e tweak 2026-01-16 11:56:48 -10:00
J. Nick Koston
24127c84a7 Merge remote-tracking branch 'upstream/dev' into tormatic 2026-01-16 11:56:04 -10:00
J. Nick Koston
0208ece006 Merge branch 'syslog_snprintf' into integration 2026-01-16 11:54:40 -10:00
J. Nick Koston
e63cd9a56d Merge branch 'cse7766_stack_debug' into integration 2026-01-16 11:51:16 -10:00
J. Nick Koston
f41ebf831d tweak 2026-01-16 11:50:15 -10:00
J. Nick Koston
91e5191c67 Merge branch 'dev' into cse7766_stack_debug 2026-01-16 11:49:52 -10:00
J. Nick Koston
22882abbe7 cleanup 2026-01-16 11:47:55 -10:00
J. Nick Koston
bfac86b547 Merge branch 'syslog_snprintf' into integration 2026-01-16 11:43:30 -10:00
J. Nick Koston
88e1295e2f [syslog] Use buf_append_printf for ESP8266 flash optimization 2026-01-16 11:43:05 -10:00
J. Nick Koston
c1dc79618d Merge branch 'statsd_stack' into integration 2026-01-16 11:36:33 -10:00
J. Nick Koston
5934b88d2e Merge remote-tracking branch 'upstream/dev' into statsd_stack 2026-01-16 11:35:55 -10:00
J. Nick Koston
5ce4b0c445 tweak 2026-01-16 11:35:52 -10:00
Clyde Stubbs
c5e4a60884 [select] Add condition for testing select option (#13267)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-01-17 08:35:40 +11:00
J. Nick Koston
fc5917c243 Merge branch 'homeassistant_number_snprintf' into integration 2026-01-16 11:32:53 -10:00
J. Nick Koston
075364f4b4 [homeassistant] Use buf_append_printf for ESP8266 flash optimization 2026-01-16 11:32:26 -10:00
J. Nick Koston
17412a4af5 Merge branch 'esp8266_gpio' into integration 2026-01-16 11:30:17 -10:00
J. Nick Koston
d7823f3e49 [gpio] Use buf_append_printf in dump_summary for ESP8266 flash optimization 2026-01-16 11:29:22 -10:00
J. Nick Koston
3b4dd3eaec Merge branch 'uptime_text_sensor' into integration 2026-01-16 11:27:06 -10:00
J. Nick Koston
0699ecbd19 [uptime] Use buf_append_printf for ESP8266 flash optimization 2026-01-16 11:26:43 -10:00
J. Nick Koston
364ba0b371 Merge branch 'web_server_simplify_snprintf' into integration 2026-01-16 11:21:59 -10:00
J. Nick Koston
d6181982e8 [web_server] Simplify datetime formatting with buf_append_printf 2026-01-16 11:21:30 -10:00
J. Nick Koston
9db1cc6882 Merge branch 'daikin_arc_sprintf' into integration 2026-01-16 11:18:25 -10:00
J. Nick Koston
f580fef9d4 Update esphome/components/daikin_arc/daikin_arc.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-16 11:17:43 -10:00
J. Nick Koston
355697e377 [daikin_arc] Fix undefined behavior in sprintf calls 2026-01-16 11:13:51 -10:00
J. Nick Koston
6655a1c19e Merge remote-tracking branch 'upstream/dev' into integration 2026-01-16 10:29:28 -10:00
dependabot[bot]
a680884138 Bump ruff from 0.14.12 to 0.14.13 (#13275)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-16 20:29:02 +00:00
Jonathan Swoboda
6832efbacc Add Claude Code PR workflow skill (#13271)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 10:24:28 -10:00
dependabot[bot]
3057a0484f Bump actions/cache from 5.0.1 to 5.0.2 in /.github/actions/restore-python (#13277)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-16 09:36:42 -10:00
dependabot[bot]
bc78f80f77 Bump actions/cache from 5.0.1 to 5.0.2 (#13276)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-16 09:36:29 -10:00
J. Nick Koston
916b028fb2 [mqtt] Replace sprintf with snprintf for friendly name hash (#13262) 2026-01-16 08:30:22 -10:00
mrtoy-me
16adae7359 [ntc, resistance] change log level to verbose (#13268) 2026-01-16 10:19:09 -05:00
Remco van Essen
4906f87751 [mipi_dsi] add JC8012P4A1 (#13241) 2026-01-16 21:17:32 +11:00
Keith Burzinski
5b37d2fb27 [helpers] Support base64url encoding (#13264) 2026-01-16 08:55:24 +00:00
J. Nick Koston
3c75454c97 Merge branch 'mqtt_snprintf' into integration 2026-01-15 19:14:19 -10:00
J. Nick Koston
638de5da46 [mqtt] Replace sprintf with snprintf for friendly name hash 2026-01-15 19:13:24 -10:00
J. Nick Koston
f24f4331ba Merge remote-tracking branch 'upstream/buf_append' into integration 2026-01-15 19:02:23 -10:00
J. Nick Koston
b3570a9bfd Merge remote-tracking branch 'upstream/avoid_prefs_heap_churn' into integration 2026-01-15 19:02:18 -10:00
J. Nick Koston
73eff47998 Merge remote-tracking branch 'upstream/debug_cleanup_buf' into integration 2026-01-15 19:02:13 -10:00
J. Nick Koston
ac2cb8b3b3 Merge remote-tracking branch 'upstream/esp8266_web_server_defer' into integration 2026-01-15 19:02:07 -10:00
J. Nick Koston
68affe0b9c [core] Add --device hint when DNS resolution fails (#13240) 2026-01-15 18:55:32 -10:00
J. Nick Koston
98b8fa2260 [web_server] Skip defer on ESP8266 where callbacks already run in main loop 2026-01-15 18:49:07 -10:00
J. Nick Koston
5f57c6bb82 Update esphome/components/remote_base/aeha_protocol.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-15 18:34:15 -10:00
J. Nick Koston
3926d3a09d remove debug changes 2026-01-15 18:26:59 -10:00
J. Nick Koston
fd33087b3f merge 2026-01-15 18:26:17 -10:00
J. Nick Koston
7c09985300 Merge remote-tracking branch 'upstream/dev' into buf_append 2026-01-15 18:25:54 -10:00
J. Nick Koston
6812654435 [debug] Use shared buf_append_printf helper from core 2026-01-15 18:24:19 -10:00
J. Nick Koston
42b9863cd3 bot concerns 2026-01-15 18:19:15 -10:00
J. Nick Koston
9bdefc98b1 bot concerns 2026-01-15 18:17:42 -10:00
J. Nick Koston
2db4e15452 Merge branch 'dev' into avoid_prefs_heap_churn 2026-01-15 18:09:37 -10:00
J. Nick Koston
8263a8273f [debug] Add min_free heap sensor for ESP32 and LibreTiny, add fragmentation for ESP32 (#13231) 2026-01-15 18:08:26 -10:00
J. Nick Koston
530df75b43 Merge branch 'avoid_prefs_heap_churn' into integration 2026-01-15 18:05:47 -10:00
Keith Burzinski
14b7539094 [infrared, remote_base] Optimize IR transmit path for web_server base85 data (#13238) 2026-01-15 22:04:21 -06:00
J. Nick Koston
7641c36c95 [preferences] Reduce heap churn with small inline buffer optimization 2026-01-15 18:03:44 -10:00
Keith Burzinski
73d0d7b129 Merge branch 'dev' into buf_append 2026-01-15 22:03:18 -06:00
J. Nick Koston
b37cb812a7 [core] Add buf_append_printf helper for safe buffer formatting (#13258) 2026-01-15 22:03:11 -06:00
J. Nick Koston
42491569c8 [analyze_memory] Add nRF52/Zephyr platform support for memory analysis (#13249) 2026-01-15 17:53:53 -10:00
J. Nick Koston
a8f937adf1 Merge remote-tracking branch 'origin/libretiny_heap_debug' into integration 2026-01-15 17:05:55 -10:00
J. Nick Koston
b1230ec6bb [esp32_ble_client] Reduce GATT data event logging to prevent firmware update failures (#13252) 2026-01-15 16:49:19 -10:00
J. Nick Koston
4eda9e965f [api] Fix clock conflicts when multiple clients connected to homeassistant time (#13253) 2026-01-15 16:49:01 -10:00
J. Nick Koston
d2528af649 [dallas_temp] Use const char* for set_timeout to fix deprecation warning and heap churn (#13250) 2026-01-15 16:48:44 -10:00
J. Nick Koston
60da5587d1 tweak validators 2026-01-15 16:47:58 -10:00
J. Nick Koston
422ed5e125 tweak validators 2026-01-15 16:46:27 -10:00
J. Nick Koston
4213ed6e91 [core] Add buf_append_printf helper and fix unsafe sprintf in remote_base 2026-01-15 16:26:33 -10:00
Keith Burzinski
2eabc1b96b [helpers] Add base85 support (#13254)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-16 02:22:05 +00:00
J. Nick Koston
00b805344c Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:53:07 -10:00
J. Nick Koston
9ee808e917 tweak 2026-01-15 13:52:54 -10:00
J. Nick Koston
0e584ef8d1 Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:48:25 -10:00
J. Nick Koston
a5267e6bfe tweak 2026-01-15 13:48:12 -10:00
J. Nick Koston
175378774b Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:25:15 -10:00
J. Nick Koston
bf8f3d7076 better handle 2038 2026-01-15 13:22:15 -10:00
J. Nick Koston
fe15b3e706 better handle 2038 2026-01-15 13:21:59 -10:00
J. Nick Koston
e4a193a8f9 Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:19:34 -10:00
J. Nick Koston
f2ff04f685 comment 2026-01-15 13:19:22 -10:00
J. Nick Koston
58ad49ec0a comment 2026-01-15 13:19:11 -10:00
J. Nick Koston
df260b13ab Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:15:59 -10:00
J. Nick Koston
8861abea73 avoid clock churn 2026-01-15 13:14:22 -10:00
J. Nick Koston
9a0ce98d8b Merge branch 'conflicting_clocks_when_logging' into integration 2026-01-15 13:06:47 -10:00
J. Nick Koston
357542960d [api] Fix clock conflicts when multiple clients connected to homeassistant time 2026-01-15 13:05:50 -10:00
J. Nick Koston
1cae3a2387 Merge branch 'fix_firmware_update_failing_with_bluetooth_proxy_from_logging' into integration 2026-01-15 11:50:28 -10:00
J. Nick Koston
0109e4b9e5 [esp32_ble_client] Reduce GATT data event logging to prevent firmware update failures 2026-01-15 11:49:06 -10:00
J. Nick Koston
3259c5ef03 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-15 11:33:33 -10:00
J. Nick Koston
535c3eb2a2 [sprinkler] Fix scheduler deprecation warnings and heap churn with FixedVector (#13251) 2026-01-15 11:32:02 -10:00
Jonathan Swoboda
20f937692e Merge branch 'beta' into dev 2026-01-15 16:24:19 -05:00
Jonathan Swoboda
c2737ca3bb Merge pull request #13247 from esphome/bump-2026.1.0b2
2026.1.0b2
2026-01-15 16:24:08 -05:00
J. Nick Koston
0ed7570a92 Merge branch 'nrf52_memory_impact' into integration 2026-01-15 11:10:37 -10:00
J. Nick Koston
2beedc903b Merge branch 'dallas_temp_heap_churn_timer' into integration 2026-01-15 11:09:03 -10:00
J. Nick Koston
8f8e450d29 Merge branch 'sprinkler_schedule_heap_churn_fix' into integration 2026-01-15 11:08:59 -10:00
J. Nick Koston
eff91f85dd [sprinkler] Fix scheduler deprecation warnings and heap churn with FixedVector 2026-01-15 11:05:11 -10:00
J. Nick Koston
1542a01b77 [dallas_temp] Use const char* for set_timeout to fix deprecation warning and heap churn 2026-01-15 10:55:05 -10:00
J. Nick Koston
19fb23823b [analyze_memory] Add nRF52/Zephyr platform support for memory analysis 2026-01-15 10:47:50 -10:00
J. Nick Koston
00cc9e44b6 [analyze_memory] Fix ELF section mapping for RTL87xx and LN882X platforms (#13213) 2026-01-15 10:38:24 -10:00
Jonathan Swoboda
c151b2da67 Bump version to 2026.1.0b2 2026-01-15 15:26:04 -05:00
J. Nick Koston
dacd185afb [web_server][captive_portal] Change default compression from Brotli to gzip (#13246) 2026-01-15 15:26:04 -05:00
John Stenger
f88cf1b83a [qr_code] Allocate and free memory for QR code buffer (#13161)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-15 15:26:04 -05:00
Jonathan Swoboda
3f6412ba07 [safe_mode] Detect bootloader rollback support at runtime (#13230)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 15:26:04 -05:00
J. Nick Koston
1ad0969099 [core] Fix ESP32-S2/S3 hardware SHA crash by aligning HashBase digest buffer (#13234)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-01-15 15:26:04 -05:00
J. Nick Koston
737c2b8732 [core] Fix platform subcomponents not filtering source files (#13208) 2026-01-15 15:26:04 -05:00
J. Nick Koston
9030dc9d4e [api] Fix state updates being sent to clients that did not subscribe (#13237) 2026-01-15 15:26:04 -05:00
J. Nick Koston
0b5a3506cc [core] Optimize and normalize entity state publishing logs with >> format (#13236) 2026-01-15 15:26:04 -05:00
Clyde Stubbs
3c63ff5e36 [image] Correctly handle dimensions in physical units (#13209) 2026-01-15 15:26:04 -05:00
J. Nick Koston
4e28b0179b Merge remote-tracking branch 'origin/integration' into integration 2026-01-15 10:05:38 -10:00
J. Nick Koston
3da1fd6b5d Merge remote-tracking branch 'upstream/dev' into integration 2026-01-15 10:05:25 -10:00
dependabot[bot]
0427350101 Bump ruff from 0.14.11 to 0.14.12 (#13244)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-15 09:59:40 -10:00
J. Nick Koston
41dceb76ec [web_server][captive_portal] Change default compression from Brotli to gzip (#13246) 2026-01-15 19:56:35 +00:00
J. Nick Koston
b4dfcc8378 Merge branch 'back_to_gzip' into integration 2026-01-15 09:42:45 -10:00
J. Nick Koston
18054c358e [web_server][captive_portal] Change default compression from Brotli to gzip 2026-01-15 09:36:44 -10:00
J. Nick Koston
302526f148 [web_server][captive_portal] Change default compression from Brotli to gzip 2026-01-15 09:36:32 -10:00
John Stenger
6380458d78 [qr_code] Allocate and free memory for QR code buffer (#13161)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-15 14:18:08 -05:00
Jonathan Swoboda
0dc5a7c9a4 [safe_mode] Detect bootloader rollback support at runtime (#13230)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:17:00 -05:00
J. Nick Koston
ca0bbe8a17 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-15 09:09:22 -10:00
J. Nick Koston
9003844eda [core] Fix ESP32-S2/S3 hardware SHA crash by aligning HashBase digest buffer (#13234)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-01-15 18:29:11 +00:00
J. Nick Koston
22a4ec69c2 [core] Fix platform subcomponents not filtering source files (#13208) 2026-01-15 07:38:44 -10:00
J. Nick Koston
9d42bfd161 [api] Fix state updates being sent to clients that did not subscribe (#13237) 2026-01-15 07:38:18 -10:00
J. Nick Koston
49c881d067 [core] Optimize and normalize entity state publishing logs with >> format (#13236) 2026-01-15 10:13:05 +00:00
J. Nick Koston
a7a4746537 Merge branch 'fix_state_sub_check' into integration 2026-01-14 23:26:52 -10:00
J. Nick Koston
682a47aa3c [api] Fix state updates being sent to clients that did not subscribe 2026-01-14 23:22:47 -10:00
J. Nick Koston
1bb5ad26e1 Merge branch 'normalize_state_send' into integration 2026-01-14 22:47:45 -10:00
J. Nick Koston
f40e4825c7 preen 2026-01-14 22:39:04 -10:00
J. Nick Koston
09f35147e7 Merge branch 'normalize_state_send' into integration 2026-01-14 22:34:02 -10:00
J. Nick Koston
142fb85ff0 more 2026-01-14 22:32:12 -10:00
J. Nick Koston
4cf0e2ef0d more 2026-01-14 22:30:16 -10:00
J. Nick Koston
a8e3aa89ff Merge branch 'normalize_state_send' into integration 2026-01-14 22:28:46 -10:00
J. Nick Koston
b28fda6899 [core] Optimize and normalize entity state publishing logs with >> format 2026-01-14 22:24:57 -10:00
J. Nick Koston
283a654beb Merge remote-tracking branch 'upstream/dev' into integration 2026-01-14 19:58:33 -10:00
J. Nick Koston
78aee4f498 [web_server] Remove unused button_state_json_generator (#13235) 2026-01-14 23:48:55 -06:00
J. Nick Koston
aa28bf29ce Merge branch 'sha256_align_buffer' into integration 2026-01-14 19:41:06 -10:00
J. Nick Koston
b1fd69a2f5 limit scope 2026-01-14 19:40:57 -10:00
J. Nick Koston
9296fc8d4a limit scope 2026-01-14 19:40:21 -10:00
J. Nick Koston
46d4c4bf3d limit scope 2026-01-14 19:36:51 -10:00
J. Nick Koston
580a3d5594 Merge branch 'button_is_stateless' into integration 2026-01-14 19:33:39 -10:00
J. Nick Koston
a1b1fdaad7 [web_server] Remove unused button_state_json_generator 2026-01-14 19:33:19 -10:00
J. Nick Koston
ec3b419692 Merge branch 'sha256_align_buffer' into integration 2026-01-14 19:17:10 -10:00
J. Nick Koston
6625e52842 [core] Fix ESP32-S2/S3 hardware SHA crash by aligning HashBase digest buffer 2026-01-14 19:11:10 -10:00
J. Nick Koston
0acbe48965 Merge branch 'str_sanitize_to' into integration 2026-01-14 17:50:16 -10:00
J. Nick Koston
bbd8d90cbe .c_str() 2026-01-14 17:46:05 -10:00
J. Nick Koston
3b90a8f210 .c_str() 2026-01-14 17:46:04 -10:00
J. Nick Koston
76082b3eb9 [core][mqtt] Add str_sanitize_to(), soft-deprecate str_sanitize() 2026-01-14 17:43:03 -10:00
J. Nick Koston
114e7d34cc Merge branch 'dep_format_bin' into integration 2026-01-14 17:37:18 -10:00
J. Nick Koston
6e3241fe79 bot comments 2026-01-14 17:36:41 -10:00
J. Nick Koston
c6ff6d268b safer 2026-01-14 17:35:36 -10:00
J. Nick Koston
d760a5dad3 [core][opentherm] Add format_bin_to(), soft-deprecate format_bin() 2026-01-14 17:28:00 -10:00
Clyde Stubbs
9da2c08f36 [image] Correctly handle dimensions in physical units (#13209) 2026-01-15 03:27:26 +00:00
J. Nick Koston
9e8c679c7f Merge branch 'libretiny_heap_debug' into integration 2026-01-14 17:15:41 -10:00
J. Nick Koston
767e1f88df appyl bot suggeations 2026-01-14 17:13:03 -10:00
J. Nick Koston
8560be69f2 Merge branch 'libretiny_heap_debug' into integration 2026-01-14 17:02:21 -10:00
J. Nick Koston
973576130b [debug] Add min_free heap sensor for ESP32 and LibreTiny, add fragmentation for ESP32 2026-01-14 16:57:44 -10:00
pre-commit-ci-lite[bot]
21507c570d [pre-commit.ci lite] apply automatic fixes 2026-01-15 02:29:46 +00:00
J. Nick Koston
6986bb4ef9 Merge branch 'modbus_string' into integration 2026-01-14 16:29:32 -10:00
J. Nick Koston
5b6be2c8d9 Update esphome/components/modbus_controller/text_sensor/modbus_textsensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 16:28:26 -10:00
J. Nick Koston
66e80fe13b Update esphome/components/modbus_controller/modbus_controller.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 16:28:16 -10:00
J. Nick Koston
f4ebdf94f1 Merge branch 'sockaddr_heap_fix' into integration 2026-01-14 16:20:47 -10:00
J. Nick Koston
dbb6e437cc Merge branch 'cse7766_stack_debug' into integration 2026-01-14 16:20:43 -10:00
J. Nick Koston
325a812202 tidy 2026-01-14 16:20:29 -10:00
J. Nick Koston
e7f3606ef6 [socket] Eliminate heap allocations in set_sockaddr() 2026-01-14 16:18:49 -10:00
J. Nick Koston
141f9cf7e7 Merge branch 'cse7766_stack_debug' into integration 2026-01-14 16:06:19 -10:00
J. Nick Koston
d49c06df35 Increase buffer to 128 bytes and improve docstrings 2026-01-14 16:04:22 -10:00
J. Nick Koston
0b676c0daa review 2026-01-14 16:02:42 -10:00
J. Nick Koston
d4bbad9ea2 Merge remote-tracking branch 'upstream/dev' into cse7766_stack_debug 2026-01-14 15:58:14 -10:00
J. Nick Koston
4befd86a96 review 2026-01-14 15:56:32 -10:00
J. Nick Koston
35a26b5b3d Merge branch 'str_sprintf' into integration 2026-01-14 15:48:29 -10:00
J. Nick Koston
06c619b2e0 [ci] Soft-deprecate str_sprintf/str_snprintf to prevent hidden heap allocations 2026-01-14 15:48:22 -10:00
J. Nick Koston
71c922bb60 [ci] Soft-deprecate str_sprintf/str_snprintf to prevent hidden heap allocations 2026-01-14 15:46:09 -10:00
J. Nick Koston
7bf6f48b75 Merge branch 'esp32_hosted_str_sprintf' into integration 2026-01-14 15:39:51 -10:00
J. Nick Koston
abba6e6db5 [esp32_hosted] Use stack buffer instead of str_sprintf for version string 2026-01-14 15:39:21 -10:00
J. Nick Koston
4473d35a0f Merge branch 'tormatic' into integration 2026-01-14 15:37:03 -10:00
J. Nick Koston
9cbee92589 [tormatic] Use stack buffers instead of str_sprintf in debug methods 2026-01-14 15:36:35 -10:00
J. Nick Koston
bc15349c59 Merge branch 'gdk101_heap_fix' into integration 2026-01-14 15:32:22 -10:00
J. Nick Koston
62eba4fa30 [gdk101] Use stack buffer to eliminate heap allocation for firmware version 2026-01-14 15:31:48 -10:00
J. Nick Koston
b2ddba7013 Merge branch 'statsd_stack' into integration 2026-01-14 15:29:13 -10:00
J. Nick Koston
0ea5d7abff [statsd] Use direct appends and stack buffer instead of str_sprintf 2026-01-14 15:27:04 -10:00
J. Nick Koston
03f3deff41 [lvgl] Use stack buffer for event code formatting, document justified str_sprintf usage (#13220)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2026-01-15 01:24:42 +00:00
J. Nick Koston
15ae96b7fe Merge branch 'sml_sprintf' into integration 2026-01-14 15:21:02 -10:00
J. Nick Koston
fc4f1ab094 [sml] Use stack buffers instead of str_sprintf 2026-01-14 15:20:33 -10:00
J. Nick Koston
bebb8f1ebd Merge branch 'modbus_string' into integration 2026-01-14 15:16:51 -10:00
J. Nick Koston
a50654ef4d [modbus_controller] Use stack buffers instead of str_sprintf/str_snprintf 2026-01-14 15:13:54 -10:00
J. Nick Koston
6d63f764e9 Merge branch 'lvgl_str_sprintf' into integration 2026-01-14 15:09:46 -10:00
J. Nick Koston
167eb24a63 [lvgl] Use stack buffer for event code formatting, document justified str_sprintf usage 2026-01-14 15:08:51 -10:00
J. Nick Koston
994ebac243 Merge branch 'dfrobot_sen0395' into integration 2026-01-14 14:54:17 -10:00
J. Nick Koston
bee4940947 Merge branch 'ezo_stack_format' into integration 2026-01-14 14:54:10 -10:00
J. Nick Koston
f5495e9d93 fix 2026-01-14 14:52:57 -10:00
J. Nick Koston
ce8e5b1a6b [dfrobot_sen0395] Reduce heap allocations in command building 2026-01-14 14:51:10 -10:00
J. Nick Koston
147d2aa384 Update esphome/components/ezo/ezo.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 14:50:54 -10:00
J. Nick Koston
6c02ca7900 Update esphome/components/ezo/ezo.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 14:50:42 -10:00
J. Nick Koston
fc18617e6a Merge branch 'ezo_stack_format' into integration 2026-01-14 14:46:22 -10:00
J. Nick Koston
63bff589c3 Merge branch 'cse7766_stack_debug' into integration 2026-01-14 14:46:16 -10:00
J. Nick Koston
e13743a9c3 tidy 2026-01-14 14:45:55 -10:00
J. Nick Koston
0515225437 [ezo] Replace str_sprintf with stack-based formatting 2026-01-14 14:44:29 -10:00
J. Nick Koston
3248722b9c Merge branch 'cse7766_stack_debug' into integration 2026-01-14 14:31:45 -10:00
J. Nick Koston
d3d96afbba tweak 2026-01-14 14:30:07 -10:00
J. Nick Koston
f5317a58be Merge branch 'cse7766_stack_debug' into integration 2026-01-14 14:05:53 -10:00
J. Nick Koston
6e77182523 [cse7766] Use stack buffer for verbose debug logging 2026-01-14 14:04:28 -10:00
pre-commit-ci-lite[bot]
944194e04e [pre-commit.ci lite] apply automatic fixes 2026-01-15 00:02:35 +00:00
J. Nick Koston
d27d6d64da Update esphome/components/mqtt/mqtt_component.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 14:00:57 -10:00
J. Nick Koston
85beae1292 Merge branch 'mqtt_formatting' into integration 2026-01-14 14:00:24 -10:00
J. Nick Koston
ea18159f3a Merge branch 'zephyr_prefs' into integration 2026-01-14 14:00:20 -10:00
J. Nick Koston
77fa1f1261 tweak comment 2026-01-14 13:59:36 -10:00
J. Nick Koston
2182d1e9f0 [mqtt] Use stack buffers for discovery message formatting 2026-01-14 13:57:45 -10:00
J. Nick Koston
79d3dbd374 Merge branch 'zephyr_prefs' into integration 2026-01-14 13:51:55 -10:00
J. Nick Koston
6b5fea9be9 [zephyr] Avoid heap allocation in preferences key formatting 2026-01-14 13:51:29 -10:00
J. Nick Koston
c663626000 Merge branch 'resize_to_erase_end' into integration 2026-01-14 13:38:48 -10:00
J. Nick Koston
d3c2ecdf68 erase is faster 2026-01-14 13:32:21 -10:00
J. Nick Koston
2cf58c2ef9 Merge branch 'libretiny_mapping' into integration 2026-01-14 13:21:27 -10:00
J. Nick Koston
20e28724a2 [analyze_memory] Fix ELF section mapping for RTL87xx and LN882X platforms 2026-01-14 13:20:12 -10:00
J. Nick Koston
4ecdc80164 [analyze_memory] Fix ELF section mapping for RTL87xx and LN882X platforms 2026-01-14 13:19:55 -10:00
J. Nick Koston
0b9a8d3302 Merge branch 'fix_filter' into integration 2026-01-14 12:47:52 -10:00
J. Nick Koston
12f7519f7f Merge remote-tracking branch 'upstream/dev' into integration 2026-01-14 12:46:10 -10:00
dependabot[bot]
f1e5d3a39a Bump resvg-py from 0.2.5 to 0.2.6 (#13211)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-14 10:40:26 -10:00
J. Nick Koston
e351c65c93 [core] Fix platform subcomponents not filtering source files 2026-01-14 07:30:56 -10:00
J. Nick Koston
ea4e714f62 [core] Fix platform subcomponents not filtering source files 2026-01-14 07:24:54 -10:00
Jonathan Swoboda
2f6863230d Merge branch 'beta' into dev 2026-01-14 10:52:28 -05:00
Jonathan Swoboda
0de91e6648 Merge pull request #13206 from esphome/bump-2026.1.0b1
2026.1.0b1
2026-01-14 10:52:13 -05:00
Jonathan Swoboda
f44036310c Bump version to 2026.2.0-dev 2026-01-14 09:19:45 -05:00
Jonathan Swoboda
66b4af1777 Bump version to 2026.1.0b1 2026-01-14 09:19:45 -05:00
J. Nick Koston
068b497b9b [web_server] Store method/domain comparison strings in flash on ESP8266 (#13205)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 09:18:17 -05:00
J. Nick Koston
d6fa1d6e5f [ethernet_info] Convert to event-driven IP state listener pattern (#13203)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 09:17:47 -05:00
J. Nick Koston
d5f557ad1c [scheduler] Eliminate heap allocations for std::string names and add uint32_t ID API (#13200) 2026-01-14 09:15:31 -05:00
J. Nick Koston
b58b2045f0 Merge remote-tracking branch 'origin/web_server_match_flash' into integration 2026-01-14 01:21:13 -10:00
J. Nick Koston
ee08953e5c [web_server] Store method/domain comparison strings in flash on ESP8266 2026-01-14 01:17:22 -10:00
tomaszduda23
9c5f4e5288 [usb_cdc_acm] move esp32 implementation to new file (#12824)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2026-01-14 04:07:18 -06:00
J. Nick Koston
49cae5eda8 Merge branch 'scheduler_no_heap' into integration 2026-01-13 22:39:53 -10:00
J. Nick Koston
5541a7f043 one more place to log 2026-01-13 22:36:37 -10:00
J. Nick Koston
1210512286 fix double dep warning 2026-01-13 22:33:32 -10:00
J. Nick Koston
c73a412537 tweaks 2026-01-13 22:30:17 -10:00
J. Nick Koston
4e2c635d14 no ram increase 2026-01-13 22:21:29 -10:00
J. Nick Koston
edde7194c9 no ram increase 2026-01-13 22:19:40 -10:00
J. Nick Koston
bf6d75fd5e fix 2026-01-13 22:08:57 -10:00
J. Nick Koston
38c5421d54 name log 2026-01-13 21:56:06 -10:00
J. Nick Koston
25b7d1ea15 minimize diff 2026-01-13 21:50:03 -10:00
J. Nick Koston
4520f7f646 minimize diff 2026-01-13 21:47:27 -10:00
J. Nick Koston
ba36934f91 minimize diff 2026-01-13 21:46:19 -10:00
J. Nick Koston
16d7342772 cleanup 2026-01-13 21:37:24 -10:00
J. Nick Koston
c8fcc258c3 cleanup 2026-01-13 21:32:24 -10:00
J. Nick Koston
42f98ebc80 [scheduler] Eliminate heap allocations for std::string names and add uint32_t ID API 2026-01-13 20:16:59 -10:00
J. Nick Koston
c8cc29a991 [api] Reduce batch RAM usage by 33% via switch dispatch (#13199) 2026-01-14 03:58:06 +00:00
J. Nick Koston
8b49d465f8 [bh1750] Eliminate heap allocations by replacing callbacks with state machine (#11950) 2026-01-13 17:44:43 -10:00
J. Nick Koston
0a25eae420 Merge branch 'reduce_batch_size' into integration 2026-01-13 17:17:25 -10:00
J. Nick Koston
52088009e4 bot comment 2026-01-13 17:16:41 -10:00
J. Nick Koston
44f9e8507a safety 2026-01-13 17:12:03 -10:00
J. Nick Koston
02b2d4f1a2 fix events 2026-01-13 17:05:45 -10:00
J. Nick Koston
23e6a9a27a narrow 2026-01-13 17:04:50 -10:00
J. Nick Koston
f027b32c18 fix events 2026-01-13 17:00:43 -10:00
J. Nick Koston
54665edd18 use push_back, generates much simpler code for pod types 2026-01-13 16:57:34 -10:00
J. Nick Koston
5580d11a2e tweak 2026-01-13 16:53:41 -10:00
J. Nick Koston
a3061a7488 [api] Reduce BatchItem size from 12 to 8 bytes using switch dispatch 2026-01-13 16:47:55 -10:00
J. Nick Koston
47ee2f4ad9 [wifi] Use StaticVector for WiFi listeners with per-type compile-time sizing (#13197) 2026-01-14 02:20:39 +00:00
J. Nick Koston
2efc51b28c Merge remote-tracking branch 'upstream/dev' into integration 2026-01-13 15:46:38 -10:00
J. Nick Koston
2793e33baf [logger] Use StaticVector for log listeners with compile-time sizing (#13196)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 15:43:17 -10:00
J. Nick Koston
5dfdd05122 [logger] Use RAII guards for recursion protection and optimize hot path (#13194)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 15:43:02 -10:00
J. Nick Koston
316b41710c Merge remote-tracking branch 'origin/request_log_listener' into integration 2026-01-13 14:28:14 -10:00
J. Nick Koston
32fe66c2ae Merge branch 'wifi_listeners_static_vector' into integration 2026-01-13 14:28:04 -10:00
J. Nick Koston
ad64a1b7b4 document, document, documet 2026-01-13 14:21:35 -10:00
J. Nick Koston
9567046e9c [wifi] Use StaticVector for WiFi listeners with per-type compile-time sizing 2026-01-13 14:20:04 -10:00
J. Nick Koston
e01e616aad address bot comments 2026-01-13 14:18:58 -10:00
J. Nick Koston
52574e2fd4 Update esphome/components/logger/__init__.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 14:12:48 -10:00
J. Nick Koston
3f3d2b3df2 Merge branch 'request_log_listener' into integration 2026-01-13 14:00:40 -10:00
J. Nick Koston
1d2fa12911 [logger] Use StaticVector for log listeners with compile-time sizing 2026-01-13 13:59:37 -10:00
J. Nick Koston
bc035e06fd Merge branch 'logger_raii' into integration 2026-01-13 13:40:25 -10:00
J. Nick Koston
6ed7412634 Update esphome/components/logger/logger.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 13:36:18 -10:00
J. Nick Koston
fdb7b800df Update esphome/components/logger/logger.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-13 13:36:12 -10:00
J. Nick Koston
c2c616a2ec Merge branch 'logger_raii' into integration 2026-01-13 13:34:48 -10:00
Cougar
be12e3667a [ssd1306_i2c] fix "SSD1306 72x40" display initialization (add SSD1306B Iref setup) (#13148) 2026-01-13 18:30:15 -05:00
J. Nick Koston
421646030b Merge branch 'dev' into logger_raii 2026-01-13 13:29:24 -10:00
Clyde Stubbs
52c631384a [epaper_spi] Add Waveshare 2.13v3 (#13117) 2026-01-13 18:28:24 -05:00
Jonathan Swoboda
45e000f091 [ota] Mark partition valid when OTA begins to prevent rollback blocking (#13195)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 18:27:45 -05:00
tomaszduda23
e45cad45fe [nrf52,zigbee] Add binary output as switch (#13083)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-13 17:39:28 -05:00
J. Nick Koston
f852fb4300 tweak 2026-01-13 12:14:49 -10:00
J. Nick Koston
92f15e82d7 [logger] Use RAII guards for recursion protection and optimize hot path 2026-01-13 12:11:38 -10:00
J. Nick Koston
3d74d1e7f0 [libretiny] Regenerate boards, enable Cortex-M4 atomics, and consolidate platform code (#13191) 2026-01-13 21:39:11 +00:00
J. Nick Koston
a060d1d044 [wifi] Fix ESP8266 disconnect callback order to set error flag before notifying listeners (#13189) 2026-01-13 11:33:36 -10:00
J. Nick Koston
52c34441b1 Merge branch 'libretiny_regen_fixes' into integration 2026-01-13 09:50:52 -10:00
Kevin Ahrendt
733f57da50 [i2s_audio] Bugfix: Buffer overflow in software volume control (#13190) 2026-01-13 09:42:36 -10:00
dependabot[bot]
4d96c60696 Bump yamllint from 1.37.1 to 1.38.0 (#13192)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-13 09:36:58 -10:00
J. Nick Koston
ae2575b33f fix 2026-01-13 09:34:43 -10:00
J. Nick Koston
3d51413706 lets not miss it 2026-01-13 09:33:46 -10:00
J. Nick Koston
6fd6b46ef8 [libretiny] Regenerate boards, enable Cortex-M4 atomics, and consolidate platform code 2026-01-13 09:31:05 -10:00
J. Nick Koston
ec38ffc310 [libretiny] Regenerate boards, enable Cortex-M4 atomics, and consolidate platform code 2026-01-13 09:09:49 -10:00
J. Nick Koston
a45cbc6595 [libretiny] Regenerate boards, enable Cortex-M4 atomics, and consolidate platform code 2026-01-13 09:07:04 -10:00
J. Nick Koston
62bce73b7e Merge branch 'fix_callback_order_wifi_8266' into integration 2026-01-13 08:39:42 -10:00
J. Nick Koston
39f77a3315 [wifi] Fix ESP8266 disconnect callback order to set error flag before notifying listeners 2026-01-13 08:14:46 -10:00
J. Nick Koston
714188cfd8 [wifi] Fix ESP8266 disconnect callback order to set error flag before notifying listeners 2026-01-13 08:13:37 -10:00
J. Nick Koston
3d40979c96 [mqtt] Avoid intermediate string allocations in publish calls (#13174) 2026-01-13 08:05:04 -10:00
J. Nick Koston
7fed9144a6 [api] Use stack buffer for VERY_VERBOSE proto message dumps (#13176) 2026-01-13 08:04:48 -10:00
J. Nick Koston
7abb374f2a [improv_serial] Use stack buffers for webserver URL formatting (#13175) 2026-01-13 08:04:33 -10:00
Jonathan Swoboda
5d90f170e5 Merge branch 'release' into dev 2026-01-13 11:55:58 -05:00
Jonathan Swoboda
6e01c4f86e Merge pull request #13188 from esphome/bump-2025.12.6
2025.12.6
2026-01-13 11:55:44 -05:00
Jonathan Swoboda
f4c17e15ea Bump version to 2025.12.6 2026-01-13 11:01:21 -05:00
J. Nick Koston
d6507ce329 [esphome] Fix OTA backend abort not being called on error (#13182) 2026-01-13 11:01:21 -05:00
Jonathan Swoboda
9504e92458 [remote_transmitter] Fix ESP8266 timing by using busy loop (#13172)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-13 11:01:21 -05:00
Jonathan Swoboda
3911991de2 [packet_transport] Fix packet size check to account for round4 padding (#13165)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:01:21 -05:00
Jonathan Swoboda
dede47477b [ltr_als_ps] Remove incorrect device_class from count sensors (#13167)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:01:21 -05:00
Jonathan Swoboda
dca8def0f2 [seeed_mr24hpc1] Add ifdef guards for conditional entity types (#13147)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 11:01:21 -05:00
Samuel Sieb
a1727a8901 [espnow] fix channel validation (#13057) 2026-01-13 11:01:20 -05:00
J. Nick Koston
d49f176f31 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-12 22:33:50 -10:00
Samuel Sieb
48f5296d24 [ld24xx] add id to support extending (#13183)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2026-01-12 22:32:20 -10:00
Samuel Sieb
1327776d5b [bme68x_bsec2] use EntityBase instead of Component for the id (#13185)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2026-01-12 22:32:11 -10:00
J. Nick Koston
d378b40235 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-12 21:54:44 -10:00
J. Nick Koston
df4a3e8915 [socket] Call lwip_read/lwip_write directly on ESP32 to reduce network I/O latency (#13179) 2026-01-13 01:47:11 -06:00
Keith Burzinski
6823e17b3b [ir_rf_proxy] New component (#12985)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-13 07:44:24 +00:00
J. Nick Koston
eb4d6ce29f Merge remote-tracking branch 'upstream/dev' into integration 2026-01-12 20:56:10 -10:00
J. Nick Koston
675103bed0 [esphome] Fix OTA backend abort not being called on error (#13182) 2026-01-12 20:55:40 -10:00
J. Nick Koston
6c043be4d3 [ci] Add format_hex_pretty to heap-allocating helper lint check (#13178) 2026-01-12 20:55:23 -10:00
J. Nick Koston
a95f2fb002 Merge remote-tracking branch 'origin/ota_fix_abort' into integration 2026-01-12 20:18:30 -10:00
J. Nick Koston
1a30851b0a [esphome] Fix OTA backend abort not being called on error 2026-01-12 20:17:38 -10:00
J. Nick Koston
a74cba61df Merge branch 'lwip_read_write' into integration 2026-01-12 20:04:18 -10:00
J. Nick Koston
47f32d60b5 [socket] Call lwip_read/lwip_write directly on ESP32 to reduce network I/O latency 2026-01-12 20:03:45 -10:00
J. Nick Koston
e5e977c054 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-12 17:41:28 -10:00
Rodrigo Martín
e9469cbe48 [mqtt] templatable state and command topics (#12441)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-12 17:40:27 -10:00
J. Nick Koston
5046ca164a fix packed buffer 2026-01-12 17:23:09 -10:00
J. Nick Koston
3a7cf3ac95 Merge branch 'improv_serial_webserver' into integration 2026-01-12 17:17:09 -10:00
J. Nick Koston
6e82606419 cleanup 2026-01-12 17:10:21 -10:00
J. Nick Koston
26ed3d24c1 Merge branch 'api_debug_logging' into integration 2026-01-12 17:07:10 -10:00
J. Nick Koston
b24a1a9e25 cleanup 2026-01-12 17:06:49 -10:00
J. Nick Koston
5e911e20bc tweaks 2026-01-12 17:00:26 -10:00
J. Nick Koston
3206c5664f Merge branch 'api_debug_logging' into integration 2026-01-12 16:55:03 -10:00
J. Nick Koston
b5f6a6e24d [api] Use stack buffer for VERY_VERBOSE proto message dumps 2026-01-12 16:51:52 -10:00
dependabot[bot]
5890cdf69a Bump github/codeql-action from 4.31.9 to 4.31.10 (#13173)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-12 16:31:51 -10:00
J. Nick Koston
e1a0398160 [improv_serial] Use stack buffers for webserver URL formatting 2026-01-12 16:27:38 -10:00
J. Nick Koston
9876788e65 Merge branch 'more_heap_cleanup' into integration 2026-01-12 15:52:46 -10:00
J. Nick Koston
4a03ff898f Merge remote-tracking branch 'upstream/dev' into integration 2026-01-12 15:52:36 -10:00
J. Nick Koston
410507d476 [mqtt] Avoid intermediate string allocations in publish calls 2026-01-12 15:46:16 -10:00
lullius
297f05d600 [tuya] add color_type_lowercase option (#13101)
Co-authored-by: lullius <>
2026-01-12 18:08:33 -05:00
Jonathan Swoboda
54fc10714d [remote_transmitter] Fix ESP8266 timing by using busy loop (#13172)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-12 18:06:41 -05:00
J. Nick Koston
889886909b [core] Soft deprecate heap-allocating string helpers to prevent fragmentation patterns (#13156) 2026-01-12 12:48:54 -10:00
J. Nick Koston
655e2b43cb [infrared] Use set_data() for vector timings in control() (#13171) 2026-01-12 15:27:42 -06:00
J. Nick Koston
81e639a6ba [core] Migrate callers and soft deprecate get_mac_address()/get_mac_address_pretty() (#13157) 2026-01-12 19:35:49 +00:00
Jonathan Swoboda
f9ffd134df [packet_transport] Fix packet size check to account for round4 padding (#13165)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 14:10:15 -05:00
Jonathan Swoboda
c50bf45496 [ltr_als_ps] Remove incorrect device_class from count sensors (#13167)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 14:09:54 -05:00
J. Nick Koston
9f9341a700 [web_server] Fix select compilation error in v1 (#13169) 2026-01-12 18:42:10 +00:00
tomaszduda23
71d532a349 [nrf52,sdk] Add framework version support (#12489) 2026-01-12 13:31:09 -05:00
Jasper van der Neut - Stulen
61a89a97d7 [deep_sleep] Fix GPIO wakeup on ESP32-C3/C6 (#12803) 2026-01-12 13:03:13 -05:00
Jasper van der Neut - Stulen
0c3433d056 [deep_sleep] Fix GPIO wakeup comment (#12815) 2026-01-12 12:57:58 -05:00
mikaabra
7e1cda8f9f [esp32_can] Add listen-only mode to esp32_can component (#13084)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 12:50:59 -05:00
J. Nick Koston
7f0e4eaa84 [nfc] Use stack-based hex formatting in pn7150/pn7160 components (#13163) 2026-01-12 07:38:39 -10:00
J. Nick Koston
8cccfa5369 [mqtt][prometheus][graph] Migrate value_accuracy_to_string() to stack-based alternative (#13159)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-12 07:38:20 -10:00
J. Nick Koston
7ea6bcef88 [api] Use stack buffer for bytes field dumping in proto message logs (#13162) 2026-01-12 07:37:58 -10:00
tomaszduda23
353daa97d0 [nrf52,zigbee] Warning if spaces in description (#13114)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-12 14:45:15 +00:00
Jas Strong
6c68ebe86e [rd03d] Filter targets with sentinel speed values (#13146)
Co-authored-by: jas <jas@asspa.in>
2026-01-12 09:25:43 -05:00
J. Nick Koston
62565304e4 Merge branch 'nfc_hex' into integration 2026-01-12 00:33:54 -10:00
J. Nick Koston
51dfb3af5e [nfc] Use stack-based hex formatting in pn7150/pn7160 components 2026-01-12 00:23:09 -10:00
J. Nick Koston
40b278f485 [nfc] Use stack-based hex formatting in pn7150/pn7160 components 2026-01-12 00:21:40 -10:00
J. Nick Koston
ed34a98f48 Merge branch 'api_format_hex_pretty_to' into integration 2026-01-12 00:04:50 -10:00
J. Nick Koston
d7e7e7849f [api] Use stack buffer for bytes field dumping in proto message logs 2026-01-11 19:59:05 -10:00
dependabot[bot]
29cef3bc5d Bump aioesphomeapi from 43.12.0 to 43.13.0 (#13160)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 19:26:40 -10:00
Keith Burzinski
83eebdf15d [infrared] Implement experimental API/Core/component for new component/entity type (#13129)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-12 05:01:23 +00:00
J. Nick Koston
595217786c [tuya][rc522][remote_base] Migrate format_hex_pretty() to stack-based alternatives (#13158) 2026-01-12 04:47:57 +00:00
J. Nick Koston
f22e42addc Merge branch 'dep_heap_fragmenting_helpers' into integration 2026-01-11 18:28:51 -10:00
J. Nick Koston
f70cb78d52 fix 2026-01-11 18:28:37 -10:00
J. Nick Koston
25e9e84ca5 Merge branch 'dep_heap_fragmenting_helpers' into integration 2026-01-11 18:27:29 -10:00
J. Nick Koston
d807f93c66 cleanup 2026-01-11 18:27:05 -10:00
J. Nick Koston
7a33793304 Merge branch 'format_hex_to_more' into integration 2026-01-11 18:24:55 -10:00
J. Nick Koston
f4437c9eaa Merge branch 'value_accuracy_to_string_to' into integration 2026-01-11 18:24:50 -10:00
J. Nick Koston
d52ea47552 [mqtt][prometheus][graph] Migrate value_accuracy_to_string() to stack-based alternative 2026-01-11 17:54:48 -10:00
J. Nick Koston
912f94d1e8 [api] Use StringRef for HomeassistantServiceMap.value to eliminate heap allocations (#13154)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-11 17:54:06 -10:00
J. Nick Koston
ea8ae2ae60 [climate] Return StringRef from get_custom_fan_mode() and get_custom_preset() (#13103) 2026-01-11 17:53:06 -10:00
J. Nick Koston
e1aac7601d [event] Return StringRef from get_last_event_type() (#13104) 2026-01-11 17:52:54 -10:00
J. Nick Koston
f1b11b1855 [light] Return StringRef from LightEffect::get_name() and LightState::get_effect_name() (#13105) 2026-01-11 17:52:39 -10:00
J. Nick Koston
6e6d545963 [tuya][rc522][remote_base] Migrate format_hex_pretty() to stack-based alternatives 2026-01-11 17:44:43 -10:00
J. Nick Koston
23f9f70b71 [select] Return StringRef from current_option() (#13095) 2026-01-11 17:40:43 -10:00
J. Nick Koston
eeeae53f76 [fan] Return StringRef from get_preset_mode() for safety and modern API (#13092) 2026-01-11 17:40:09 -10:00
J. Nick Koston
a29ad99661 Merge branch 'mac_address_stack' into integration 2026-01-11 17:35:18 -10:00
J. Nick Koston
c8fabf214e Merge branch 'dep_heap_fragmenting_helpers' into integration 2026-01-11 17:35:09 -10:00
J. Nick Koston
291db7c5a9 [core] Migrate callers and deprecate get_mac_address()/get_mac_address_pretty() 2026-01-11 17:34:03 -10:00
J. Nick Koston
cea8c9b212 [core] Deprecate heap-allocating string helpers to prevent fragmentation patterns 2026-01-11 17:26:42 -10:00
J. Nick Koston
45c0796e40 [ci] Add RP2040 to memory impact analysis (#13134) 2026-01-11 17:19:00 -10:00
J. Nick Koston
38e2e4a56d [runtime_stats] Fix log output formatting alignment (#13155) 2026-01-11 17:18:49 -10:00
J. Nick Koston
52132ea3bc [ch422g][lc709203f][qmc5883l] Avoid heap allocation in status_set_warning calls (#13152) 2026-01-11 17:18:37 -10:00
J. Nick Koston
ace3ff2170 [safe_mode] Conditionally compile callback when on_safe_mode is configured (#13136) 2026-01-11 17:18:24 -10:00
J. Nick Koston
26e90b4ca6 [light] Move LightColorValues::lerp() out of header to reduce code duplication (#13138) 2026-01-11 17:18:13 -10:00
J. Nick Koston
684790c2ab [web_server_idf] Reduce heap usage in DefaultHeaders and auth (#13141) 2026-01-11 17:17:57 -10:00
J. Nick Koston
6a3737bac3 [improv_serial] Use int8_to_str to avoid heap allocation for RSSI formatting (#13149) 2026-01-11 17:17:44 -10:00
J. Nick Koston
723ca57617 [uptime] Format text sensor output on stack to avoid heap allocations (#13150)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-11 17:17:32 -10:00
J. Nick Koston
909bd1074a [wifi] Fix captive portal/improv only attempting last configured network (#13086)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-11 17:17:18 -10:00
J. Nick Koston
68064dc974 [web_server] Fix v1 compilation on ESP-IDF by adding missing write method (#13153) 2026-01-11 17:17:07 -10:00
Jonathan Swoboda
742d724e65 [seeed_mr24hpc1] Add ifdef guards for conditional entity types (#13147)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 22:16:55 -05:00
J. Nick Koston
69dd056516 Merge branch 'complete_removal_no_zero_copy' into integration 2026-01-11 16:12:57 -10:00
J. Nick Koston
024097b635 cleanup 2026-01-11 16:05:33 -10:00
J. Nick Koston
0d30c2cdfd drop no zero copy 2026-01-11 16:03:26 -10:00
J. Nick Koston
2c0954c03c [api] Use StringRef for HomeassistantServiceMap.value to eliminate heap allocations 2026-01-11 16:00:44 -10:00
J. Nick Koston
f6eebe9b27 Merge branch 'web_server_1' into integration 2026-01-11 15:40:15 -10:00
J. Nick Koston
78edba8db5 [web_server] Fix v1 compilation on ESP-IDF by adding missing write method 2026-01-11 15:39:09 -10:00
J. Nick Koston
1cf3a2bc47 [web_server] Fix v1 compilation on ESP-IDF by adding missing write method 2026-01-11 15:37:22 -10:00
J. Nick Koston
3bd5dc7a8e Merge branch 'status_set_warning_str_print' into integration 2026-01-11 15:10:12 -10:00
J. Nick Koston
3e2f12d5d6 [ch422g][lc709203f][qmc5883l] Avoid heap allocation in status_set_warning calls 2026-01-11 15:09:30 -10:00
J. Nick Koston
ce79556cbd Merge remote-tracking branch 'origin/uptime_sensor_text' into integration 2026-01-11 14:52:53 -10:00
J. Nick Koston
a36b3fc81b Merge remote-tracking branch 'origin/improv_serial_format' into integration 2026-01-11 14:52:48 -10:00
J. Nick Koston
cdd09bdb94 preen 2026-01-11 14:46:14 -10:00
J. Nick Koston
c19e129821 another pass at reducing the logic 2026-01-11 14:40:50 -10:00
J. Nick Koston
f14d1edcc9 [uptime] Format text sensor output on stack to avoid heap allocations 2026-01-11 14:33:31 -10:00
J. Nick Koston
cda750e6b7 [improv_serial] Use int8_to_str to avoid heap allocation for RSSI formatting 2026-01-11 14:04:48 -10:00
dependabot[bot]
5ae46a4369 Bump aioesphomeapi from 43.11.0 to 43.12.0 (#13139)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 09:49:17 -10:00
J. Nick Koston
7666644ad8 Merge branch 'web_server_idf_cleanup_strings' into integration 2026-01-11 09:01:16 -10:00
J. Nick Koston
d7dd6a5cb8 static, less heap 2026-01-11 09:00:20 -10:00
J. Nick Koston
1fa86a7505 tweak comment 2026-01-11 08:46:02 -10:00
J. Nick Koston
c6bb62cc36 tweak comment 2026-01-11 08:45:54 -10:00
J. Nick Koston
0e6a798b2f Merge branch 'web_server_idf_cleanup_strings' into integration 2026-01-11 08:42:02 -10:00
J. Nick Koston
cd37e3c1f6 [web_server_idf] Reduce string allocations in HTTP header storage and auth 2026-01-11 08:39:11 -10:00
J. Nick Koston
5ca7b885e8 Merge branch 'light_color_values' into integration 2026-01-11 01:18:54 -10:00
J. Nick Koston
bc91fbec83 [light] Move LightColorValues::lerp() out of header to reduce code duplication 2026-01-11 01:03:08 -10:00
J. Nick Koston
31c63ef2b4 Merge branch 'safe_mode_ifdef' into integration 2026-01-10 21:06:01 -10:00
J. Nick Koston
ce336b7745 [safe_mode] Conditionally compile callback when on_safe_mode is configured 2026-01-10 20:35:11 -10:00
J. Nick Koston
a30d12fb89 [safe_mode] Conditionally compile callback when on_safe_mode is configured 2026-01-10 20:34:05 -10:00
J. Nick Koston
b480b8f572 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-10 17:09:03 -10:00
J. Nick Koston
a1395af763 [helpers] Add format_hex_prefixed_to for "0x" prefixed hex formatting (#13115) 2026-01-10 17:07:21 -10:00
J. Nick Koston
6222fae907 [libretiny] Disable BLE stack on BK7231N to save ~21KB RAM (#13131) 2026-01-10 16:43:15 -10:00
J. Nick Koston
e34532f283 [sensor] Use C++17 nested namespace syntax (#13116) 2026-01-10 21:42:35 -05:00
Keith Burzinski
f2eb61a767 [api] Proto code generator changes for #12985 (#13100)
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-10 15:43:27 -10:00
dependabot[bot]
5725a4840e Bump aioesphomeapi from 43.10.1 to 43.11.0 (#13132)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-11 01:09:25 +00:00
J. Nick Koston
de82f96ccb [core] Rename FixedVector::shrink_to_fit() to release() for clarity (#13130) 2026-01-11 00:43:31 +00:00
J. Nick Koston
a295a552f9 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-10 13:06:24 -10:00
Jonathan Swoboda
6c981d8b71 [esp32_hosted] Bump component versions (#13118)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 10:26:42 -10:00
Jas Strong
c03faf2d9a [aqi] Fix precision loss for low PM concentration values (#13120)
Co-authored-by: jas <jas@asspa.in>
2026-01-10 09:40:14 -10:00
J. Nick Koston
dff01ab8f3 Merge branch 'sensor_ns' into integration 2026-01-09 23:14:36 -10:00
J. Nick Koston
3392216b0b [sensor] Use C++17 nested namespace syntax 2026-01-09 23:12:27 -10:00
J. Nick Koston
523e27e103 Merge branch 'fan_get_preset_mode_safer' into integration 2026-01-09 22:01:43 -10:00
J. Nick Koston
4289ba23f2 Merge branch 'light_std_string' into integration 2026-01-09 22:01:32 -10:00
J. Nick Koston
90e6ff2922 Merge branch 'select_current_option' into integration 2026-01-09 22:01:17 -10:00
J. Nick Koston
c20d20bf73 Merge branch 'climate_string_view' into integration 2026-01-09 22:01:10 -10:00
J. Nick Koston
6a280f8e2b Merge branch 'event_string_view' into integration 2026-01-09 22:01:04 -10:00
J. Nick Koston
3fd31581d6 cleanup 2026-01-09 21:59:19 -10:00
J. Nick Koston
3178ae32dd missed some 2026-01-09 21:56:14 -10:00
J. Nick Koston
3b5b9445fe Merge remote-tracking branch 'origin/integration' into integration 2026-01-09 17:05:11 -10:00
J. Nick Koston
db7bba744d Merge remote-tracking branch 'upstream/dev' into integration 2026-01-09 17:05:03 -10:00
J. Nick Koston
54668648df fix 2026-01-09 16:56:02 -10:00
J. Nick Koston
54d3ea4098 fix: use simple .c_str() for ESP8266 compatibility 2026-01-09 16:54:21 -10:00
J. Nick Koston
08bd49c038 fix 2026-01-09 16:50:42 -10:00
J. Nick Koston
a3a4c12f3e try 2026-01-09 16:47:40 -10:00
J. Nick Koston
2eb98c19f7 strinferf 2026-01-09 16:43:28 -10:00
J. Nick Koston
fef7b6093d Merge branch 'dev' into event_string_view 2026-01-09 16:40:12 -10:00
J. Nick Koston
74f2619097 Merge branch 'dev' into select_current_option 2026-01-09 16:39:43 -10:00
J. Nick Koston
1593b6f10d Merge branch 'dev' into climate_string_view 2026-01-09 16:39:08 -10:00
J. Nick Koston
0aab72a462 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-09 16:38:32 -10:00
esphomebot
da7680f7d9 Update webserver local assets to 20260110-013228 (#13113)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2026-01-09 16:38:01 -10:00
J. Nick Koston
2034e7d39c Merge remote-tracking branch 'origin/climate_string_view' into climate_string_view 2026-01-09 16:36:59 -10:00
J. Nick Koston
f01aeded4d tests update 2026-01-09 16:36:17 -10:00
J. Nick Koston
cacbb017c0 fix 2026-01-09 16:35:04 -10:00
J. Nick Koston
682b2104f2 tweak comments 2026-01-09 16:31:01 -10:00
J. Nick Koston
7bc970809a tweak comments 2026-01-09 16:29:38 -10:00
J. Nick Koston
3dbca6692e stringref 2026-01-09 16:28:21 -10:00
J. Nick Koston
48906aaa51 Merge remote-tracking branch 'origin/dev' into integration 2026-01-09 16:21:50 -10:00
J. Nick Koston
7a64d834d1 Merge remote-tracking branch 'origin/light_std_string' into light_std_string 2026-01-09 16:19:56 -10:00
J. Nick Koston
dc49f4c180 fix 2026-01-09 16:19:43 -10:00
J. Nick Koston
15734c63a1 back to print 2026-01-09 16:18:35 -10:00
J. Nick Koston
33d2140f1c stringref 2026-01-09 16:13:17 -10:00
J. Nick Koston
606ce9cfd2 stringref 2026-01-09 16:12:12 -10:00
J. Nick Koston
aa760446af Merge branch 'dev' into select_current_option 2026-01-09 16:07:32 -10:00
J. Nick Koston
60a06a5aac Merge branch 'dev' into light_std_string 2026-01-09 16:01:07 -10:00
J. Nick Koston
c8f86f0a94 stringref 2026-01-09 15:57:20 -10:00
J. Nick Koston
ca31c975be stringref 2026-01-09 15:57:06 -10:00
J. Nick Koston
ec03a0155b stringref 2026-01-09 15:52:11 -10:00
J. Nick Koston
5f6cfb4feb Merge remote-tracking branch 'origin/fan_get_preset_mode_safer' into fan_get_preset_mode_safer 2026-01-09 15:40:31 -10:00
J. Nick Koston
1fdacd9d22 use stringref 2026-01-09 15:40:18 -10:00
J. Nick Koston
ab3ab6f521 Merge remote-tracking branch 'upstream/dev' into fan_get_preset_mode_safer 2026-01-09 15:36:04 -10:00
J. Nick Koston
9ef492e95a Merge branch 'dev' into fan_get_preset_mode_safer 2026-01-09 15:35:19 -10:00
Douwe
cea2878b55 [water_heater] (3/4) Implement web_server for new water_heater component (#12511)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-09 15:25:42 -10:00
J. Nick Koston
a5b906516d Merge branch 'dev' into light_std_string 2026-01-09 14:03:26 -10:00
J. Nick Koston
2e6b22aa62 Merge remote-tracking branch 'origin/light_std_string' into light_std_string 2026-01-09 14:02:57 -10:00
J. Nick Koston
66d978ade1 comment 2026-01-09 14:02:37 -10:00
Jonathan Swoboda
e0ff7fdaa1 [esp32_hosted] Add HTTP-based coprocessor firmware update support (#13090)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-09 17:36:56 -05:00
tomaszduda23
3c9b300c46 [CI] skip endpoint check due to test grouping (#13111) 2026-01-09 22:13:37 +00:00
J. Nick Koston
9bcdcedd94 Merge branch 'dev' into light_std_string 2026-01-09 09:48:20 -10:00
J. Nick Koston
ed07c7c7ee cleanups 2026-01-09 09:47:43 -10:00
J. Nick Koston
32f90b2855 [mdns] Remove deprecated api password from test configuration (#13107) 2026-01-09 09:40:24 -10:00
J. Nick Koston
2fb7c0d453 [mapping] Fix test SPI data rate for RP2040 (#13108) 2026-01-09 09:39:53 -10:00
dependabot[bot]
7935fba4b1 Bump esphome-dashboard from 20251013.0 to 20260110.0 (#13109)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-09 14:37:53 -05:00
Stuart Parmenter
ab32b93928 [hub75] Fix gamma_correct to use enum value instead of key string (#13102)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-09 13:34:04 -06:00
J. Nick Koston
999d2d7f7e [light] Return std::string_view from LightEffect::get_name() and LightState::get_effect_name() 2026-01-09 09:11:58 -10:00
J. Nick Koston
a693e631bb [light] Return std::string_view from LightEffect::get_name() and LightState::get_effect_name() 2026-01-09 08:38:08 -10:00
J. Nick Koston
775c6a077d [light] Return std::string_view from LightEffect::get_name() and LightState::get_effect_name() 2026-01-09 08:35:37 -10:00
J. Nick Koston
8a3e26e6e9 [event] Return std::string_view from get_last_event_type() 2026-01-09 08:07:57 -10:00
J. Nick Koston
56ced4a403 [climate] Return std::string_view from get_custom_fan_mode() and get_custom_preset() 2026-01-09 07:47:42 -10:00
J. Nick Koston
265bc55c28 [climate] Return std::string_view from get_custom_fan_mode() and get_custom_preset() 2026-01-09 07:43:52 -10:00
J. Nick Koston
6dcbc24864 [climate] Return std::string_view from get_custom_fan_mode() and get_custom_preset() 2026-01-09 07:43:01 -10:00
J. Nick Koston
3d54ccac65 Revert "[wifi] Disable SoftAP support on Arduino ESP32 when ap: not configured" (#13099) 2026-01-09 09:35:19 -05:00
Keith Burzinski
c40f44f4bd [remote_base] Add zero-copy packed sint32 decoder for #12985 (#13093) 2026-01-09 04:06:03 -06:00
Keith Burzinski
62cb08c3dc [api] Add methods supporting efficient packed repeated sint32 field encoding for #12985 (#13094) 2026-01-09 04:05:47 -06:00
J. Nick Koston
26671cb1ee [select] Return std::string_view from current_option() 2026-01-08 23:05:30 -10:00
J. Nick Koston
6596186240 actually commit thte tests 2026-01-08 23:00:34 -10:00
J. Nick Koston
e8465bfcda [select] Return std::string_view from current_option() 2026-01-08 22:58:49 -10:00
J. Nick Koston
b9b3adae0d Merge branch 'dev' into fan_get_preset_mode_safer 2026-01-08 22:26:49 -10:00
J. Nick Koston
872b2ec7db address copilot review comments 2026-01-08 22:25:16 -10:00
J. Nick Koston
a3553dab1c address copilot review comments 2026-01-08 22:24:38 -10:00
J. Nick Koston
cd76747b25 tests 2026-01-08 22:19:52 -10:00
J. Nick Koston
0ebe99ccf5 tests 2026-01-08 22:00:04 -10:00
J. Nick Koston
04eba0563a tests 2026-01-08 21:58:20 -10:00
Stuart Parmenter
7576e032f8 [hub75] Fix depth and gamma mode defines (#13091) 2026-01-09 01:56:51 -06:00
J. Nick Koston
1e30f54dff cleanup 2026-01-08 21:49:59 -10:00
J. Nick Koston
6c502d879b cleanup 2026-01-08 21:49:15 -10:00
J. Nick Koston
04ffa74643 if we are going ot break it, string view 2026-01-08 21:44:40 -10:00
J. Nick Koston
ff0b1a24c7 [fan] Make get_preset_mode() return empty string instead of nullptr for safety 2026-01-08 21:35:18 -10:00
J. Nick Koston
b24dbf77e4 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-08 21:01:17 -10:00
J. Nick Koston
cd43b4114e [api] Fire on_client_disconnected trigger after removing client from list (#13088) 2026-01-08 20:36:24 -10:00
J. Nick Koston
2c165e4817 [web_server] Use centralized length constants for buffer sizing (#13073) 2026-01-08 20:36:08 -10:00
J. Nick Koston
5afe4b7b12 [wifi] Warn when AP is configured without captive_portal or web_server (#13087) 2026-01-08 16:41:34 -10:00
Anton Viktorov
dcb8c994cc [ac_dimmer] Added support for ESP-IDF (5+) (#7072)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-08 15:24:01 -10:00
J. Nick Koston
7f5887581d Merge branch 'ap_misconfigured_warn' into integration 2026-01-08 14:55:32 -10:00
J. Nick Koston
12be08f85e [wifi] Warn when AP is configured without captive_portal or web_server 2026-01-08 14:54:41 -10:00
J. Nick Koston
8c6a3f8d62 Merge branch 'blind_retry' into integration 2026-01-08 14:27:48 -10:00
J. Nick Koston
23eec55ed3 [wifi] Fix captive portal/improv only attempting last configured network 2026-01-08 14:26:24 -10:00
J. Nick Koston
cb383c8049 [wifi] Fix captive portal/improv only attempting last configured network 2026-01-08 14:23:44 -10:00
J. Nick Koston
ca45c0de66 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-08 12:16:22 -10:00
Rodrigo Martín
012a1e2afd [mqtt] Include session_present and reason parameters in connection callbacks (#12413)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-08 22:05:53 +00:00
J. Nick Koston
d4969f581a [wifi] Limit ignored disconnect events on LibreTiny to speed up AP failover (#13070) 2026-01-08 11:42:30 -10:00
J. Nick Koston
40f108116b [mqtt] Reduce heap allocations in topic string building (#13072) 2026-01-08 11:42:18 -10:00
J. Nick Koston
52459d1bc7 [wifi] Fix infinite roaming when best-signal AP is crashed/broken (#13071) 2026-01-08 11:42:06 -10:00
dependabot[bot]
325c938074 Bump ruff from 0.14.10 to 0.14.11 (#13082)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-08 20:57:30 +00:00
J. Nick Koston
423a617b15 [core] Improve minimum_chip_revision warning for PSRAM users (#13074) 2026-01-08 10:52:27 -10:00
J. Nick Koston
eb5c4f34e2 [wifi] Disable SoftAP support on Arduino ESP32 when ap: not configured (#13076) 2026-01-08 10:51:58 -10:00
J. Nick Koston
c9ab4ca018 [libretiny] Bump to 1.9.2 (#13077) 2026-01-08 10:51:35 -10:00
J. Nick Koston
da0b01f4d0 [logger] Enable loop disable optimization for LibreTiny task log buffer (#13078) 2026-01-08 10:51:18 -10:00
J. Nick Koston
7ff590e1da Merge branch 'disable_loop_when_buffer_empty_' into integration 2026-01-07 23:35:13 -10:00
J. Nick Koston
d402b0c391 [logger] Enable loop disable optimization for LibreTiny task log buffer 2026-01-07 23:34:39 -10:00
J. Nick Koston
ebd484495e Merge branch 'bump_libretiny_192' into integration 2026-01-07 23:07:52 -10:00
J. Nick Koston
36e748609e [libretiny] Bump to 1.9.2 2026-01-07 23:01:00 -10:00
J. Nick Koston
57152edf23 Merge branch 'wifi_ard_esp32' into integration 2026-01-07 22:50:06 -10:00
J. Nick Koston
1c3f421746 [wifi] Disable SoftAP support on Arduino ESP32 when ap: not configured 2026-01-07 22:42:49 -10:00
J. Nick Koston
182063d5c6 Merge remote-tracking branch 'origin/reuse_constexpr_web_server' into integration 2026-01-07 22:06:54 -10:00
J. Nick Koston
f8f6ad942b Merge branch 'min_chip_psram' into integration 2026-01-07 22:06:40 -10:00
J. Nick Koston
fd1ad89a33 [core] Improve minimum_chip_revision warning for PSRAM users 2026-01-07 22:05:40 -10:00
J. Nick Koston
735aca89ee [web_server] Use centralized length constants for buffer sizing 2026-01-07 20:03:18 -10:00
J. Nick Koston
aa3bed7089 [web_server] Use centralized length constants for buffer sizing 2026-01-07 20:01:54 -10:00
J. Nick Koston
40cd6aa18b [web_server] Use centralized length constants for buffer sizing 2026-01-07 20:01:23 -10:00
J. Nick Koston
b8da3b3265 [web_server] Use centralized length constants for buffer sizing 2026-01-07 20:00:40 -10:00
J. Nick Koston
9a3d1f5acc [web_server] Use centralized length constants for buffer sizing 2026-01-07 19:59:45 -10:00
J. Nick Koston
ec5290ef80 [web_server] Use centralized length constants for buffer sizing 2026-01-07 19:58:30 -10:00
J. Nick Koston
197cf6f445 [web_server] Use centralized length constants for buffer sizing 2026-01-07 19:56:16 -10:00
J. Nick Koston
8b46610281 tweaks 2026-01-07 19:39:11 -10:00
J. Nick Koston
3234f44660 Address Copilot review comments 2026-01-07 19:32:30 -10:00
J. Nick Koston
b5b78a674e [mqtt] Reduce heap allocations in topic string building 2026-01-07 18:42:58 -10:00
Keith Burzinski
e301b8d0e0 [thermostat] Allow heat_cool_mode without an automation (#13069)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-01-07 21:44:10 -06:00
J. Nick Koston
3a2f2aa6a8 Merge branch 'wifi_roaming_prevent_ping_pong_broken_ap' into integration 2026-01-07 16:37:48 -10:00
J. Nick Koston
d46b0c4abb tweak 2026-01-07 16:37:09 -10:00
J. Nick Koston
329e800684 more logging 2026-01-07 16:36:45 -10:00
J. Nick Koston
8aa77f7888 Merge branch 'wifi_roaming_prevent_ping_pong_broken_ap' into integration 2026-01-07 16:30:34 -10:00
J. Nick Koston
79c1680b80 show attempts remaining in logging 2026-01-07 16:30:25 -10:00
J. Nick Koston
d2347e1302 Merge branch 'wifi_roaming_prevent_ping_pong_broken_ap' into integration 2026-01-07 16:28:35 -10:00
J. Nick Koston
de1c213537 handle scan error 2026-01-07 16:27:27 -10:00
J. Nick Koston
1fb2eaa905 fixes 2026-01-07 16:24:55 -10:00
J. Nick Koston
b919cc584c fixes 2026-01-07 16:24:46 -10:00
J. Nick Koston
142b1640b6 Merge branch 'wifi_roaming_prevent_ping_pong_broken_ap' into integration 2026-01-07 16:18:21 -10:00
J. Nick Koston
fb4d50150a [wifi] Fix infinite roaming when best-signal AP is crashed/broken 2026-01-07 16:16:47 -10:00
J. Nick Koston
d0843d504e [wifi] Fix infinite roaming when best-signal AP is crashed/broken 2026-01-07 16:15:38 -10:00
J. Nick Koston
77077b470a Merge branch 'libretiny_limit_wifi_retries' into integration 2026-01-07 15:40:11 -10:00
J. Nick Koston
22af0b9eec [wifi] Limit ignored disconnect events on LibreTiny to speed up AP failover 2026-01-07 15:38:54 -10:00
Clyde Stubbs
738678e87b [image] Add define and core data (#13058) 2026-01-08 11:20:37 +11:00
J. Nick Koston
761aa2eecf Merge remote-tracking branch 'upstream/dev' into integration 2026-01-07 13:44:27 -10:00
J. Nick Koston
0ce3ac438b [logger] Add thread-safe logging support for LibreTiny platform (#13062) 2026-01-07 13:40:15 -10:00
marcbodea
afa4fe9820 [esp32_touch] Disable hardware timeout to prevent continuous interrupts (#13059)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-07 18:37:47 -05:00
J. Nick Koston
cc08d17f85 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-07 11:52:17 -10:00
esphomebot
a66df9ab0f Update webserver local assets to 20260107-214817 (#13064)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2026-01-07 11:52:02 -10:00
J. Nick Koston
4ad721f632 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-07 11:51:46 -10:00
J. Nick Koston
1339f3e77e [web_server][captive_portal] Add Brotli compression (saves ~11KB flash when using local) (#12959) 2026-01-07 11:49:23 -10:00
J. Nick Koston
fb03947d28 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-07 11:39:50 -10:00
J. Nick Koston
e29523e248 [abbwelcome] Use stack-based formatting to eliminate heap allocations (#12799) 2026-01-07 10:31:19 -10:00
J. Nick Koston
44eac36e05 [debug] Use stack buffers with buf_append helper instead of std::string (#13020) 2026-01-07 10:19:10 -10:00
J. Nick Koston
050e9b0d4a [wifi] Add basic post-connect roaming support for stationary devices (#12809) 2026-01-07 08:30:23 -10:00
J. Nick Koston
25ac89e9b5 [logger] Add thread-safe logging for host platform (#13010) 2026-01-07 08:29:50 -10:00
J. Nick Koston
d86d1f9f52 [modbus_controller] Replace format_hex_pretty with stack-based format_hex_pretty_to (#12781) 2026-01-07 08:29:28 -10:00
J. Nick Koston
fd19280df9 [es8388] Use index-based select publish_state to avoid heap allocations (#13053) 2026-01-07 08:29:00 -10:00
J. Nick Koston
b7dbda497a [core] Improve log timestamp accuracy by batching serial reads (#12750) 2026-01-07 08:28:31 -10:00
J. Nick Koston
815543b77e [tuya] Avoid heap allocation in text sensor enum publish (#13056) 2026-01-07 08:28:14 -10:00
J. Nick Koston
0948e0359f [core] Add integer overload for fnv1a_hash_extend (#13054) 2026-01-07 08:27:58 -10:00
J. Nick Koston
2830c7dab8 [ld2410/ld2412/ld2450] Use index-based select publish_state to avoid heap allocations (#13051) 2026-01-07 08:27:39 -10:00
J. Nick Koston
a03c13f304 [esp32_hosted] Add SHA256 alignment for hardware DMA compatibility (#13050) 2026-01-07 08:26:49 -10:00
J. Nick Koston
ef64226ed0 [mqtt] Use ESPHOME_F() for JSON strings to reduce ESP8266 RAM usage (#13049) 2026-01-07 08:26:21 -10:00
J. Nick Koston
ed39a130a8 [http_request] Store JSON keys in flash for ESP8266 (#13048) 2026-01-07 08:26:04 -10:00
J. Nick Koston
21687a1f58 [sun_gtil2] Eliminate heap allocations in text sensor publishing (#13047)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-07 08:25:33 -10:00
J. Nick Koston
bf75f77eee [preferences] Fix preferences not syncing in safe mode due to component registration order (#13041) 2026-01-07 08:25:08 -10:00
J. Nick Koston
39526e5360 [analyze-memory] Add RAM symbol analysis by component (#13040) 2026-01-07 08:24:44 -10:00
J. Nick Koston
8e40a55d5d [ble_client] Eliminate heap allocations in text sensor (#13038) 2026-01-07 08:24:22 -10:00
J. Nick Koston
20927674da [sun] Eliminate heap allocation in text sensor (#13037) 2026-01-07 08:24:09 -10:00
J. Nick Koston
8464307a43 [api] Coalesce log packets to reduce buffer pressure and prevent dropped state updates (#13026) 2026-01-07 08:23:50 -10:00
J. Nick Koston
546cdbde0d [api] Simplify string handling by removing bifurcated client/server storage (#12822) 2026-01-07 08:23:28 -10:00
tomaszduda23
ada4e6d5e9 [nrf52, zigbee] Add sensor (#12187)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-07 08:20:01 -10:00
Keith Burzinski
d6554702d8 [zwave_proxy] Make send_frame safer, make set_home_id protected (#13055) 2026-01-07 08:54:08 +00:00
Samuel Sieb
b083c33857 [espnow] fix channel validation (#13057) 2026-01-07 00:41:24 -08:00
J. Nick Koston
30cf47f737 Merge branch 'fnv_extend' into integration 2026-01-06 22:19:21 -10:00
J. Nick Koston
d2fb4b1af7 [core] Add integer overloads for fnv1_hash_extend and fnv1a_hash_extend 2026-01-06 22:17:44 -10:00
J. Nick Koston
062bb66943 Merge branch 'es8388' into integration 2026-01-06 21:45:02 -10:00
J. Nick Koston
7a300b04f0 [es8388] Use index-based select publish_state to avoid heap allocations 2026-01-06 21:44:21 -10:00
Keith Burzinski
f8309b007c [zwave_proxy] Add logging if client sends zero-length message (#13052) 2026-01-07 01:41:33 -06:00
J. Nick Koston
112cf35960 Merge branch 'ld24xx_select_heap' into integration 2026-01-06 21:36:13 -10:00
J. Nick Koston
899f40a024 fix up 2026-01-06 21:31:08 -10:00
J. Nick Koston
b128f1fb76 Merge branch 'ld24xx_select_heap' into integration 2026-01-06 21:22:10 -10:00
J. Nick Koston
255aa14aff [ld2410/ld2412/ld2450] Use index-based select publish_state to avoid heap allocations 2026-01-06 21:20:48 -10:00
Clyde Stubbs
ac672e4b8f [esp32] Don't warn about no ota rollback if no ota at all (#13045) 2026-01-07 18:19:46 +11:00
J. Nick Koston
7c0562b134 Merge branch 'esp_hosted_dma' into integration 2026-01-06 20:57:52 -10:00
J. Nick Koston
cf2beb40af [esp32_hosted] Add SHA256 alignment for hardware DMA compatibility 2026-01-06 20:56:20 -10:00
J. Nick Koston
631089b852 Merge branch 'debug_cleanup' into integration 2026-01-06 20:38:28 -10:00
J. Nick Koston
d02830307f missed one 2026-01-06 20:36:57 -10:00
J. Nick Koston
cd3b9fa268 Merge branch 'update_esp8266' into integration 2026-01-06 20:20:30 -10:00
J. Nick Koston
99171afd01 Merge branch 'mqtt_json_flash' into integration 2026-01-06 20:20:25 -10:00
J. Nick Koston
8c549d1ef3 [mqtt] Use ESPHOME_F() for JSON strings to reduce ESP8266 RAM usage 2026-01-06 20:19:48 -10:00
J. Nick Koston
e4a92989b3 [http_request] Store JSON keys in flash for ESP8266 2026-01-06 20:13:54 -10:00
J. Nick Koston
813099ace6 Merge branch 'debug_cleanup' into integration 2026-01-06 19:48:06 -10:00
J. Nick Koston
18b0f0965f Merge branch 'no_heap_no_change_text' into integration 2026-01-06 19:47:57 -10:00
J. Nick Koston
d7f832c1cd Merge branch 'sun_gtil2_heap' into integration 2026-01-06 19:47:52 -10:00
J. Nick Koston
f512882a38 Merge branch 'dev' into debug_cleanup 2026-01-06 19:31:49 -10:00
J. Nick Koston
499dbd9e91 [sun_gtil2] Eliminate heap allocations in text sensor publishing 2026-01-06 19:29:00 -10:00
J. Nick Koston
c387c03944 [text_sensor][text] Avoid heap allocation when state unchanged (#13044) 2026-01-06 19:22:04 -10:00
J. Nick Koston
0acd78612f [text_sensor][text] Avoid heap allocation when state unchanged 2026-01-06 18:06:08 -10:00
J. Nick Koston
22dea00d1b Merge remote-tracking branch 'upstream/dev' into integration 2026-01-06 17:57:17 -10:00
J. Nick Koston
906fb3213f Merge branch 'sun_heap_churn' into integration 2026-01-06 17:57:02 -10:00
J. Nick Koston
fb47bfe92a [dsmr] Eliminate heap allocation when publishing telegram (#13032) 2026-01-06 17:54:20 -10:00
J. Nick Koston
5b9be7c169 [ci] Add lint check to prevent usage of deprecated CORE.using_esp_idf (#13029) 2026-01-06 17:54:04 -10:00
J. Nick Koston
6d1f6a1084 [wifi_info] Eliminate heap churn in text sensors (#13031) 2026-01-06 17:53:54 -10:00
J. Nick Koston
f9ed2aa17f [pylontech] Eliminate heap allocations in text sensors (#13033) 2026-01-06 17:53:42 -10:00
J. Nick Koston
35118da606 [ethernet_info] Eliminate heap allocations in text sensors (#13034) 2026-01-06 17:53:29 -10:00
J. Nick Koston
498477c5a2 [homeassistant] Eliminate heap allocation in text sensor state updates (#13035) 2026-01-06 17:53:14 -10:00
J. Nick Koston
3a84e4a0b4 [openthread_info] Eliminate heap allocations in text sensors (#13036) 2026-01-06 17:53:00 -10:00
J. Nick Koston
bb1dcca39d lower case - clang-tidy 2026-01-06 17:52:38 -10:00
J. Nick Koston
4391457a96 [sml] Eliminate heap allocations in text sensor (#13039) 2026-01-06 17:51:26 -10:00
Kyrill
68b4bc9d9e Map HEAT_COOL to MODE_AUTO in HeatpumpIR component (#12058)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-06 21:28:41 -06:00
J. Nick Koston
b052c9f562 [esp32_camera][uart] Add missing wake_loop_threadsafe() preprocessor guards (#13043) 2026-01-07 03:22:10 +00:00
J. Nick Koston
c73d88ce33 enforce buffer size safety at compile time 2026-01-06 16:36:36 -10:00
J. Nick Koston
04057a59c6 tests 2026-01-06 16:35:05 -10:00
J. Nick Koston
c9f4a0e010 enforce buffer size safety at compile time 2026-01-06 16:27:12 -10:00
J. Nick Koston
2a89488cb6 enforce buffer size safety at compile time 2026-01-06 16:24:55 -10:00
J. Nick Koston
58375a3f36 Merge branch 'dev' into sun_heap_churn 2026-01-06 16:18:47 -10:00
J. Nick Koston
a19597626b [text_sensor][text] Add const char* overloads to publish_state to eliminate heap churn (#13030) 2026-01-06 16:16:37 -10:00
J. Nick Koston
609cb8f0fe Merge branch 'flash_write_after_ota_broken_libretiny' into integration 2026-01-06 16:12:56 -10:00
J. Nick Koston
46a85203e0 fix 2026-01-06 16:09:26 -10:00
J. Nick Koston
bf8caeb0a8 Merge branch 'flash_write_after_ota_broken_libretiny' into integration 2026-01-06 14:53:54 -10:00
J. Nick Koston
f54505243c [safe_mode] Fix devices getting stuck in safe mode on LibreTiny 2026-01-06 14:49:06 -10:00
J. Nick Koston
3aa396ceb6 Merge remote-tracking branch 'origin/ram_symbols' into integration 2026-01-06 14:37:01 -10:00
J. Nick Koston
b341374a5d Merge branch 'sml_fix_heap_churn' into integration 2026-01-06 14:36:46 -10:00
J. Nick Koston
34819881c6 Merge branch 'ble_client_heap_churn' into integration 2026-01-06 14:36:40 -10:00
J. Nick Koston
d9c9d21750 [analyze-memory] Add RAM symbol analysis by component 2026-01-06 14:35:35 -10:00
J. Nick Koston
aba4645d81 remove useless 2026-01-06 14:27:07 -10:00
J. Nick Koston
04d498eb41 [sml] Eliminate heap allocations in text sensor 2026-01-06 14:25:33 -10:00
J. Nick Koston
b6058e837b Merge branch 'ble_client_heap_churn' into integration 2026-01-06 14:18:02 -10:00
J. Nick Koston
6b088eac16 [ble_client] Eliminate heap allocations in text sensor 2026-01-06 14:16:19 -10:00
J. Nick Koston
7ec6f6ba76 Merge branch 'sun_heap_churn' into integration 2026-01-06 14:10:35 -10:00
J. Nick Koston
34de46ecec [sun] Eliminate heap allocation in text sensor 2026-01-06 14:08:58 -10:00
J. Nick Koston
a51c1ec9f8 Merge branch 'openthread_heap_churn' into integration 2026-01-06 13:03:15 -10:00
J. Nick Koston
97591a8743 [openthread_info] Eliminate heap allocations in text sensors 2026-01-06 13:02:24 -10:00
J. Nick Koston
6fe0f29bac Merge branch 'homeassistant_text_churn' into integration 2026-01-06 12:51:17 -10:00
J. Nick Koston
6b1a36b416 [homeassistant] Eliminate heap allocation in text sensor state updates 2026-01-06 12:49:56 -10:00
J. Nick Koston
d85c0ff4d5 Merge branch 'ethernet_text_churn' into integration 2026-01-06 12:45:31 -10:00
J. Nick Koston
319be3498a [ethernet_info] Eliminate heap allocations in text sensors 2026-01-06 12:44:47 -10:00
J. Nick Koston
5c482f0809 Merge branch 'pylontech_no_heap' into integration 2026-01-06 12:41:12 -10:00
J. Nick Koston
bdbd275dcc Merge branch 'dsmr_no_heap' into integration 2026-01-06 12:41:07 -10:00
J. Nick Koston
776b6a6cac [pylontech] Eliminate heap allocations in text sensors 2026-01-06 12:40:10 -10:00
J. Nick Koston
559f534f13 [dsmr] Eliminate heap allocation when publishing telegram 2026-01-06 12:37:25 -10:00
J. Nick Koston
be77f57fc3 Merge branch 'text_no_string' into integration 2026-01-06 12:33:33 -10:00
J. Nick Koston
45b195aba5 [wifi_info] Eliminate heap churn in text sensors 2026-01-06 12:32:41 -10:00
J. Nick Koston
d07772671e Merge branch 'fix_text_heap_churn' into integration 2026-01-06 12:19:41 -10:00
J. Nick Koston
9ee5c1bb27 wip 2026-01-06 12:19:32 -10:00
J. Nick Koston
3d1589a278 Merge branch 'fix_text_heap_churn' into integration 2026-01-06 12:17:32 -10:00
J. Nick Koston
227787ab95 [text_sensor][text] Add const char* overloads to publish_state to eliminate heap churn 2026-01-06 12:16:49 -10:00
J. Nick Koston
7bd77eec31 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-06 11:52:26 -10:00
J. Nick Koston
2147ddf8c7 [api] Eliminate std::string from ClientInfo struct (#12566)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2026-01-06 21:32:23 +00:00
Jas Strong
412ab5dbbf [aqi] Implement a sensor that computes AQI (#12958)
Co-authored-by: jas <jas@asspa.in>
2026-01-06 16:31:50 -05:00
David Woodhouse
4419bf02b1 [async_tcp] Fix build conflicts and use IDF component for ESP32 (#13025)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-06 20:26:27 +00:00
J. Nick Koston
8eb28a7724 [neopixelbus] Fix ESP8266 compilation by enabling Serial/Serial1 for NeoPixelBus library (#13027) 2026-01-06 18:38:39 +00:00
J. Nick Koston
cf1444742b Merge branch 'log_coalesce' into integration 2026-01-06 08:30:57 -10:00
J. Nick Koston
195b606259 explain 2026-01-06 08:30:13 -10:00
J. Nick Koston
d6c2dd3c26 [wifi] Eliminate heap allocations in IP address logging (#13017) 2026-01-06 08:21:16 -10:00
J. Nick Koston
c4d3a56cc9 [api] Coalesce log packets to reduce buffer pressure and prevent dropped state updates 2026-01-06 08:13:35 -10:00
J. Nick Koston
ac42102320 [core] Auto-replace / in entity names with Unicode fraction slash during deprecation period (#13016) 2026-01-06 07:36:01 -10:00
J. Nick Koston
2c6584baf5 [xiaomi_ble] Simplify set_bindkey using parse_hex and const char* (#13014) 2026-01-06 07:35:40 -10:00
J. Nick Koston
c1ad39a072 [wifi] Clean up duplicate and empty logging output (#13018) 2026-01-06 07:35:16 -10:00
J. Nick Koston
d3e193cd71 [ota] Fix ESP32-S3 OTA crash with hardware SHA acceleration on IDF 5.5.x (#13021) 2026-01-06 07:34:58 -10:00
J. Nick Koston
11aed601b8 [ble_scanner] Use stack-based string formatting to reduce heap allocations (#13013) 2026-01-06 07:34:38 -10:00
J. Nick Koston
e0981323bd [mqtt] Move Home Assistant discovery keys to PROGMEM on ESP8266 (#13011) 2026-01-06 07:33:56 -10:00
J. Nick Koston
1e56325b33 [improv_base] Optimize next_url to avoid STL string operations (#13015) 2026-01-06 07:33:32 -10:00
J. Nick Koston
a8a26f4ea8 [opentherm][nau7802] Use direct format specifiers instead of to_string().c_str() (#13019) 2026-01-06 07:32:43 -10:00
Jonathan Swoboda
a94eef3a60 Merge branch 'release' into dev 2026-01-06 10:23:02 -05:00
Jonathan Swoboda
b6f3a5d8b7 Merge pull request #13024 from esphome/bump-2025.12.5
2025.12.5
2026-01-06 10:22:48 -05:00
Jonathan Swoboda
3322b04e00 Bump version to 2025.12.5 2026-01-06 09:35:38 -05:00
Jonathan Swoboda
47d0d3cfeb [cc1101] Add PLL lock verification and retry support (#13006) 2026-01-06 09:35:37 -05:00
Clyde Stubbs
8255c02d5d [esp32_ble] Remove requirement for configured network (#12891) 2026-01-06 09:35:37 -05:00
Conrad Juhl Andersen
8b4ba8dfe6 [wts01] Fix negative values for WTS01 sensor (#12835) 2026-01-06 09:35:37 -05:00
Artur
178a61b6fd [sn74hc595]: fix 'Attempted read from write-only channel' when using esp-idf framework (#12801) 2026-01-06 09:35:37 -05:00
Clyde Stubbs
b5df4cdf1d [lvgl] Fix arc background angles (#12773) 2026-01-06 09:35:37 -05:00
Jonathan Swoboda
484f4b3aad [cc1101] Add PLL lock verification and retry support (#13006) 2026-01-06 09:34:28 -05:00
J. Nick Koston
249d89cc5d Merge branch 'sha256_ota_fix' into integration 2026-01-06 00:51:09 -10:00
J. Nick Koston
ffb15b592c cleanup 2026-01-06 00:50:43 -10:00
J. Nick Koston
b40de61224 cleanup 2026-01-06 00:48:40 -10:00
J. Nick Koston
3e6d777439 fix 2026-01-06 00:46:15 -10:00
J. Nick Koston
f5ae09056c cleanup 2026-01-06 00:34:36 -10:00
J. Nick Koston
72892b8913 fix 2026-01-06 00:31:40 -10:00
J. Nick Koston
84e382387d [ota] Fix ESP32-S3 OTA crash with hardware SHA acceleration on IDF 5.5.x 2026-01-06 00:09:14 -10:00
J. Nick Koston
4e80a89f61 tidy 2026-01-05 23:44:22 -10:00
J. Nick Koston
b19918cdbf [debug] Use stack buffers with buf_append helper instead of std::string 2026-01-05 23:38:06 -10:00
J. Nick Koston
2288f8eb5e [debug] Use stack buffers with buf_append helper instead of std::string 2026-01-05 23:35:24 -10:00
J. Nick Koston
9420ae7795 [debug] Use stack buffers with buf_append helper instead of std::string 2026-01-05 23:32:36 -10:00
J. Nick Koston
5e573ee116 [debug] Use stack buffers with buf_append helper instead of std::string 2026-01-05 23:28:17 -10:00
J. Nick Koston
8046dc5ea5 Merge branch 'drop_to_string' into integration 2026-01-05 22:51:25 -10:00
J. Nick Koston
efbd14c15c [opentherm][nau7802] Use direct format specifiers instead of to_string().c_str() 2026-01-05 22:50:51 -10:00
J. Nick Koston
d51ee3d004 Merge branch 'wifi_logging_cleanup' into integration 2026-01-05 22:35:53 -10:00
J. Nick Koston
570ecd1842 tweak 2026-01-05 22:35:40 -10:00
J. Nick Koston
3502ac7bee tweak 2026-01-05 22:33:14 -10:00
J. Nick Koston
04cc713b0c Merge branch 'wifi_logging_cleanup' into integration 2026-01-05 22:29:04 -10:00
J. Nick Koston
63713cac57 [wifi] Clean up duplicate and empty logging output 2026-01-05 22:26:36 -10:00
J. Nick Koston
44ecdeb3b6 Merge branch 'wifi_fix_more_alloc' into integration 2026-01-05 19:35:52 -10:00
J. Nick Koston
913609d985 simplify code 2026-01-05 19:32:47 -10:00
J. Nick Koston
a7b4ae13a3 simplify code 2026-01-05 19:32:11 -10:00
J. Nick Koston
a02583028e Merge branch 'wifi_fix_more_alloc' into integration 2026-01-05 19:24:19 -10:00
J. Nick Koston
43e0f1fb35 [wifi] Eliminate heap allocations in IP address logging 2026-01-05 19:23:46 -10:00
J. Nick Koston
b8faecfd4e Merge branch 'slash_workaround' into integration 2026-01-05 18:49:34 -10:00
J. Nick Koston
4b4c1c1191 [core] Auto-replace / in entity names with Unicode fraction slash during deprecation period 2026-01-05 18:46:54 -10:00
J. Nick Koston
4a499054b7 Merge branch 'bind_key_simplify' into integration 2026-01-05 18:25:01 -10:00
J. Nick Koston
2d65717e43 Merge remote-tracking branch 'origin/improv_next_url' into integration 2026-01-05 18:24:55 -10:00
J. Nick Koston
d8731d376d fixes 2026-01-05 18:23:43 -10:00
J. Nick Koston
d42567c5b0 [improv_base] Optimize next_url to avoid STL string operations 2026-01-05 18:20:23 -10:00
J. Nick Koston
b5ea8a4627 [xiaomi_ble] Simplify set_bindkey using parse_hex and const char* 2026-01-05 18:17:58 -10:00
J. Nick Koston
bc54c5aff3 Merge branch 'ble_scanner_reduce_realloc' into integration 2026-01-05 18:02:40 -10:00
J. Nick Koston
442cd60341 [ble_scanner] Use stack-based string formatting to reduce heap allocations 2026-01-05 17:55:41 -10:00
J. Nick Koston
0a9287df33 Merge remote-tracking branch 'upstream/dev' into integration
# Conflicts:
#	esphome/components/bedjet/bedjet_hub.cpp
#	esphome/components/esp8266/preferences.cpp
#	esphome/components/radon_eye_ble/radon_eye_listener.cpp
#	esphome/components/radon_eye_rd200/radon_eye_rd200.cpp
2026-01-05 17:48:09 -10:00
J. Nick Koston
22cb0da903 [radon_eye_rd200, radon_eye_ble] Use stack-based string formatting in logging (#12991) 2026-01-05 17:45:51 -10:00
Jas Strong
28cf3b7a9b [rd03d] Add Ai-Thinker RD-03D mmWave radar component (#12764)
Co-authored-by: jas <jas@asspa.in>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-05 22:35:32 -05:00
J. Nick Koston
84dd17187d [pvvx_mithermometer] Reduce heap allocations with stack-based string formatting (#12994) 2026-01-05 17:35:22 -10:00
J. Nick Koston
110c892c3c [esp8266] Avoid heap allocation in preferences save/load (#12465)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-05 17:35:04 -10:00
J. Nick Koston
8518424a88 [esp8266] Add enable_serial/enable_serial1 helpers to exclude unused Serial objects (#12736) 2026-01-05 17:26:49 -10:00
J. Nick Koston
7ba4dc0f1a [airthings_wave_base, airthings_ble] Use stack-based string formatting in logging (#12989) 2026-01-05 17:22:27 -10:00
J. Nick Koston
95573bc106 [mopeka] Reduce heap allocations with stack-based string formatting (#12990) 2026-01-05 17:21:54 -10:00
J. Nick Koston
a6adc29b14 [xiaomi_ble] Reduce heap allocations with stack-based string formatting (#12992) 2026-01-05 17:20:51 -10:00
J. Nick Koston
8251513556 [bedjet] Use stack-based UUID formatting in logging (#12993) 2026-01-05 17:19:34 -10:00
J. Nick Koston
e6e0be3345 [bthome_mithermometer] Reduce heap allocations with stack-based string formatting (#12995) 2026-01-05 17:18:58 -10:00
J. Nick Koston
64da6d46e9 [ruuvi_ble] Reduce heap allocation with stack-based string formatting (#12997) 2026-01-05 17:18:06 -10:00
J. Nick Koston
9b9a341db0 [b_parasite] Reduce heap allocation with stack-based string formatting (#12998) 2026-01-05 17:17:37 -10:00
J. Nick Koston
18217fbe10 [atc_mithermometer] Reduce heap allocations with stack-based string formatting (#12996) 2026-01-05 17:16:47 -10:00
J. Nick Koston
c3e6a4178c [thermopro_ble] Reduce heap allocation with stack-based string formatting (#12999) 2026-01-05 17:16:14 -10:00
J. Nick Koston
2d4cd4ce7e [midea] Reduce heap allocations with stack-based string formatting (#13000) 2026-01-05 17:15:50 -10:00
J. Nick Koston
0290ed5d23 [voice_assistant] Reduce heap allocation with stack-based timer formatting (#13001) 2026-01-05 17:14:33 -10:00
Evaldas Auryla
b402e403a0 [radon_eye_rd200] update Radon Eye RD200 with v2/v3 support (#7962)
Co-authored-by: Artem Butusov <art.sormy@gmail.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-05 16:34:23 -10:00
J. Nick Koston
b34260d5c8 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-05 16:21:07 -10:00
J. Nick Koston
4a97bd4859 Merge branch 'host_logger_thread_safe' into integration 2026-01-05 15:26:26 -10:00
J. Nick Koston
0453c74133 Address Copilot review: fix pthread_setname_np for Linux, simplify loop() condition 2026-01-05 15:14:24 -10:00
J. Nick Koston
a6a7b41b2e Merge remote-tracking branch 'origin/host_logger_thread_safe' into host_logger_thread_safe 2026-01-05 15:11:27 -10:00
J. Nick Koston
327458169c bot nits 2026-01-05 15:11:01 -10:00
Jonathan Swoboda
b2c22a02b1 [cc1101] Add freq_offset to on_packet trigger (#13008) 2026-01-05 20:08:07 -05:00
J. Nick Koston
f237d96121 Merge branch 'dev' into host_logger_thread_safe 2026-01-05 14:59:34 -10:00
J. Nick Koston
21b0955d4f [logger] Add thread-safe logging for host platform 2026-01-05 14:58:29 -10:00
J. Nick Koston
d3a128803c add diagram 2026-01-05 14:55:48 -10:00
J. Nick Koston
813012a65d remove dead code 2026-01-05 14:53:42 -10:00
J. Nick Koston
993070156a host has plenty of ram, do not give a knob, its not needed 2026-01-05 14:50:55 -10:00
J. Nick Koston
4a3e3a3b37 host has plenty of ram, do not give a knob, its not needed 2026-01-05 14:50:46 -10:00
J. Nick Koston
602bde0e5d reduce ram 2026-01-05 14:49:24 -10:00
J. Nick Koston
4c0e45ea5d wip 2026-01-05 14:43:48 -10:00
J. Nick Koston
707337d27a tweak 2026-01-05 14:33:40 -10:00
J. Nick Koston
6ea3dd8975 tweak 2026-01-05 14:33:00 -10:00
J. Nick Koston
c64514acdc tweak 2026-01-05 14:31:38 -10:00
J. Nick Koston
0d2c48a55a tweak 2026-01-05 14:29:52 -10:00
J. Nick Koston
b2f1f0faad tweak 2026-01-05 14:26:55 -10:00
J. Nick Koston
f0775d7ae0 host logger thread safe 2026-01-05 14:21:36 -10:00
PolarGoose
7ed4922d28 [dsmr] Remove dependency on Arduino framework. Various bug fixes. Add missing sensors. (#11036)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-06 00:18:54 +00:00
Clyde Stubbs
21aa245cff [image] Replace use of cairosvg with resvg-py (#12863)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-06 10:56:59 +11:00
David Woodhouse
94bedd83be async_tcp: Add AsyncClient for ESP-IDF and host (#12337)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-05 23:37:38 +00:00
guillempages
c8f5a97cef [esphome OTA] Allow compilation on host platform (#11655)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-05 23:33:06 +00:00
J. Nick Koston
90597a1255 Merge branch 'esp8266_prefs_avoid_heap' into integration 2026-01-05 09:34:27 -10:00
J. Nick Koston
3fed238f79 Merge branch 'voice_assistant_format_stack' into integration 2026-01-05 09:28:10 -10:00
J. Nick Koston
cc8bd2d29d dry 2026-01-05 09:26:41 -10:00
J. Nick Koston
7a0d7c5ca1 [voice_assistant] Reduce heap allocation with stack-based timer formatting 2026-01-05 09:24:33 -10:00
J. Nick Koston
bc7b2d317c Merge branch 'midea_stack_format' into integration 2026-01-05 09:21:12 -10:00
J. Nick Koston
334b7168bd [midea] Reduce heap allocations with stack-based string formatting 2026-01-05 09:20:45 -10:00
J. Nick Koston
8aaa51e5c7 Merge branch 'thermopro_ble' into integration 2026-01-05 09:16:35 -10:00
J. Nick Koston
d9568251dc [thermopro_ble] Reduce heap allocation with stack-based string formatting 2026-01-05 09:16:04 -10:00
J. Nick Koston
652660ca57 Merge branch 'b_parasite' into integration 2026-01-05 09:14:55 -10:00
J. Nick Koston
6b9f105b0b [b_parasite] Reduce heap allocation with stack-based string formatting 2026-01-05 09:14:26 -10:00
J. Nick Koston
8751e00077 Merge branch 'ruuvi_ble' into integration 2026-01-05 09:13:04 -10:00
J. Nick Koston
647c727708 [ruuvi_ble] Reduce heap allocation with stack-based string formatting 2026-01-05 09:12:36 -10:00
J. Nick Koston
b376b78625 Merge branch 'atc_mithermometer' into integration 2026-01-05 09:10:41 -10:00
J. Nick Koston
fdb4d411ce [atc_mithermometer] Reduce heap allocations with stack-based string formatting 2026-01-05 09:09:11 -10:00
J. Nick Koston
a762590b35 Merge branch 'bthome_mithermometer_logging' into integration 2026-01-05 09:06:33 -10:00
J. Nick Koston
6f1185011f [bthome_mithermometer] Reduce heap allocations with stack-based string formatting 2026-01-05 09:04:12 -10:00
J. Nick Koston
8092215de1 [bthome_mithermometer] Reduce heap allocations with stack-based string formatting 2026-01-05 09:02:46 -10:00
J. Nick Koston
b4a1421c71 Merge branch 'pvvx_mithermometer_format' into integration 2026-01-05 08:58:43 -10:00
J. Nick Koston
fc9b0cd56c [pvvx_mithermometer] Reduce heap allocations with stack-based string formatting 2026-01-05 08:58:08 -10:00
J. Nick Koston
16c61afb15 Merge branch 'bedjet_logging' into integration 2026-01-05 08:55:52 -10:00
J. Nick Koston
754a34357d [bedjet] Use stack-based UUID formatting in logging 2026-01-05 08:55:14 -10:00
J. Nick Koston
dc7aeec9ee Merge branch 'xiaomi_heap_logging' into integration 2026-01-05 08:53:13 -10:00
J. Nick Koston
cc3e05dece Merge branch 'mopeka_stack_format' into integration 2026-01-05 08:53:08 -10:00
J. Nick Koston
92399e58fc Merge branch 'radon_eye_stack' into integration 2026-01-05 08:53:04 -10:00
J. Nick Koston
70792ac9c5 fix bug 2026-01-05 08:52:20 -10:00
J. Nick Koston
152a146946 reduce 2026-01-05 08:50:24 -10:00
J. Nick Koston
0184636cde [xiaomi_ble] Reduce heap allocations with stack-based string formatting 2026-01-05 08:48:29 -10:00
J. Nick Koston
215fa497d8 Merge branch 'radon_eye_stack' into integration 2026-01-05 08:38:11 -10:00
J. Nick Koston
6dbcb28012 [radon_eye_rd200, radon_eye_ble] Use stack-based string formatting in logging 2026-01-05 08:28:04 -10:00
J. Nick Koston
204a15d53f Merge branch 'airthings_stack_format_logs' into integration 2026-01-05 08:26:03 -10:00
J. Nick Koston
de060e3209 Merge branch 'mopeka_stack_format' into integration 2026-01-05 08:25:55 -10:00
J. Nick Koston
879c6b87bb [mopeka] Reduce heap allocations with stack-based string formatting 2026-01-05 08:25:16 -10:00
J. Nick Koston
bed16ee76a [airthings_wave_base, airthings_ble] Use stack-based string formatting in logging 2026-01-05 08:21:31 -10:00
J. Nick Koston
1be3cab71d Merge branch 'logger_esp8266' into integration 2026-01-05 08:15:34 -10:00
J. Nick Koston
4a31fd6a9c escape hatch 2026-01-05 08:10:13 -10:00
J. Nick Koston
6974e8b767 keep error log 2026-01-05 07:44:21 -10:00
J. Nick Koston
fc7e55bfdc [api] Avoid heap string copies in Home Assistant state subscription callbacks (#12506) 2026-01-05 07:42:18 -10:00
J. Nick Koston
54c9f0db42 Merge branch 'dev' into esp8266_prefs_avoid_heap 2026-01-05 07:41:25 -10:00
J. Nick Koston
6aaaae5d0e [ci] Add LibreTiny (BK72XX) to memory impact analysis (#12983)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-05 07:40:49 -10:00
J. Nick Koston
e87a3b3916 [light] Use zero-copy set_effect overload in JSON schema parsing (#12979) 2026-01-05 07:40:24 -10:00
J. Nick Koston
3fb5b28930 [captive_portal] Avoid defer overhead on ESP8266 when saving WiFi credentials (#12981) 2026-01-05 07:40:04 -10:00
J. Nick Koston
1bb4be435c [esp32_ble_tracker, ble_client] Reduce heap allocations with stack-based string formatting (#12982) 2026-01-05 07:39:37 -10:00
J. Nick Koston
0990a9c2b0 [esp32_ble] Avoid heap allocation in ESPBTUUID::from_raw for string literals (#12980) 2026-01-05 07:39:24 -10:00
Samuel Schultze
086eb4b930 [whirlpool] support for 14 byte whirlpool IR receiver messages (#12774)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-05 11:45:32 -05:00
J. Nick Koston
ed03b09b61 Merge remote-tracking branch 'upstream/avoid_heap_address_str' into integration 2026-01-04 19:30:02 -10:00
J. Nick Koston
f7109c6ced more 2026-01-04 19:28:10 -10:00
J. Nick Koston
d4e3396ce1 Merge remote-tracking branch 'upstream/avoid_heap_address_str' into integration 2026-01-04 19:20:31 -10:00
J. Nick Koston
dbfef45fbb [esp32_ble_tracker, ble_client] Reduce heap allocations with stack-based string formatting 2026-01-04 19:19:23 -10:00
J. Nick Koston
dc7b5a5498 Merge branch 'no_defer_cap_port_8266' into integration 2026-01-04 18:52:01 -10:00
J. Nick Koston
d46982a6af [captive_portal] Avoid defer overhead on ESP8266 when saving WiFi credentials 2026-01-04 18:51:13 -10:00
J. Nick Koston
454471d923 Merge remote-tracking branch 'origin/esp_btuid_from_raw_no_heap_alloc' into integration 2026-01-04 18:33:01 -10:00
J. Nick Koston
6dc8e8ce64 Revert "constexpr"
This reverts commit 5ed2043037.
2026-01-04 18:27:53 -10:00
J. Nick Koston
5ed2043037 constexpr 2026-01-04 18:21:06 -10:00
J. Nick Koston
bd8f9d5984 [esp32_ble] Avoid heap allocation in ESPBTUUID::from_raw for string literals 2026-01-04 18:14:55 -10:00
J. Nick Koston
851f3733db Merge branch 'avoid_forced_heap_alloc_light_json_schema' into integration 2026-01-04 18:06:14 -10:00
J. Nick Koston
690cf1aec9 [light] Use zero-copy set_effect overload in JSON schema parsing 2026-01-04 18:05:48 -10:00
J. Nick Koston
d107b37d3b [st7735] Combine log statements to reduce loop blocking (#12977) 2026-01-04 17:51:02 -10:00
J. Nick Koston
0aa8cfcff5 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-04 17:03:54 -10:00
J. Nick Koston
80ab9485e0 [spi_led_strip] Combine log statements to reduce loop blocking (#12968) 2026-01-04 17:00:59 -10:00
J. Nick Koston
28d30fdddb [ssd1306_i2c] Combine log statements to reduce loop blocking (#12969) 2026-01-04 17:00:40 -10:00
J. Nick Koston
0bd8a7e1a0 [ssd1306_spi] Combine log statements to reduce loop blocking (#12970) 2026-01-04 17:00:21 -10:00
J. Nick Koston
2381ea7ff5 [ssd1322_spi] Combine log statements to reduce loop blocking (#12971) 2026-01-04 17:00:09 -10:00
J. Nick Koston
06101c54a5 [ssd1327_spi] Combine log statements to reduce loop blocking (#12973) 2026-01-04 16:59:52 -10:00
J. Nick Koston
ed332a034b [ssd1351_spi] Combine log statements to reduce loop blocking (#12974) 2026-01-04 16:59:36 -10:00
J. Nick Koston
a2bb9468ff [sm2235] Combine log statements to reduce loop blocking (#12964)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-05 02:57:43 +00:00
J. Nick Koston
d8387799d9 [sm2335] Combine log statements to reduce loop blocking (#12965) 2026-01-04 16:56:30 -10:00
J. Nick Koston
ae3cdeda99 [ssd1325_spi] Combine log statements to reduce loop blocking (#12972) 2026-01-04 16:55:55 -10:00
J. Nick Koston
9cd003034c [spi_device] Combine log statements to reduce loop blocking (#12967) 2026-01-04 16:55:31 -10:00
J. Nick Koston
f67a8d0d1f [sonoff_d1] Combine log statements to reduce loop blocking (#12966) 2026-01-04 16:55:11 -10:00
J. Nick Koston
47223965b6 [sm2135] Combine log statements to reduce loop blocking (#12963) 2026-01-04 16:54:17 -10:00
J. Nick Koston
9128fc3120 [sm16716] Combine log statements to reduce loop blocking (#12962) 2026-01-04 16:54:03 -10:00
J. Nick Koston
c742db48b8 [sim800l] Combine log statements to reduce loop blocking (#12961) 2026-01-04 16:52:57 -10:00
J. Nick Koston
4bc1a02fc2 [shtcx] Combine log statements to reduce loop blocking (#12960) 2026-01-04 16:52:03 -10:00
J. Nick Koston
1d0f36ba35 [st7789v] Combine log statements to reduce loop blocking (#12978) 2026-01-04 16:51:37 -10:00
J. Nick Koston
405b26426c [st7567_spi] Combine log statements to reduce loop blocking (#12976) 2026-01-04 16:51:24 -10:00
J. Nick Koston
2295f57dec [st7567_i2c] Combine log statements to reduce loop blocking (#12975) 2026-01-04 16:51:11 -10:00
J. Nick Koston
81a230284f Merge branch 'web_server_br' into integration 2026-01-04 16:28:36 -10:00
J. Nick Koston
a011d5ea96 [sht3xd] Combine log statements to reduce loop blocking (#12957) 2026-01-05 02:14:57 +00:00
tomaszduda23
12027569d3 [nrf52,zigbee] add support for binary_input (#11535)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-04 21:11:14 -05:00
J. Nick Koston
ab0e15e4bb [runtime_stats] Combine log statements to reduce loop blocking (#12954) 2026-01-04 16:10:51 -10:00
J. Nick Koston
9f7925c1d5 [safe_mode] Combine log statements to reduce loop blocking (#12955) 2026-01-04 16:10:19 -10:00
J. Nick Koston
7449421cea [shelly_dimmer] Combine log statements to reduce loop blocking (#12956) 2026-01-04 16:10:06 -10:00
J. Nick Koston
4f20c1ceb1 [rp2040_pwm] Combine log statements to reduce loop blocking (#12952) 2026-01-04 16:09:51 -10:00
J. Nick Koston
452fcd56dd [remote_receiver] Combine log statements to reduce loop blocking (#12951) 2026-01-04 16:08:45 -10:00
J. Nick Koston
44fc156ef6 [remote_base] Combine log statements to reduce loop blocking (#12950) 2026-01-04 16:07:50 -10:00
J. Nick Koston
3ec05a5a13 [radon_eye_rd200] Combine log statements to reduce loop blocking (#12949) 2026-01-04 16:06:55 -10:00
J. Nick Koston
e6a630ae64 [qmp6988] Combine log statements to reduce loop blocking (#12947) 2026-01-04 16:06:34 -10:00
J. Nick Koston
3c8fd5c5c0 [pulse_counter] Combine log statements to reduce loop blocking (#12946) 2026-01-04 16:05:05 -10:00
J. Nick Koston
a635c82830 [pid] Combine log statements to reduce loop blocking (#12942) 2026-01-04 16:04:50 -10:00
J. Nick Koston
b550e2f4f9 [web_server][captive_portal] Add Brotli compression (saves ~11KB flash) 2026-01-04 15:40:25 -10:00
J. Nick Koston
676517fff3 [web_server][captive_portal] Add Brotli compression (saves ~11KB flash) 2026-01-04 15:40:19 -10:00
J. Nick Koston
a16746d30a [web_server][captive_portal] Add Brotli compression (saves ~11KB flash) 2026-01-04 15:38:15 -10:00
J. Nick Koston
0b9fcf9ed3 [pn532] Combine log statements to reduce loop blocking (#12943) 2026-01-04 14:46:21 -10:00
J. Nick Koston
2d8abbb2ac [pn7150] Combine log statements to reduce loop blocking (#12944) 2026-01-04 14:46:09 -10:00
J. Nick Koston
6d8142c539 [rpi_dpi_rgb] Combine log statements to reduce loop blocking (#12953) 2026-01-04 14:45:52 -10:00
J. Nick Koston
50f27cdd77 [pn7160] Combine log statements to reduce loop blocking (#12945) 2026-01-04 14:45:38 -10:00
J. Nick Koston
6c809583d3 [qspi_dbi] Combine log statements to reduce loop blocking (#12948)
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-04 14:45:22 -10:00
J. Nick Koston
4e94d1ba58 Merge branch 'get_peername_stack_save_ram' into integration 2026-01-04 14:07:08 -10:00
J. Nick Koston
cd3f0e9fc4 Merge remote-tracking branch 'upstream/dev' into get_peername_stack_save_ram 2026-01-04 14:06:41 -10:00
J. Nick Koston
f41f0506c1 [pcf8574] Combine log statements to reduce loop blocking (#12941) 2026-01-04 14:05:17 -10:00
J. Nick Koston
850f189225 [api] Fix message batch size mismatch and improve naming consistency (#12940) 2026-01-04 23:44:49 +00:00
J. Nick Koston
a37d4b17eb [wifi] Combine log statements to reduce loop blocking (#12939) 2026-01-04 23:11:48 +00:00
J. Nick Koston
7309a65167 [tlc5971] Combine log statements to reduce loop blocking (#12922) 2026-01-04 13:11:08 -10:00
J. Nick Koston
6e391bb083 Merge branch 'get_peername_stack_save_ram' into integration 2026-01-04 13:07:32 -10:00
J. Nick Koston
8862fcac45 Merge remote-tracking branch 'upstream/dev' into get_peername_stack_save_ram
# Conflicts:
#	esphome/components/voice_assistant/voice_assistant.cpp
2026-01-04 13:05:42 -10:00
J. Nick Koston
7fde110ac5 [voice_assistant] Combine log statements to reduce loop blocking (#12930) 2026-01-04 13:04:22 -10:00
J. Nick Koston
9ed107bc33 [xgzp68xx] Combine log statements to reduce loop blocking (#12935) 2026-01-04 13:04:08 -10:00
J. Nick Koston
b291f359ae [x9c] Combine log statements to reduce loop blocking (#12934) 2026-01-04 13:03:56 -10:00
J. Nick Koston
161545584d [wl_134] Combine log statements to reduce loop blocking (#12933) 2026-01-04 13:03:42 -10:00
J. Nick Koston
3ea11d4e59 [xpt2046] Combine log statements to reduce loop blocking (#12937) 2026-01-04 13:03:22 -10:00
J. Nick Koston
5713d69efe [ufire_ec] Combine log statements to reduce loop blocking (#12925) 2026-01-04 13:03:06 -10:00
J. Nick Koston
9d9f9c3c84 [xiaomi_xmwsdj04mmc] Combine log statements to reduce loop blocking (#12936) 2026-01-04 13:02:52 -10:00
J. Nick Koston
29d332af92 [wireguard] Combine log statements to reduce loop blocking (#12932) 2026-01-04 13:02:02 -10:00
J. Nick Koston
c44d095f8a [usb_host] Combine log statements to reduce loop blocking (#12927) 2026-01-04 13:01:49 -10:00
J. Nick Koston
0b996616b8 [waveshare_epaper] Combine log statements to reduce loop blocking (#12931) 2026-01-04 13:01:33 -10:00
J. Nick Koston
557b6a9ef0 [sun] Combine log statements to reduce loop blocking (#12919) 2026-01-04 13:00:59 -10:00
J. Nick Koston
6e633f7f3b [usb_uart] Combine log statements to reduce loop blocking (#12928) 2026-01-04 13:00:03 -10:00
J. Nick Koston
c59455e445 [mqtt] Combine log statements to reduce loop blocking (#12938) 2026-01-04 12:59:47 -10:00
J. Nick Koston
32b3d27c7c [uln2003] Combine log statements to reduce loop blocking (#12926) 2026-01-04 12:58:42 -10:00
J. Nick Koston
88cb5d9671 [tmp1075] Combine log statements to reduce loop blocking (#12923) 2026-01-04 12:58:20 -10:00
J. Nick Koston
56d1d928f9 [tlc5947] Combine log statements to reduce loop blocking (#12921) 2026-01-04 12:57:10 -10:00
J. Nick Koston
e9cab96cb7 [sx1509] Combine log statements to reduce loop blocking (#12920) 2026-01-04 12:56:50 -10:00
J. Nick Koston
022c42f9ca [tuya] Combine log statements to reduce loop blocking (#12924) 2026-01-04 12:53:58 -10:00
J. Nick Koston
25ef9aff04 [vl53l0x] Combine log statements to reduce loop blocking (#12929) 2026-01-04 12:53:46 -10:00
J. Nick Koston
f4d2fa8da5 Merge branch 'align_max_messages' into integration 2026-01-04 12:47:06 -10:00
J. Nick Koston
1ef6c6a416 move const 2026-01-04 12:46:35 -10:00
J. Nick Koston
a1aaaedf3c Merge branch 'align_max_messages' into integration 2026-01-04 12:43:56 -10:00
J. Nick Koston
9297850afe [api] Fix message batch size mismatch and improve naming consistency 2026-01-04 12:41:01 -10:00
Clyde Stubbs
71940acc49 [esp32_ble] Remove requirement for configured network (#12891) 2026-01-04 22:37:44 +00:00
J. Nick Koston
4bffe5bd4a Merge remote-tracking branch 'upstream/dev' into integration 2026-01-04 11:56:33 -10:00
J. Nick Koston
05695affff [m5stack_8angle] Combine log statements to reduce loop blocking (#12908) 2026-01-04 11:55:31 -10:00
J. Nick Koston
f2308c77c6 [libretiny_pwm] Combine log statements to reduce loop blocking (#12907) 2026-01-04 11:55:18 -10:00
J. Nick Koston
a5368d1d95 [modbus] Combine log statements to reduce loop blocking (#12910) 2026-01-04 11:54:47 -10:00
J. Nick Koston
b8d93f2150 [mopeka_std_check] Combine log statements to reduce loop blocking (#12911) 2026-01-04 11:54:31 -10:00
J. Nick Koston
ca574a1550 [ledc] Combine log statements to reduce loop blocking (#12906) 2026-01-04 11:54:14 -10:00
J. Nick Koston
b0855b4a0e [lc709203f] Combine log statements to reduce loop blocking (#12905) 2026-01-04 11:53:50 -10:00
J. Nick Koston
1fccddf67f [ina2xx_base] Combine log statements to reduce loop blocking (#12904) 2026-01-04 11:52:56 -10:00
J. Nick Koston
548600b47a [ina260] Combine log statements to reduce loop blocking (#12903) 2026-01-04 11:52:34 -10:00
J. Nick Koston
9bbfad4a08 [honeywellabp] Combine log statements to reduce loop blocking (#12902) 2026-01-04 11:52:08 -10:00
J. Nick Koston
8ae1f26b6a [hlw8012] Combine log statements to reduce loop blocking (#12901) 2026-01-04 11:51:45 -10:00
J. Nick Koston
9b2a36a313 [hc8] Combine log statements to reduce loop blocking (#12900) 2026-01-04 11:51:33 -10:00
J. Nick Koston
aa4b274b3c [mcp3204] Combine log statements to reduce loop blocking (#12912) 2026-01-04 11:51:18 -10:00
J. Nick Koston
d1d5c942ec [mcp9600] Combine log statements to reduce loop blocking (#12913) 2026-01-04 11:51:01 -10:00
J. Nick Koston
a336cba035 Merge branch 'get_peername_stack_save_ram' into integration 2026-01-04 11:47:52 -10:00
J. Nick Koston
aa30a1d008 all 3 2026-01-04 11:47:34 -10:00
J. Nick Koston
591b5fa25b all 3 2026-01-04 11:45:27 -10:00
J. Nick Koston
96b59af983 all 3 2026-01-04 11:42:07 -10:00
J. Nick Koston
17250c7244 Merge remote-tracking branch 'upstream/get_peername_stack_save_ram' into integration 2026-01-04 11:28:41 -10:00
J. Nick Koston
ccc9d95c9d [mqtt] Combine log statements to reduce loop blocking (#12914) 2026-01-04 11:28:14 -10:00
J. Nick Koston
6d9d593e12 [my9231] Combine log statements to reduce loop blocking (#12915) 2026-01-04 11:27:14 -10:00
J. Nick Koston
fc9683f024 [opentherm] Combine log statements to reduce loop blocking (#12916) 2026-01-04 11:26:13 -10:00
J. Nick Koston
61ecfb5f2b [openthread] Combine log statements to reduce loop blocking (#12917) 2026-01-04 11:25:52 -10:00
J. Nick Koston
7e75826064 [wifi] Fix LibreTiny thread safety with queue-based event handling (#12833) 2026-01-04 11:25:24 -10:00
J. Nick Koston
8287484a36 [gl_r01_i2c] Combine log statements to reduce loop blocking (#12899) 2026-01-04 11:24:51 -10:00
J. Nick Koston
dd8259b2ce [gcja5] Combine log statements to reduce loop blocking (#12898) 2026-01-04 11:24:36 -10:00
J. Nick Koston
520f8eb9ef simplify 2026-01-04 11:18:44 -10:00
J. Nick Koston
2d0dd93ae8 Merge remote-tracking branch 'upstream/dev' into get_peername_stack_save_ram 2026-01-04 11:16:44 -10:00
J. Nick Koston
cb4a974144 simplify 2026-01-04 11:13:58 -10:00
J. Nick Koston
5143ef4f2d Merge remote-tracking branch 'upstream/dev' into integration 2026-01-04 10:56:13 -10:00
Stuart Parmenter
449e478bec [hub75] Bump esp-hub75 version to 0.2.2 (#12674) 2026-01-04 10:50:10 -10:00
Jonathan Swoboda
9ae19d53dc [ultrasonic] Fix timeout issues and deprecate timeout option (#12897)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-04 13:39:56 -05:00
J. Nick Koston
77b3ffee00 [factory_reset] Combine log statements to reduce loop blocking (#12866) 2026-01-04 08:34:16 -10:00
J. Nick Koston
dff8dc0ed1 [cc1101] Combine log statements to reduce loop blocking (#12869) 2026-01-04 08:34:07 -10:00
J. Nick Koston
5a8b0f59b8 [cd74hc4067] Combine log statements to reduce loop blocking (#12870) 2026-01-04 08:33:58 -10:00
J. Nick Koston
25a325da61 [current_based] Combine log statements to reduce loop blocking (#12873) 2026-01-04 08:33:49 -10:00
J. Nick Koston
a6db5a2ed8 [dfrobot_sen0395] Combine log statements to reduce loop blocking (#12876) 2026-01-04 08:33:38 -10:00
J. Nick Koston
9e5dbb073a [emmeti] Combine log statements to reduce loop blocking (#12878) 2026-01-04 08:31:14 -10:00
J. Nick Koston
cf513975f3 [ens160_base] Combine log statements to reduce loop blocking (#12880) 2026-01-04 08:30:45 -10:00
J. Nick Koston
1e70091a27 [esp32_hosted] Combine log statements to reduce loop blocking (#12884) 2026-01-04 08:28:17 -10:00
J. Nick Koston
766826cc9c [esp32][libretiny] Reuse preference buffer to avoid heap churn (#12890) 2026-01-04 08:28:01 -10:00
J. Nick Koston
8a4ee19c0b [es8388] Combine log statements to reduce loop blocking (#12882) 2026-01-04 08:26:19 -10:00
J. Nick Koston
b1f9c08f51 [esp32_ble_tracker] Make start_scan action idempotent (#12864) 2026-01-04 08:11:36 -10:00
J. Nick Koston
d328ccd1da Merge branch 'get_peername_stack_save_ram' into integration 2026-01-03 22:11:28 -10:00
J. Nick Koston
d7006a839b Merge remote-tracking branch 'upstream/get_peername_stack_save_ram' into get_peername_stack_save_ram 2026-01-03 22:01:59 -10:00
J. Nick Koston
156ef8df64 reduce 2026-01-03 22:01:25 -10:00
J. Nick Koston
cd5c04bc1e Merge branch 'dev' into get_peername_stack_save_ram 2026-01-03 21:55:03 -10:00
J. Nick Koston
a4accc14c4 Merge branch 'prefs_no_churn_reuse' into integration 2026-01-03 21:21:03 -10:00
J. Nick Koston
9c37443757 guard 2026-01-03 21:20:16 -10:00
J. Nick Koston
8ac16bac7d Merge branch 'prefs_no_churn_reuse' into integration 2026-01-03 21:17:02 -10:00
J. Nick Koston
0f6b9818e4 [esp32][libretiny] Reuse preference buffer to avoid heap churn 2026-01-03 21:16:25 -10:00
J. Nick Koston
facf4777a4 [ezo_pmp] Combine log statements to reduce loop blocking (#12888) 2026-01-03 18:04:00 -10:00
J. Nick Koston
096de869b6 [esp32_ble_client] Combine log statements to reduce loop blocking (#12883) 2026-01-03 18:01:55 -10:00
J. Nick Koston
c59314ec09 [debug] Combine log statements to reduce loop blocking (#12875) 2026-01-03 18:01:28 -10:00
J. Nick Koston
e94158a12f [fan] Combine log statements to reduce loop blocking (#12889) 2026-01-03 18:00:52 -10:00
J. Nick Koston
cb598c43e8 [endstop] Combine log statements to reduce loop blocking (#12879) 2026-01-03 18:00:31 -10:00
J. Nick Koston
6e8817cbc4 [esp8266_pwm] Combine log statements to reduce loop blocking (#12885) 2026-01-03 18:00:11 -10:00
J. Nick Koston
9f06f046d6 [espnow] Combine log statements to reduce loop blocking (#12887) 2026-01-03 17:59:53 -10:00
J. Nick Koston
44fa6bae95 [dht] Combine log statements to reduce loop blocking (#12877) 2026-01-03 17:57:53 -10:00
J. Nick Koston
bc9093127e [cap1188] Combine log statements to reduce loop blocking (#12868) 2026-01-03 17:00:14 -10:00
J. Nick Koston
cf93b66306 [chsc6x] Combine log statements to reduce loop blocking (#12871) 2026-01-03 16:59:55 -10:00
J. Nick Koston
16ada4d477 [epaper_spi] Combine log statements to reduce loop blocking (#12881) 2026-01-04 02:48:39 +00:00
J. Nick Koston
c96d0015a0 [esp_ldo] Combine log statements to reduce loop blocking (#12886) 2026-01-04 02:48:04 +00:00
J. Nick Koston
12c6f5749e [cst816] Combine log statements to reduce loop blocking (#12872) 2026-01-04 02:46:29 +00:00
Douwe
5f1eacf4ec [water_heater] (4/4) Implement tests for new water_heater component (#12517)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-03 16:43:31 -10:00
J. Nick Koston
5d384c77c5 [esp32] Move heap functions to flash, saving ~6KB (#12862) 2026-01-03 16:00:50 -10:00
dependabot[bot]
32562ca991 Bump aioesphomeapi from 43.10.0 to 43.10.1 (#12865)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-04 01:59:03 +00:00
J. Nick Koston
6b4b1272db [binary_sensor] Combine log statements to reduce loop blocking (#12849) 2026-01-04 01:56:52 +00:00
J. Nick Koston
7b74f94360 [wifi] Combine log statements to reduce loop blocking (#12856)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-04 01:54:56 +00:00
J. Nick Koston
79de1bc609 Merge branch 'esp32_ble_automations' into integration 2026-01-03 15:54:36 -10:00
J. Nick Koston
93adab389e [esp32_ble_tracker] Make start_scan action idempotent 2026-01-03 15:54:15 -10:00
J. Nick Koston
997ab553c1 [ac_dimmer] Combine log statements to reduce loop blocking (#12840)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2026-01-04 01:36:08 +00:00
Frederic Meeuwissen
8b80fe9c6b [esp32_rmt_led_strip] Support inverted logic (#12825)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-03 20:32:27 -05:00
J. Nick Koston
ee65f2f0cd [adc] Combine log statements to reduce loop blocking (#12841) 2026-01-03 15:24:41 -10:00
J. Nick Koston
c2c7d4e89d Merge branch 'heap-in-iram-flash' into integration 2026-01-03 15:22:29 -10:00
J. Nick Koston
ba1bbaf67d [esp32] Move heap functions to flash, saving ~6KB
This is the culmination of months of work to reduce heap churn
throughout the ESPHome codebase. By systematically eliminating
unnecessary dynamic allocations (StaticVector, FixedVector, const
char* instead of std::string, pre-allocated buffers, etc.), heap
functions are now called so infrequently that they can safely be
moved from IRAM to flash.

Enable CONFIG_HEAP_PLACE_FUNCTION_INTO_FLASH by default, which moves
malloc/free/realloc from IRAM to flash. This is safe because:
- Heap functions should never be called from ISRs
- CONFIG_SPI_MASTER_ISR_IN_IRAM is not enabled
- Audio/video use pre-allocated ring buffers, not dynamic allocation

Measured results: +6,124 bytes of heap freed.

Add heap_in_iram advanced option as an escape hatch for users who
need heap functions in IRAM for specific use cases.
2026-01-03 15:10:32 -10:00
J. Nick Koston
723ccd7547 [ade7880] Combine log statements to reduce loop blocking (#12842) 2026-01-03 15:05:41 -10:00
J. Nick Koston
102862e99d [ads1115] Combine log statements to reduce loop blocking (#12843) 2026-01-03 15:05:29 -10:00
J. Nick Koston
9cb265347c [ads1118] Combine log statements to reduce loop blocking (#12844) 2026-01-03 15:05:15 -10:00
J. Nick Koston
d84562f878 [anova] Combine log statements to reduce loop blocking (#12845) 2026-01-03 15:04:57 -10:00
J. Nick Koston
6bbee3cfc6 [as3935] Combine log statements to reduce loop blocking (#12846) 2026-01-03 15:04:38 -10:00
J. Nick Koston
41e7ecb29f [bedjet] Combine log statements to reduce loop blocking (#12848) 2026-01-03 15:04:21 -10:00
J. Nick Koston
0196d6ee55 [ble_nus] Combine log statements to reduce loop blocking (#12850) 2026-01-03 15:03:44 -10:00
J. Nick Koston
ea848db683 [bp1658cj] Combine log statements to reduce loop blocking (#12851) 2026-01-03 15:03:20 -10:00
J. Nick Koston
41a188ac35 [ac_dimmer] Fix ESP8266 build by requiring waveform support (#12852) 2026-01-03 15:03:01 -10:00
J. Nick Koston
8ddfeb2d38 [captive_portal] Combine log statements to reduce loop blocking (#12853) 2026-01-03 15:02:26 -10:00
J. Nick Koston
d364432e3a [uart] Combine log statements to reduce loop blocking (#12855) 2026-01-03 15:02:12 -10:00
J. Nick Koston
2a6b192af8 [ethernet] Combine log statements to reduce loop blocking (#12854) 2026-01-03 15:01:35 -10:00
J. Nick Koston
07a581e13a [update] Combine log statements to reduce loop blocking (#12857) 2026-01-03 15:01:24 -10:00
J. Nick Koston
5f5edf90e9 [water_heater] Combine log statements to reduce loop blocking (#12858) 2026-01-03 15:01:12 -10:00
J. Nick Koston
5e24469ce3 [http_request] Combine log statements to reduce loop blocking (#12859) 2026-01-03 15:01:01 -10:00
J. Nick Koston
d7a1ac83ca [esp32_ble_tracker] Combine log statements to reduce loop blocking (#12860) 2026-01-03 15:00:51 -10:00
Douwe
f11abc7dbf [water_heater] (2/4) Implement template for new water_heater component (#12516)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-03 14:45:49 -10:00
J. Nick Koston
f98cc96a6f Merge branch 'combine-logs-captive_portal' into integration 2026-01-03 14:35:05 -10:00
J. Nick Koston
dff89193dd Merge branch 'combine-logs-uart' into integration 2026-01-03 14:35:01 -10:00
J. Nick Koston
b868d0f254 Merge branch 'combine-logs-ethernet' into integration 2026-01-03 14:34:54 -10:00
tomaszduda23
ec05692f0d [nrf52] add printk doc (#12839) 2026-01-04 00:12:31 +00:00
J. Nick Koston
2e2e54811a [absolute_humidity] Combine log statements to reduce loop blocking (#12838) 2026-01-03 17:52:23 -06:00
J. Nick Koston
6d7949c686 [uart] Combine log statements to reduce loop blocking 2026-01-03 13:26:17 -10:00
J. Nick Koston
f78cf6d6b3 [ethernet] Combine log statements to reduce loop blocking 2026-01-03 13:25:58 -10:00
J. Nick Koston
8f77e0712e [captive_portal] Combine log statements to reduce loop blocking 2026-01-03 13:25:38 -10:00
Clyde Stubbs
c29aa61e2a [image] Use alternative version of CairoSVG on Windows (#12811) 2026-01-04 10:08:47 +11:00
J. Nick Koston
cb3edfc654 [wifi] Use stack-based MAC formatting in ESP8266 and IDF event handlers (#12834) 2026-01-03 12:32:22 -10:00
J. Nick Koston
6685fa1da9 [core] Fix startup delay from setup timing logs when console connected (#12832) 2026-01-03 12:32:10 -10:00
J. Nick Koston
d505f0316b [wifi] Combine scan result log lines to reduce loop blocking with many matching APs (#12830) 2026-01-03 12:31:58 -10:00
J. Nick Koston
9781073f2a [espnow] Use stack-based MAC formatting and remove dead code (#12836) 2026-01-03 12:31:38 -10:00
John Hollowell
0a0501c140 Fix comment typos (#12828) 2026-01-03 17:11:48 -05:00
Jasper van der Neut - Stulen
a6e9aa7876 [mhz19] Refactor Actions to Parented (#12837) 2026-01-03 17:11:02 -05:00
Conrad Juhl Andersen
ede7391582 [wts01] Fix negative values for WTS01 sensor (#12835) 2026-01-03 17:06:33 -05:00
J. Nick Koston
1a86f7c67c Merge branch 'espnow_mac_format' into integration 2026-01-03 11:05:42 -10:00
J. Nick Koston
8a59e13bbc [espnow] Use stack-based MAC formatting and remove dead code 2026-01-03 11:05:20 -10:00
J. Nick Koston
7e31e9823b Merge branch 'wifi_esp8266_idf_format_mac_address_pretty' into integration 2026-01-03 10:59:49 -10:00
J. Nick Koston
becab116c7 [wifi] Use stack-based MAC formatting in ESP8266 and IDF event handlers 2026-01-03 10:59:27 -10:00
J. Nick Koston
28bad19900 Merge branch 'libretiny_thread_safe_wifi' into integration 2026-01-03 10:52:10 -10:00
J. Nick Koston
eada23d587 optimize away 2026-01-03 10:51:56 -10:00
Jasper van der Neut - Stulen
5cfcf8d104 [mhz19] Make detection range configurable (#12677)
Co-authored-by: Fabio Pugliese Ornellas <fabio.ornellas@gmail.com>
2026-01-03 15:51:48 -05:00
J. Nick Koston
a1e5d59161 Merge branch 'libretiny_thread_safe_wifi' into integration 2026-01-03 10:48:33 -10:00
J. Nick Koston
2074447120 tune 2026-01-03 10:48:24 -10:00
J. Nick Koston
f267eac729 Merge branch 'libretiny_thread_safe_wifi' into integration 2026-01-03 10:42:23 -10:00
J. Nick Koston
9187bf52e6 tweak 2026-01-03 10:42:06 -10:00
J. Nick Koston
a95dcad380 Merge branch 'libretiny_thread_safe_wifi' into integration 2026-01-03 10:23:37 -10:00
J. Nick Koston
f0a496b08d [wifi] Fix LibreTiny thread safety with queue-based event handling 2026-01-03 10:22:08 -10:00
J. Nick Koston
cc56702e79 Merge branch 'no_delay_startup_many_entities' into integration 2026-01-03 09:34:22 -10:00
J. Nick Koston
a8e8c9d8b5 [core] Fix startup delay from setup timing logs when console connected 2026-01-03 09:33:43 -10:00
J. Nick Koston
846d46cd72 Merge branch 'wifi_roam' into integration 2026-01-03 09:27:51 -10:00
J. Nick Koston
6dbd0de0b5 tweak 2026-01-03 09:19:31 -10:00
J. Nick Koston
c34665f650 [api] Fix KeyError when running logs after password removal (#12831) 2026-01-03 19:13:07 +00:00
J. Nick Koston
fcab160049 Merge branch 'wifi_roam' into integration 2026-01-03 09:11:26 -10:00
J. Nick Koston
c809f86507 fix refactoring error 2026-01-03 09:11:18 -10:00
J. Nick Koston
a184b00051 Merge branch 'wifi_roam' into integration 2026-01-03 09:08:32 -10:00
J. Nick Koston
f7d9ebcf01 reduce 2026-01-03 09:08:23 -10:00
Mariusz Kryński
69867bf818 [nrf52, zephyr] move nrf52-specific code to nrf52 component (#12582)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2026-01-03 18:58:56 +00:00
J. Nick Koston
16f3605399 Merge branch 'dev' into get_peername_stack_save_ram 2026-01-03 08:02:34 -10:00
J. Nick Koston
c95b00e7fc Merge branch 'get_rid_of_complex_bifurcated_client_server_api_strings' into integration 2026-01-03 08:01:08 -10:00
J. Nick Koston
8cbb2eef84 merge 2026-01-03 08:00:56 -10:00
J. Nick Koston
21556e714b Merge remote-tracking branch 'upstream/dev' into get_rid_of_complex_bifurcated_client_server_api_strings 2026-01-03 08:00:17 -10:00
J. Nick Koston
dd9804aff4 Merge branch 'missing_password_removal' into integration 2026-01-03 07:56:51 -10:00
J. Nick Koston
b93817e872 [api] Fix KeyError when running logs after password removal 2026-01-03 07:42:46 -10:00
J. Nick Koston
af69ca58c6 Merge branch 'many_mesh_still_blocked_loop' into integration 2026-01-03 07:26:03 -10:00
J. Nick Koston
64261d9b04 [wifi] Combine scan result log lines to reduce loop blocking with many APs 2026-01-03 07:24:21 -10:00
J. Nick Koston
1d323c2d71 [api] Remove deprecated password authentication (#12819) 2026-01-03 07:14:48 -10:00
J. Nick Koston
e8de6627d8 document, document, document 2026-01-03 00:44:37 -10:00
J. Nick Koston
6029f24369 Merge branch 'wifi_roam' into integration 2026-01-03 00:42:31 -10:00
J. Nick Koston
b4f24f6a7f Merge remote-tracking branch 'origin/wifi_roam' into wifi_roam 2026-01-03 00:42:21 -10:00
J. Nick Koston
356e6a3c97 document roam fail path 2026-01-03 00:42:06 -10:00
J. Nick Koston
c4820fcc36 Merge branch 'logger_esp8266' into integration 2026-01-03 00:20:27 -10:00
J. Nick Koston
36d1ef9584 fixes 2026-01-03 00:20:02 -10:00
J. Nick Koston
a5269efd48 fixes 2026-01-03 00:16:07 -10:00
J. Nick Koston
46d9cdfe93 Merge branch 'dev' into logger_esp8266 2026-01-03 00:06:49 -10:00
J. Nick Koston
da34fca20c Merge branch 'dev' into wifi_roam 2026-01-02 23:57:41 -10:00
J. Nick Koston
dc159737ec Merge branch 'wifi_roam' into integration 2026-01-02 23:52:08 -10:00
J. Nick Koston
0ba1fe8457 -49 is the boundray for excellent 2026-01-02 23:51:02 -10:00
tomaszduda23
95a7356ea0 [uart] make sure that all variables are initialized (#12823) 2026-01-03 03:43:17 -06:00
J. Nick Koston
a46a51e885 tweak 2026-01-02 23:43:03 -10:00
J. Nick Koston
bb414f1745 Merge branch 'wifi_roam' into integration 2026-01-02 23:34:54 -10:00
J. Nick Koston
9d79a98c0d log cleanup 2026-01-02 23:34:45 -10:00
J. Nick Koston
cc7e075857 Merge branch 'wifi_roam' into integration 2026-01-02 23:24:41 -10:00
J. Nick Koston
b8c0dc7b04 stale comments 2026-01-02 23:24:22 -10:00
J. Nick Koston
7e313de1c1 Merge remote-tracking branch 'upstream/dev' into wifi_roam 2026-01-02 23:22:45 -10:00
J. Nick Koston
68ad5e457a fix stale comment 2026-01-02 23:22:10 -10:00
J. Nick Koston
a020a3421c Merge branch 'wifi_roam' into integration 2026-01-02 23:17:30 -10:00
J. Nick Koston
8fff7f6b85 len 1 2026-01-02 23:16:01 -10:00
J. Nick Koston
27ae2881de Merge branch 'wifi_roam' into integration 2026-01-02 23:11:42 -10:00
J. Nick Koston
2ab27a6ae2 avoid inlining expensive vector ops 2026-01-02 23:11:30 -10:00
J. Nick Koston
22ad0f2f2d handle race 2026-01-02 23:09:45 -10:00
J. Nick Koston
d99fd22f53 Merge branch 'wifi_roam' into integration 2026-01-02 23:06:01 -10:00
J. Nick Koston
f32c190905 optimize 2026-01-02 23:05:39 -10:00
J. Nick Koston
996bd12871 optimize 2026-01-02 23:03:52 -10:00
J. Nick Koston
516c074b8f optimize 2026-01-02 22:58:18 -10:00
J. Nick Koston
1c9e0f6b22 optimize 2026-01-02 22:56:48 -10:00
J. Nick Koston
828a27b1b6 reduce some code size 2026-01-02 22:53:42 -10:00
J. Nick Koston
039ae65ed8 Update esphome/components/wifi/wifi_component.cpp 2026-01-02 22:52:01 -10:00
J. Nick Koston
2275f638fb Merge remote-tracking branch 'origin/wifi_roam' into wifi_roam 2026-01-02 22:51:29 -10:00
J. Nick Koston
369f32b496 reduce some code size 2026-01-02 22:50:38 -10:00
J. Nick Koston
c6774d81cb Merge branch 'wifi_roam' into integration 2026-01-02 22:29:30 -10:00
J. Nick Koston
828e91a61b Merge remote-tracking branch 'origin/get_rid_of_complex_bifurcated_client_server_api_strings' into get_rid_of_complex_bifurcated_client_server_api_strings 2026-01-02 22:19:12 -10:00
J. Nick Koston
fb255d7e7c fixes 2026-01-02 22:19:01 -10:00
J. Nick Koston
c7e9eda5aa Merge branch 'dev' into get_rid_of_complex_bifurcated_client_server_api_strings 2026-01-02 22:11:24 -10:00
J. Nick Koston
979b96f7d4 cleanup 2026-01-02 21:56:38 -10:00
J. Nick Koston
af8c453f7c [api] Simplify string handling by removing bifurcated client/server storage 2026-01-02 21:52:20 -10:00
Keith Burzinski
5db4574cb8 Merge branch 'dev' into get_peername_stack_save_ram 2026-01-03 01:01:07 -06:00
J. Nick Koston
89b550b74a [tests] Remove reserved / character from entity names in component tests (#12820) 2026-01-03 01:00:46 -06:00
dependabot[bot]
538c6544a0 Bump ruamel-yaml from 0.18.17 to 0.19.1 (#12768)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-02 20:51:56 -10:00
dependabot[bot]
98e3695c89 Bump aioesphomeapi from 43.9.1 to 43.10.0 (#12821)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-03 06:45:17 +00:00
J. Nick Koston
ae1082e3e6 Merge branch 'get_peername_stack_save_ram' into integration 2026-01-02 20:31:10 -10:00
J. Nick Koston
a63ed0d616 fix merge conflict 2026-01-02 20:29:45 -10:00
J. Nick Koston
c2ffd4e49a fix merge conflict 2026-01-02 20:28:37 -10:00
J. Nick Koston
c2c513fd75 Merge branch 'dev' into get_peername_stack_save_ram 2026-01-02 20:26:30 -10:00
J. Nick Koston
2ed5015089 Merge branch 'api_avoid_copies' into integration 2026-01-02 20:21:47 -10:00
J. Nick Koston
48760ef927 match it to upstream change 2026-01-02 20:21:06 -10:00
J. Nick Koston
40b09e8cd4 match it to upstream change 2026-01-02 20:20:02 -10:00
J. Nick Koston
61692894e1 Merge branch 'dev' into api_avoid_copies 2026-01-02 20:19:11 -10:00
J. Nick Koston
00fd4f2fdd [esp8266] Exclude unused waveform code to save ~596 bytes RAM (#12690) 2026-01-02 19:51:07 -10:00
J. Nick Koston
2a5be725c8 [api] Enable zero-copy bytes SOURCE_BOTH messages (#12816) 2026-01-02 19:50:30 -10:00
Robert Klep
c4d339a4c9 [core] Add CONF_ON_START (#12439) (#12440) 2026-01-02 23:42:18 -05:00
J. Nick Koston
c25b732d39 Merge remote-tracking branch 'upstream/source_both_zero_copy' into integration 2026-01-02 17:02:10 -10:00
J. Nick Koston
3148cb2bdd Merge branch 'api_avoid_copies' into integration 2026-01-02 17:01:56 -10:00
J. Nick Koston
114624acbd fix conflicts 2026-01-02 16:57:41 -10:00
J. Nick Koston
c82ae34ccf Merge remote-tracking branch 'upstream/dev' into get_peername_stack_save_ram
# Conflicts:
#	esphome/components/api/api_connection.cpp
#	esphome/components/api/api_frame_helper.cpp
#	esphome/components/api/api_frame_helper_noise.cpp
#	esphome/components/api/api_frame_helper_plaintext.cpp
2026-01-02 16:52:04 -10:00
J. Nick Koston
cf46f71933 Merge branch 'dev' into source_both_zero_copy 2026-01-02 16:45:45 -10:00
J. Nick Koston
9fc78d424c Merge remote-tracking branch 'upstream/dev' into api_avoid_copies
# Conflicts:
#	esphome/components/api/api_connection.cpp
2026-01-02 16:44:53 -10:00
J. Nick Koston
6409970f6e [uponor_smatrix] Use stack-based hex formatting in verbose logging (#12797)
Co-authored-by: Stefan Rado <628587+kroimon@users.noreply.github.com>
2026-01-02 16:41:02 -10:00
J. Nick Koston
bc1af007b4 [vbus] Use stack-based hex formatting in verbose logging (#12796) 2026-01-02 16:40:47 -10:00
Thomas Rupprecht
c3ffc1635d [gps] add icon for HDOP and use correct state_class for longitude and… (#12718) 2026-01-02 21:40:28 -05:00
J. Nick Koston
016eeef04a [tee501] Use stack-based hex formatting in verbose logging (#12795) 2026-01-02 16:40:06 -10:00
J. Nick Koston
ace48464a8 [addressable_light] Use StringRef to avoid allocation when saving effect name (#12759) 2026-01-02 16:39:44 -10:00
J. Nick Koston
64ba376330 [hte501] Use stack-based hex formatting in verbose logging (#12794) 2026-01-02 16:37:38 -10:00
J. Nick Koston
d946ddabfd [xiaomi_ble] Use stack-based hex formatting in verbose logging (#12793) 2026-01-02 16:37:16 -10:00
J. Nick Koston
a57011b50b [kuntze] Use stack buffer for hex formatting in verbose logging (#12775) 2026-01-02 16:36:57 -10:00
J. Nick Koston
1240e7907e [api] Use stack-based format_hex_pretty_to for packet logging macros (#12788) 2026-01-02 16:35:44 -10:00
J. Nick Koston
d70b3091c9 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-02 16:35:18 -10:00
J. Nick Koston
f0391f0213 [api] Remove object_id from API protocol - clients compute it from name #12698 (#12818) 2026-01-02 16:32:46 -10:00
J. Nick Koston
3cc6810be5 [core] Remove object_id RAM storage - no longer in hot path after #12627 (#12631) 2026-01-02 15:46:01 -10:00
J. Nick Koston
916370a943 [gpio] Avoid heap allocation in dump_summary (#12760) 2026-01-02 15:42:56 -10:00
J. Nick Koston
3d6c64b657 Merge branch 'dev' into wifi_roam 2026-01-02 14:28:59 -10:00
J. Nick Koston
e2f45c590e [esp32_improv] Use stack buffer for hex formatting in verbose logging (#12737) 2026-01-02 14:28:38 -10:00
J. Nick Koston
7d21411ca4 [epaper_spi] Use stack buffer for hex formatting in command logging (#12734) 2026-01-02 14:27:00 -10:00
J. Nick Koston
56ed5af27d [nextion] Use stack buffers for hex formatting in upload logging (#12733) 2026-01-02 14:26:14 -10:00
J. Nick Koston
c8241b0122 [sonoff_d1] Use stack buffer for hex formatting in logging (#12730) 2026-01-02 14:25:02 -10:00
J. Nick Koston
30efd7fb07 [jsn_sr04t] Use stack buffer for hex formatting in error logging (#12729) 2026-01-02 14:24:47 -10:00
J. Nick Koston
1703343694 [a02yyuw] Use stack buffer for hex formatting in error logging (#12728) 2026-01-02 14:24:30 -10:00
J. Nick Koston
7fa04b6c25 [a01nyub] Use stack buffer for hex formatting in error logging (#12727) 2026-01-02 14:23:33 -10:00
J. Nick Koston
61b6476de4 [opentherm] Replace heap-allocating format calls with printf format specifiers in debug_error (#12726) 2026-01-02 14:23:18 -10:00
J. Nick Koston
b4e5e0bc9b [rc522] Use stack buffers for hex formatting in tag logging (#12725) 2026-01-02 14:22:58 -10:00
J. Nick Koston
f9b4e0e489 [remote_base] Use stack buffer for hex formatting in haier protocol logging (#12723) 2026-01-02 14:22:26 -10:00
J. Nick Koston
9ccb100cca [remote_base] Use stack buffer for hex formatting in mirage protocol logging (#12722) 2026-01-02 14:21:42 -10:00
J. Nick Koston
20b66cba23 [shelly_dimmer] Use stack buffer for hex formatting in command logging (#12721) 2026-01-02 14:21:23 -10:00
J. Nick Koston
b711172b33 [wifi] Use precision format specifier for SSID logging to avoid stack copy (#12704) 2026-01-02 14:21:09 -10:00
J. Nick Koston
0c4184b129 [cse7766] Use stack buffer for hex formatting in debug logging (#12732) 2026-01-02 14:20:17 -10:00
J. Nick Koston
0e108c2178 [esp32] Add minimum_chip_revision setting and log chip revision at startup (#12696) 2026-01-02 14:14:52 -10:00
J. Nick Koston
2230e56347 [wifi] Use stack buffers for IP address logging to avoid heap allocations (#12680) 2026-01-02 14:14:24 -10:00
J. Nick Koston
2ff9535f5f [esp32_improv] Use stack buffer for URL formatting to avoid heap allocation (#12682) 2026-01-02 14:14:12 -10:00
J. Nick Koston
ddb6c6cfd4 [captive_portal] Use stack buffer for IP address logging in DNS server (#12679) 2026-01-02 14:13:59 -10:00
J. Nick Koston
00ab64a3c7 [wifi] Use wifi_ssid_to() to avoid heap allocations in automation and connection checks (#12678) 2026-01-02 14:13:43 -10:00
J. Nick Koston
e732f8469e [udp] Avoid heap allocations when joining multicast groups (#12685) 2026-01-02 14:13:26 -10:00
J. Nick Koston
023be88a87 [tuya] Use stack buffers for hex logging to avoid heap allocations (#12689) 2026-01-02 14:13:08 -10:00
J. Nick Koston
25e60d62cf [mqtt] Avoid heap allocations when logging IP addresses (#12686) 2026-01-02 14:12:04 -10:00
J. Nick Koston
167a42aa27 [api] Use StringRef in send_action_response and send_execute_service_response (#12658) 2026-01-02 14:11:45 -10:00
J. Nick Koston
0ef49a8b73 [ld2410][ld2412][ld2450] Use stack buffers for hex logging (#12688) 2026-01-02 14:11:31 -10:00
J. Nick Koston
e3fe738966 Merge branch 'dev' into source_both_zero_copy 2026-01-02 14:10:27 -10:00
J. Nick Koston
51259888bf [voice_assistant] Use zero-copy buffer access for audio data (#12656) 2026-01-02 14:10:21 -10:00
J. Nick Koston
0b7ff09657 [api] Use pointer to FixedVector for siren tones field (#12657) 2026-01-02 14:09:40 -10:00
J. Nick Koston
8a5e06b6d2 merge 2026-01-02 14:08:09 -10:00
J. Nick Koston
560966ad98 Merge remote-tracking branch 'upstream/dev' into source_both_zero_copy
# Conflicts:
#	script/api_protobuf/api_protobuf.py
2026-01-02 14:07:55 -10:00
J. Nick Koston
f394cf3f4d [packet_transport] Use stack-based format_hex_pretty_to for logging (#12791) 2026-01-02 14:06:03 -10:00
J. Nick Koston
4cb066bcbf [api] Use StringRef in handle_action_response to avoid temporary string (#12655) 2026-01-02 14:05:50 -10:00
J. Nick Koston
e7001c5eea [api] Auto-generate zero-copy pointer access for incoming API bytes fields (#12654) 2026-01-02 14:05:37 -10:00
esphomebot
5bb9ffa0cb Update webserver local assets to 20260102-230255 (#12817) 2026-01-02 23:14:11 +00:00
J. Nick Koston
7438034411 Merge remote-tracking branch 'upstream/dev' into integration 2026-01-02 13:09:46 -10:00
J. Nick Koston
c6713eaccb [web_server] Fix URL collisions with UTF-8 names and sub-devices (#12627) 2026-01-02 13:07:11 -10:00
J. Nick Koston
5b4bd555dd cleanup per bot 2026-01-02 12:36:44 -10:00
J. Nick Koston
9b02daae2b cleanup per bot 2026-01-02 12:35:05 -10:00
J. Nick Koston
d77fc596a9 its going to drop anyways 2026-01-02 11:37:56 -10:00
Jonathan Swoboda
087f521b19 [ultrasonic] Use interrupt-based measurement for reliability (#12617)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-02 15:58:53 -05:00
J. Nick Koston
9906724828 [api] Enable zero-copy bytes for VoiceAssistantAudio and other SOURCE_BOTH messages 2026-01-02 10:56:17 -10:00
Jonathan Swoboda
763515d3a1 [core] Remove unused USE_ESP32_FRAMEWORK_ARDUINO ifdefs (#12813)
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-02 14:47:14 -05:00
J. Nick Koston
5c890fcfc4 add roam diagram 2026-01-02 09:29:59 -10:00
J. Nick Koston
5d8346cfb6 Merge branch 'dev' into bytes_zero_copy_default_api 2026-01-02 08:17:33 -10:00
J. Nick Koston
6d4f4d8d23 [api] Auto-generate StringRef for incoming API string fields (#12648) 2026-01-02 08:17:05 -10:00
J. Nick Koston
0a98f7877c tweak 2026-01-01 22:49:21 -10:00
Tobias Stanzel
d7fd85e610 [spi] Allow any achievable data rate (#12753)
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2026-01-02 18:10:30 +11:00
J. Nick Koston
8acaa16987 [usb_cdc_acm] Use stack-based hex formatting in verbose logging (#12792) 2026-01-02 01:04:11 -06:00
J. Nick Koston
4e8c02b396 [xiaomi_*] Use stack-based hex formatting for bindkey logging (#12798) 2026-01-01 20:25:12 -10:00
J. Nick Koston
a828abf53d [ota] Remove MD5 authentication support (#12707) 2026-01-01 20:24:31 -10:00
J. Nick Koston
ebfa0149cc [light] Use StringRef to avoid allocation in JSON effect name serialization (#12758) 2026-01-01 20:23:37 -10:00
J. Nick Koston
3a4cca0027 [ble_client] Use stack buffer for hex formatting in very verbose logging (#12744) 2026-01-01 20:22:48 -10:00
J. Nick Koston
7702a9ae85 [ethernet] Use stack buffer for hex formatting in very verbose logging (#12742) 2026-01-01 20:22:19 -10:00
J. Nick Koston
2e8baa0493 [esp32_ble_tracker] Use stack buffer for hex formatting in very verbose logging (#12741) 2026-01-01 20:21:33 -10:00
J. Nick Koston
69ec311d21 [hlk_fm22x] Use stack buffer for hex formatting in verbose logging (#12740) 2026-01-01 20:20:58 -10:00
J. Nick Koston
1cc18055ef [i2c] Use stack buffer for hex formatting in verbose logging (#12739) 2026-01-01 20:20:24 -10:00
J. Nick Koston
bcc6bbbf5f [espnow] Use stack buffer for hex formatting in verbose logging (#12738) 2026-01-01 20:19:49 -10:00
J. Nick Koston
71c3d4ca27 [mopeka_std_check] Use stack-based format_hex_pretty_to for very verbose logging (#12790) 2026-01-01 20:19:20 -10:00
J. Nick Koston
c6f3860f90 [ee895] Use stack-based format_hex_to for verbose logging (#12789) 2026-01-01 20:18:23 -10:00
J. Nick Koston
0049c8ad38 [zwave_proxy] Use stack-based format_hex_pretty_to for very verbose logging (#12786) 2026-01-01 20:17:51 -10:00
J. Nick Koston
e1788bba45 [seeed_mr60fda2] Use stack-based format_hex_pretty_to for verbose logging (#12785) 2026-01-01 20:17:22 -10:00
J. Nick Koston
4fcd263ea8 [seeed_mr60bha2] Replace format_hex_pretty with stack-based format_hex_pretty_to (#12784) 2026-01-01 20:16:40 -10:00
J. Nick Koston
c81ce243cc [qspi_dbi] Replace format_hex_pretty with stack-based format_hex_pretty_to (#12783) 2026-01-01 20:13:10 -10:00
J. Nick Koston
7df41124b2 [pn532_spi] Replace format_hex_pretty with stack-based format_hex_pretty_to (#12782) 2026-01-01 20:11:53 -10:00
J. Nick Koston
b5188731f8 [modbus] Use stack buffer for hex formatting in verbose logging (#12780) 2026-01-01 20:10:45 -10:00
J. Nick Koston
0924281545 [mitsubishi] Use stack buffer for hex formatting in verbose logging (#12779) 2026-01-01 20:10:08 -10:00
J. Nick Koston
14e97642f7 [mipi_rgb] Use stack buffer for hex formatting in init sequence logging (#12777) 2026-01-01 20:09:37 -10:00
J. Nick Koston
544aaeaa66 [mipi_dsi] Use stack buffer for hex formatting in very verbose logging (#12776) 2026-01-01 20:08:57 -10:00
Stuart Parmenter
7483bbd6ea [display] Ensure drivers respect clipping during fill() (#12808) 2026-01-02 16:34:39 +11:00
Artur
2841b5fe44 [sn74hc595]: fix 'Attempted read from write-only channel' when using esp-idf framework (#12801) 2026-01-01 23:28:10 -05:00
J. Nick Koston
dd6ed4aea6 [wifi] Add basic post-connect roaming support for stationary devices 2026-01-01 17:48:20 -10:00
J. Nick Koston
ab17775c3e tweaks 2026-01-01 17:45:05 -10:00
J. Nick Koston
dc07926a91 tweaks 2026-01-01 17:44:39 -10:00
J. Nick Koston
291722c50e tweak 2026-01-01 17:18:21 -10:00
J. Nick Koston
8b7bb4ecef wip 2026-01-01 14:59:19 -10:00
J. Nick Koston
1def4df146 wip 2026-01-01 14:57:28 -10:00
J. Nick Koston
ff33e362cf wifi roam 2026-01-01 14:55:16 -10:00
J. Nick Koston
ed435241b1 [mipi_spi] Use stack buffer for hex formatting in verbose logging (#12778) 2026-01-01 11:48:37 -10:00
H. Árkosi Róbert
9847e51fbc [bthome_mithermometer] Add BTHome parsing for Xiaomi Mijia BLE Sensors (#12635) 2026-01-02 08:40:18 +11:00
dependabot[bot]
dc320f455a Bump bleak from 2.1.0 to 2.1.1 (#12804)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-01 09:16:01 -10:00
Clyde Stubbs
1945e85ddc [core] Make LockFreeQueue more widely available (#12766) 2026-01-01 22:07:35 +11:00
J. Nick Koston
84e764fa87 Merge branch 'abbwelcome_format' into integration 2025-12-31 23:12:36 -10:00
J. Nick Koston
54a5c9d4af tweak 2025-12-31 23:09:51 -10:00
J. Nick Koston
1303dfa960 tweak 2025-12-31 23:09:39 -10:00
J. Nick Koston
7ce30b693e Merge branch 'abbwelcome_format' into integration 2025-12-31 23:07:18 -10:00
J. Nick Koston
5caa9b8140 snprintf 2025-12-31 23:03:55 -10:00
J. Nick Koston
42746b4b6f tweak 2025-12-31 22:59:44 -10:00
J. Nick Koston
47603de7ce handle truncate 2025-12-31 22:51:42 -10:00
J. Nick Koston
acb54ebb38 Merge branch 'abbwelcome_format' into integration 2025-12-31 22:46:16 -10:00
J. Nick Koston
819bc0a0f2 [abbwelcome] Use stack-based formatting to eliminate heap allocations 2025-12-31 22:45:45 -10:00
J. Nick Koston
b28385da40 Merge branch 'xiaomi_cgd1' into integration 2025-12-31 22:34:22 -10:00
J. Nick Koston
c6a612f580 fix seperator 2025-12-31 22:30:16 -10:00
J. Nick Koston
ad7f48f16d Merge branch 'xiaomi_cgd1' into integration 2025-12-31 22:25:00 -10:00
J. Nick Koston
22502983df [xiaomi_*] Use stack-based hex formatting for bindkey logging 2025-12-31 22:24:29 -10:00
J. Nick Koston
160e649d86 Merge branch 'xiaomi_ble' into integration 2025-12-31 22:16:46 -10:00
J. Nick Koston
259ca86ed7 fix 2025-12-31 22:09:32 -10:00
J. Nick Koston
4ee1358a9f Merge branch 'uponor_smatrix' into integration 2025-12-31 22:07:02 -10:00
J. Nick Koston
8e4913d78c [uponor_smatrix] Use stack-based hex formatting in verbose logging 2025-12-31 22:06:26 -10:00
J. Nick Koston
b6e05a0570 Merge branch 'vbus_hex' into integration 2025-12-31 22:04:11 -10:00
J. Nick Koston
d4e2d808d7 [vbus] Use stack-based hex formatting in verbose logging 2025-12-31 22:03:40 -10:00
J. Nick Koston
fd65ea1d05 Merge branch 'tee501' into integration 2025-12-31 22:00:13 -10:00
J. Nick Koston
91e9c8b63b [tee501] Use stack-based hex formatting in verbose logging 2025-12-31 21:58:37 -10:00
J. Nick Koston
22d2087563 Merge branch 'hte501' into integration 2025-12-31 21:56:43 -10:00
J. Nick Koston
7588f3b120 [hte501] Use stack-based hex formatting in verbose logging 2025-12-31 21:56:06 -10:00
J. Nick Koston
9e1c14dde5 Merge branch 'xiaomi_ble' into integration 2025-12-31 21:54:31 -10:00
J. Nick Koston
2a262babd3 Merge branch 'usb_cdc_acm_hex' into integration 2025-12-31 21:54:26 -10:00
J. Nick Koston
4ba89d9430 Merge branch 'packet_transport_hex' into integration 2025-12-31 21:54:21 -10:00
J. Nick Koston
22fff2b147 Merge branch 'seeed_mr60fda2' into integration 2025-12-31 21:54:14 -10:00
J. Nick Koston
9928e29f52 Merge branch 'zwave_proxy_hex' into integration 2025-12-31 21:54:09 -10:00
J. Nick Koston
59419a63bd Merge branch 'mopeka_std_check' into integration 2025-12-31 21:54:05 -10:00
J. Nick Koston
9501431908 [xiaomi_ble] Use stack-based hex formatting in verbose logging 2025-12-31 21:52:02 -10:00
J. Nick Koston
7c47c1e3b2 [usb_cdc_acm] Use stack-based hex formatting in verbose logging 2025-12-31 21:48:07 -10:00
J. Nick Koston
d93ed1982e [packet_transport] Use stack-based format_hex_pretty_to for logging 2025-12-31 21:42:13 -10:00
J. Nick Koston
df4ce52deb reduce 2025-12-31 21:37:05 -10:00
J. Nick Koston
fa5aa619ad reduce 2025-12-31 21:34:42 -10:00
J. Nick Koston
ecf6e62b86 [mopeka_std_check] Use stack-based format_hex_pretty_to for very verbose logging 2025-12-31 21:30:17 -10:00
Clyde Stubbs
4313130f2e [lvgl] Fix arc background angles (#12773) 2026-01-01 14:44:21 +11:00
J. Nick Koston
252e35c516 Merge branch 'ee895' into integration 2025-12-31 17:40:59 -10:00
J. Nick Koston
45124c05ad [ee895] Use stack-based format_hex_to for verbose logging 2025-12-31 17:40:25 -10:00
J. Nick Koston
77a95a5fd4 adjust 2025-12-31 17:30:44 -10:00
J. Nick Koston
8dd958fcd1 [api] Use stack-based format_hex_pretty_to for packet logging macros 2025-12-31 17:28:01 -10:00
J. Nick Koston
2a87a70963 Merge branch 'espnow' into integration 2025-12-31 17:25:34 -10:00
J. Nick Koston
5bfb020c1f Merge branch 'epaper_spi' into integration 2025-12-31 17:25:15 -10:00
J. Nick Koston
d2afa9a120 Merge branch 'zwave_proxy_hex' into integration 2025-12-31 17:16:17 -10:00
J. Nick Koston
aade54e3c9 [zwave_proxy] Use stack-based format_hex_pretty_to for very verbose logging 2025-12-31 17:10:52 -10:00
J. Nick Koston
4439d30d27 Merge branch 'seeed_mr60fda2' into integration 2025-12-31 17:04:14 -10:00
J. Nick Koston
38381a0d24 Merge branch 'seeed_mr60bha2' into integration 2025-12-31 17:04:10 -10:00
J. Nick Koston
eddb386277 [seeed_mr60fda2] Use stack-based format_hex_pretty_to for verbose logging 2025-12-31 17:03:32 -10:00
J. Nick Koston
dde20e82f7 [seeed_mr60bha2] Replace format_hex_pretty with stack-based format_hex_pretty_to 2025-12-31 16:58:19 -10:00
J. Nick Koston
8f856fab1b Merge branch 'qspi_dbi' into integration 2025-12-31 16:55:25 -10:00
J. Nick Koston
3e1f7a9cd8 Merge branch 'pn532_spi' into integration 2025-12-31 16:55:21 -10:00
J. Nick Koston
f8e56a8565 Merge branch 'modbus_controller' into integration 2025-12-31 16:55:16 -10:00
J. Nick Koston
a952d843e7 Merge branch 'modbus' into integration 2025-12-31 16:55:12 -10:00
J. Nick Koston
278fdae770 Merge branch 'mitsubishi' into integration 2025-12-31 16:55:08 -10:00
J. Nick Koston
6fc9c63f2d Merge branch 'mipi_spi' into integration 2025-12-31 16:55:03 -10:00
J. Nick Koston
be6ec974e1 Merge branch 'mipi_rgb_hex' into integration 2025-12-31 16:54:58 -10:00
J. Nick Koston
9de52fb9f5 Merge branch 'mipi_dsi' into integration 2025-12-31 16:54:54 -10:00
J. Nick Koston
7993ff7602 Merge branch 'hlk_fm22x_format' into integration 2025-12-31 16:54:49 -10:00
J. Nick Koston
253ce861ab [qspi_dbi] Replace format_hex_pretty with stack-based format_hex_pretty_to 2025-12-31 16:54:13 -10:00
J. Nick Koston
1fff2f503f [pn532_spi] Replace format_hex_pretty with stack-based format_hex_pretty_to 2025-12-31 16:52:24 -10:00
J. Nick Koston
6925ab3bf1 tweak 2025-12-31 16:46:57 -10:00
J. Nick Koston
d8a84e6f2b wip 2025-12-31 16:42:45 -10:00
J. Nick Koston
73b19bc5d1 [modbus_controller] Replace format_hex_pretty with stack-based format_hex_pretty_to 2025-12-31 16:38:58 -10:00
J. Nick Koston
528b374b3f [modbus] Use stack buffer for hex formatting in verbose logging 2025-12-31 16:34:36 -10:00
J. Nick Koston
b7d9e3e847 [mitsubishi] Use stack buffer for hex formatting in verbose logging 2025-12-31 16:31:18 -10:00
J. Nick Koston
afd4562062 [mipi_spi] Use stack buffer for hex formatting in verbose logging 2025-12-31 16:28:51 -10:00
J. Nick Koston
724829f5bd [mipi_rgb] Use stack buffer for hex formatting in init sequence logging 2025-12-31 16:25:08 -10:00
J. Nick Koston
4f1b1d7a1e [mipi_dsi] Use stack buffer for hex formatting in very verbose logging 2025-12-31 16:22:04 -10:00
J. Nick Koston
b1ebdabaa9 Merge branch 'kuntze' into integration 2025-12-31 16:18:12 -10:00
J. Nick Koston
b1e359750c [kuntze] Use stack buffer for hex formatting in verbose logging 2025-12-31 16:17:13 -10:00
Jonathan Swoboda
3c9ed126a6 Merge branch 'release' into dev 2025-12-31 17:42:51 -05:00
Jonathan Swoboda
d8c23d4fc9 Merge pull request #12772 from esphome/bump-2025.12.4
2025.12.4
2025-12-31 17:42:39 -05:00
Konstantin Tretyakov
1d96de986e [sdist] Include yaml files in components in source distribution package
Co-authored-by: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com>
2026-01-01 08:49:43 +11:00
Jonathan Swoboda
e9e0712959 Bump version to 2025.12.4 2025-12-31 16:07:00 -05:00
J. Nick Koston
062840dd7b [docker] Add build-essential to fix ruamel.yaml 0.19.0 compilation (#12769)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-31 16:07:00 -05:00
J. Nick Koston
f0f01c081a [wifi] Fix ESP-IDF reporting connected before DHCP completes on reconnect (#12755) 2025-12-31 16:07:00 -05:00
Stuart Parmenter
dd855985be [hub75] Add clipping check (#12762) 2025-12-31 16:06:59 -05:00
J. Nick Koston
4633803d5d [docker] Add build-essential to fix ruamel.yaml 0.19.0 compilation (#12769)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-31 16:05:58 -05:00
J. Nick Koston
476d00d0e5 [wifi] Fix ESP-IDF reporting connected before DHCP completes on reconnect (#12755) 2025-12-31 15:59:28 -05:00
Stuart Parmenter
98cdef2568 [hub75] Add clipping check (#12762) 2025-12-31 15:58:37 -05:00
J. Nick Koston
4bfc14fa0e Merge branch 'dump_summary' into integration 2025-12-30 13:46:48 -10:00
J. Nick Koston
71d9dff3fc fix 2025-12-30 13:46:36 -10:00
J. Nick Koston
6728a28e1d Merge branch 'dump_summary' into integration 2025-12-30 13:43:20 -10:00
J. Nick Koston
c716983d5c tweak 2025-12-30 13:41:29 -10:00
J. Nick Koston
2c0c5a1b09 Merge branch 'dump_summary' into integration 2025-12-30 13:29:31 -10:00
J. Nick Koston
c13bbd300d tweaks 2025-12-30 13:24:32 -10:00
J. Nick Koston
ac515d6d2e tweaks 2025-12-30 13:23:21 -10:00
J. Nick Koston
e7e83305e8 Merge branch 'dump_summary' into integration 2025-12-30 13:13:40 -10:00
J. Nick Koston
580498e06c missing ; 2025-12-30 13:13:31 -10:00
J. Nick Koston
2d4be9c96f Merge branch 'dump_summary' into integration 2025-12-30 13:10:03 -10:00
J. Nick Koston
52eda13ecd reduce 2025-12-30 13:09:35 -10:00
J. Nick Koston
8ab37379e8 reduce 2025-12-30 13:08:16 -10:00
J. Nick Koston
fcd49fd32d reduce 2025-12-30 13:08:05 -10:00
J. Nick Koston
22b01ad440 Merge branch 'dump_summary' into integration 2025-12-30 13:04:36 -10:00
J. Nick Koston
53aa3f539b copilot suggestion is overkill and breaks things 2025-12-30 13:04:26 -10:00
J. Nick Koston
f42af572b8 Merge branch 'dump_summary' into integration 2025-12-30 13:04:02 -10:00
J. Nick Koston
61b377140f copilot suggestion is overkill and breaks things 2025-12-30 13:03:48 -10:00
J. Nick Koston
957b4d532c Merge branch 'dump_summary' into integration 2025-12-30 12:06:56 -10:00
J. Nick Koston
354ca54a11 adjust 2025-12-30 12:05:36 -10:00
J. Nick Koston
f0be51a49f Merge branch 'dev' into hlk_fm22x_format 2025-12-30 12:02:58 -10:00
J. Nick Koston
9ca590a125 Merge branch 'dump_summary' into integration 2025-12-30 11:53:16 -10:00
J. Nick Koston
ebf5c2851b [gpio] Avoid heap allocation in dump_summary 2025-12-30 11:52:39 -10:00
J. Nick Koston
bd3ecad3a1 [core] Add format_hex_pretty_to buffer helper and reduce code duplication (#12687) 2025-12-30 11:51:51 -10:00
J. Nick Koston
0e725a35c9 Merge branch 'light_effect_ref' into integration 2025-12-30 11:20:08 -10:00
J. Nick Koston
c2865d040f Merge branch 'addressable_light_effect_ref' into integration 2025-12-30 11:19:55 -10:00
J. Nick Koston
5a4a58fd14 Merge branch 'api_avoid_copies' into integration 2025-12-30 11:19:51 -10:00
J. Nick Koston
00f4449cc0 fix ambiguous 2025-12-30 11:17:21 -10:00
J. Nick Koston
89e0797657 simple 2025-12-30 11:14:41 -10:00
J. Nick Koston
cc79334da7 [addressable_light] Use StringRef to avoid allocation when saving effect name 2025-12-30 11:11:53 -10:00
J. Nick Koston
8d61d83425 [light] Use StringRef to avoid allocation in JSON effect name serialization 2025-12-30 11:07:59 -10:00
J. Nick Koston
ac673852bd Merge branch 'api_avoid_copies' into integration 2025-12-30 10:50:32 -10:00
J. Nick Koston
a42820dc26 should never happen but ok 2025-12-30 10:49:02 -10:00
J. Nick Koston
80e03e3951 Merge branch 'api_avoid_copies' into integration 2025-12-30 10:44:37 -10:00
J. Nick Koston
f615409032 len known 2025-12-30 10:44:30 -10:00
J. Nick Koston
d357a62fec Merge branch 'api_avoid_copies' into integration 2025-12-30 10:42:26 -10:00
J. Nick Koston
089e21b15a tweaks 2025-12-30 10:37:03 -10:00
J. Nick Koston
3e8857b358 tweaks 2025-12-30 10:32:06 -10:00
J. Nick Koston
03c9107826 Merge remote-tracking branch 'upstream/dev' into api_avoid_copies 2025-12-30 10:28:51 -10:00
J. Nick Koston
dae7ba604a [ethernet_info] Eliminate heap allocations in DNS text sensor (#12756) 2025-12-30 10:25:51 -10:00
J. Nick Koston
201ae5801a Merge branch 'ethernet_info_no_heap' into integration 2025-12-30 09:59:49 -10:00
J. Nick Koston
a346b983a7 [ethernet_info] Eliminate heap allocations in DNS text sensor 2025-12-30 09:59:20 -10:00
J. Nick Koston
880cc841f4 Merge branch 'wifi_reconnect_esp_idf' into integration 2025-12-30 09:13:26 -10:00
J. Nick Koston
eea2037627 [wifi] Fix ESP-IDF reporting connected before DHCP completes on reconnect 2025-12-30 08:51:00 -10:00
Jonathan Swoboda
96c47f3b4d Merge branch 'release' into dev 2025-12-30 09:31:44 -05:00
Jonathan Swoboda
5b5cede5f9 Merge pull request #12752 from esphome/bump-2025.12.3
2025.12.3
2025-12-30 09:31:31 -05:00
Jonathan Swoboda
c737033cc4 Bump version to 2025.12.3 2025-12-30 09:22:03 -05:00
J. Nick Koston
0194bfd9ea [core] Fix incremental build failures when adding components on ESP32-Arduino (#12745) 2025-12-30 09:22:03 -05:00
J. Nick Koston
339399eb70 [lvgl] Fix lambdas in canvas actions called from outside LVGL context (#12671) 2025-12-30 09:22:03 -05:00
Samuel Sieb
a615b28ecf [bme68x_bsec2] add id: to allow extending (#12649) 2025-12-29 23:22:36 -08:00
J. Nick Koston
065d0541d1 Merge branch 'buffering' into integration 2025-12-29 21:16:25 -10:00
J. Nick Koston
25a4d7ffab tweak 2025-12-29 21:16:11 -10:00
J. Nick Koston
10b0308bc0 tests 2025-12-29 21:11:39 -10:00
J. Nick Koston
21bd6c5b18 [core] Improve log timestamp accuracy by batching serial reads 2025-12-29 20:59:03 -10:00
bakroistvan
468bd7b04f [dallas_temp] higher precision for logged temperature (#12695) 2025-12-29 22:53:28 -08:00
J. Nick Koston
fe7fa02a4e Merge remote-tracking branch 'upstream/dev' into integration 2025-12-29 17:43:52 -10:00
Jonathan Swoboda
4c16afeacb [esp32] Add IDF framework source for Arduino builds (#12731)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-29 22:25:26 -05:00
J. Nick Koston
d86c05bfe6 [esp32] Breaking Change: Change default framework to ESP-IDF (#12746)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-30 03:23:41 +00:00
J. Nick Koston
63464a13c3 [core] Fix incremental build failures when adding components on ESP32-Arduino (#12745) 2025-12-29 16:57:22 -10:00
J. Nick Koston
f2b1c51372 Merge remote-tracking branch 'upstream/esp32_default_framework_idf' into integration 2025-12-29 16:54:05 -10:00
J. Nick Koston
3903594bd3 Update esphome/components/esp32/__init__.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-29 16:53:51 -10:00
J. Nick Koston
c4d73a07b2 Merge branch 'storage_should_update_cmake_cache_arudino_fix' into integration 2025-12-29 16:49:26 -10:00
J. Nick Koston
148dbee6cb Merge branch 'esp32_default_framework_idf' into integration 2025-12-29 16:49:22 -10:00
J. Nick Koston
436b4c4217 [esp32] Change default framework to ESP-IDF 2025-12-29 16:38:11 -10:00
J. Nick Koston
2297d240be cleanup 2025-12-29 16:28:14 -10:00
J. Nick Koston
1d1f2a9877 cover 2025-12-29 16:25:17 -10:00
J. Nick Koston
1472914527 cover 2025-12-29 16:24:10 -10:00
J. Nick Koston
c9c0bdb1c6 Merge branch 'dev' into storage_should_update_cmake_cache_arudino_fix 2025-12-29 16:23:39 -10:00
J. Nick Koston
1e5739fb93 [core] Fix incremental build failures when adding components on ESP32-Arduino 2025-12-29 16:22:04 -10:00
Clyde Stubbs
20e43398fa [cli] Report program path on host (#12743) 2025-12-30 13:21:30 +11:00
J. Nick Koston
3053687273 Merge branch 'ble_client' into integration 2025-12-29 15:52:12 -10:00
J. Nick Koston
5e7d89f302 [ble_client] Use stack buffer for hex formatting in very verbose logging 2025-12-29 15:51:35 -10:00
J. Nick Koston
005dd1ea73 [ble_client] Use stack buffer for hex formatting in very verbose logging 2025-12-29 15:49:48 -10:00
J. Nick Koston
8477dfc6c2 Merge branch 'ethernet_format_hex' into integration 2025-12-29 14:55:28 -10:00
J. Nick Koston
7b274d3347 [ethernet] Use stack buffer for hex formatting in very verbose logging 2025-12-29 14:54:53 -10:00
J. Nick Koston
e844d5403e Merge branch 'esp32_ble_tracker' into integration 2025-12-29 14:37:45 -10:00
J. Nick Koston
d16b790243 [esp32_ble_tracker] Use stack buffer for hex formatting in very verbose logging 2025-12-29 14:34:08 -10:00
J. Nick Koston
2bcdee5a09 Merge branch 'hlk_fm22x_format' into integration 2025-12-29 14:25:27 -10:00
J. Nick Koston
c413b968f3 [hlk_fm22x] Use stack buffer for hex formatting in verbose logging 2025-12-29 14:23:39 -10:00
J. Nick Koston
f98ba2827c Merge branch 'i2c' into integration 2025-12-29 14:11:23 -10:00
J. Nick Koston
8f42b3d101 [i2c] Use stack buffer for hex formatting in verbose logging 2025-12-29 14:10:34 -10:00
J. Nick Koston
b7e27087b4 [espnow] Use stack buffer for hex formatting in verbose logging 2025-12-29 14:04:36 -10:00
J. Nick Koston
4230d39262 Merge branch 'esp32_improv' into integration 2025-12-29 13:58:27 -10:00
J. Nick Koston
fe9de00f54 [esp32_improv] Use stack buffer for hex formatting in verbose logging 2025-12-29 13:56:43 -10:00
J. Nick Koston
0aa275f475 Merge branch 'dev' into logger_esp8266 2025-12-29 13:08:24 -10:00
J. Nick Koston
c94f0e16ad Merge branch 'logger_esp8266' into integration 2025-12-29 13:07:19 -10:00
J. Nick Koston
c09f555e18 [logger] Exclude unused Arduino Serial objects on ESP8266 2025-12-29 13:06:33 -10:00
hsand
2e7cdad532 [pvvx_mithermometer] fix displaying negative numbers (#12735) 2025-12-29 13:58:38 -08:00
J. Nick Koston
70bd83f4f5 Merge remote-tracking branch 'swoboda1337/esp32-arduino-idf-source' into integration 2025-12-29 10:52:11 -10:00
J. Nick Koston
2e5403c743 [epaper_spi] Use stack buffer for hex formatting in command logging 2025-12-29 10:41:39 -10:00
J. Nick Koston
eafa86e227 Merge branch 'nextion' into integration 2025-12-29 10:30:49 -10:00
J. Nick Koston
4e93fdd37a [nextion] Use stack buffers for hex formatting in upload logging 2025-12-29 10:29:57 -10:00
J. Nick Koston
05761ba972 Merge branch 'tuya_format_hex' into integration 2025-12-29 10:25:22 -10:00
J. Nick Koston
6ca9220e5b Merge branch 'cse7766' into integration 2025-12-29 10:25:17 -10:00
J. Nick Koston
98f49fa970 [cse7766] Use stack buffer for hex formatting in debug logging 2025-12-29 10:24:32 -10:00
J. Nick Koston
22656095b6 missed one 2025-12-29 10:21:11 -10:00
J. Nick Koston
ede4511b12 Merge branch 'fix_opentherm_heap_alloc_logging' into integration 2025-12-29 10:15:47 -10:00
J. Nick Koston
33fafa2427 Merge branch 'shelly_dimmer' into integration 2025-12-29 10:15:37 -10:00
J. Nick Koston
5cd4df2de9 Merge branch 'mirage_protocol' into integration 2025-12-29 10:15:34 -10:00
J. Nick Koston
37b656323c Merge branch 'rc522' into integration 2025-12-29 10:15:31 -10:00
J. Nick Koston
b19f0b092a Merge branch 'haier_protocol' into integration 2025-12-29 10:15:27 -10:00
J. Nick Koston
f70b56bb04 Merge branch 'jsn_sr04t' into integration 2025-12-29 10:15:16 -10:00
J. Nick Koston
42333473c5 Merge branch 'a02yyuw' into integration 2025-12-29 10:15:11 -10:00
J. Nick Koston
159f9afcc0 Merge branch 'a01nyub' into integration 2025-12-29 10:15:08 -10:00
J. Nick Koston
9f0644cc02 Merge branch 'sonoff_d1' into integration 2025-12-29 10:14:52 -10:00
J. Nick Koston
b2b18b26c3 [sonoff_d1] Use stack buffer for hex formatting in logging 2025-12-29 10:14:17 -10:00
Jonathan Swoboda
c5be39f499 [esp32] Add IDF framework source for Arduino builds
Add ARDUINO_IDF_VERSION_LOOKUP table mapping Arduino framework versions
to their underlying ESP-IDF versions. When building with Arduino framework,
explicitly add the corresponding IDF framework source to platform_packages
to ensure consistent IDF versions are used.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 15:12:55 -05:00
J. Nick Koston
e1ce6b151d [jsn_sr04t] Use stack buffer for hex formatting in error logging 2025-12-29 10:09:27 -10:00
J. Nick Koston
0bc35f5086 [a02yyuw] Use stack buffer for hex formatting in error logging 2025-12-29 10:05:46 -10:00
J. Nick Koston
6ead7f82db [a01nyub] Use stack buffer for hex formatting in error logging 2025-12-29 10:03:25 -10:00
J. Nick Koston
1f832064d1 [opentherm] Replace heap-allocating format calls with printf format specifiers in debug_error 2025-12-29 09:58:13 -10:00
dependabot[bot]
636cccc6a3 Bump aioesphomeapi from 43.9.0 to 43.9.1 (#12724)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-29 09:55:26 -10:00
J. Nick Koston
b47462d64a [rc522] Use stack buffers for hex formatting in tag logging 2025-12-29 09:53:03 -10:00
J. Nick Koston
fdefbeb3dc [remote_base] Use stack buffer for hex formatting in haier protocol logging` 2025-12-29 09:44:08 -10:00
J. Nick Koston
3bd1a6fcf8 [remote_base] Use stack buffer for hex formatting in mirage protocol logging 2025-12-29 09:39:27 -10:00
J. Nick Koston
80551969f1 fix 2025-12-29 09:34:43 -10:00
J. Nick Koston
29a64b9113 [shelly_dimmer] Use stack buffer for hex formatting in command logging 2025-12-29 09:31:17 -10:00
Thomas Rupprecht
93e2a1bd1a [tests] improve mipi_spi variable naming (#12716) 2025-12-29 14:21:07 -05:00
Thomas Rupprecht
dd3beb5841 [tests] fix typo mipi tests (#12715) 2025-12-29 14:20:38 -05:00
Thomas Rupprecht
97af01c5ed [usb_host] sort esp32 variants (#12720) 2025-12-29 14:19:36 -05:00
J. Nick Koston
f1f0f9d7bf Merge remote-tracking branch 'upstream/ota_drop_md5' into integration 2025-12-29 08:45:46 -10:00
J. Nick Koston
8110d36f1c Merge branch 'dev' into ota_drop_md5 2025-12-29 08:45:00 -10:00
J. Nick Koston
7e362cdafc [ota] Use precision format specifier for auth logging (#12706)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-29 08:43:54 -10:00
Jonathan Swoboda
890d531cea [esp32] Bump to ESP-IDF 5.5.2, Arduino 3.3.5, platform 55.3.35 (#12681)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-29 11:35:54 -05:00
Swaptor
6a6c6b648f [internal_temperature] Add ESP32-C5 support (#12713)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-29 11:32:32 -05:00
J. Nick Koston
2f5e3193c7 Merge branch 'ota_drop_md5' into integration 2025-12-28 22:35:01 -10:00
J. Nick Koston
5f387e5d6c tweaks 2025-12-28 22:34:49 -10:00
J. Nick Koston
dbb87f53e1 Merge branch 'ota_drop_md5' into integration 2025-12-28 22:28:26 -10:00
J. Nick Koston
fe8f9c160d Merge branch 'ota_logging_cleanups' into integration 2025-12-28 22:27:29 -10:00
J. Nick Koston
d2217a2534 [ota] Remove MD5 authentication support 2025-12-28 22:26:04 -10:00
J. Nick Koston
8dd803a05e Update esphome/components/esphome/ota/ota_esphome.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-28 22:08:27 -10:00
J. Nick Koston
3ef0a7527f Merge branch 'ota_logging_cleanups' into integration 2025-12-28 22:03:11 -10:00
J. Nick Koston
bf1d3c534d [ota] Use precision format specifier for auth logging 2025-12-28 22:02:46 -10:00
J. Nick Koston
600c2453f4 Merge branch 'stack_copy_not_needed_wifi' into integration 2025-12-28 21:54:25 -10:00
J. Nick Koston
ab332b588f [wifi] Use precision format specifier for SSID logging to avoid stack copy 2025-12-28 21:53:53 -10:00
J. Nick Koston
495b128af9 Merge branch 'no_send_object_id' into integration 2025-12-28 21:41:59 -10:00
dependabot[bot]
d0673122a8 Bump aioesphomeapi from 43.8.0 to 43.9.0 (#12702) 2025-12-28 18:15:06 -10:00
J. Nick Koston
70038ea0a8 tweak 2025-12-28 17:42:31 -10:00
J. Nick Koston
463a5b6af9 tweak 2025-12-28 17:37:25 -10:00
J. Nick Koston
2756a027f7 Merge branch 'object_id_no_ram' into no_send_object_id 2025-12-28 17:17:05 -10:00
J. Nick Koston
64b61809a4 Merge branch 'dev' into object_id_no_ram 2025-12-28 17:16:35 -10:00
dependabot[bot]
5cbef3ef95 Bump aioesphomeapi from 43.7.0 to 43.8.0 (#12701) 2025-12-29 03:15:40 +00:00
dependabot[bot]
a1e0121330 Bump bleak from 2.0.0 to 2.1.0 (#12700)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-28 16:48:20 -10:00
dependabot[bot]
eb050ff13e Bump aioesphomeapi from 43.6.0 to 43.7.0 (#12699)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-28 16:48:08 -10:00
J. Nick Koston
d65284e760 Merge branch 'no_send_object_id' into integration 2025-12-28 15:34:55 -10:00
J. Nick Koston
7a091c0ac6 [api] Remove object_id from API protocol - clients compute it from name 2025-12-28 15:23:32 -10:00
J. Nick Koston
c81aec9e58 Merge branch 'dev' into object_id_no_ram 2025-12-28 14:51:14 -10:00
J. Nick Koston
550c8c40d3 Merge branch 'min_chip_revision' into integration 2025-12-28 13:43:22 -10:00
J. Nick Koston
cd3dadb3c9 reduce 2025-12-28 13:43:04 -10:00
J. Nick Koston
c6857cb5fe Merge branch 'min_chip_revision' into integration 2025-12-28 13:31:52 -10:00
J. Nick Koston
16315d72b6 define 2025-12-28 13:30:45 -10:00
J. Nick Koston
56a0fe0a1a Merge branch 'min_chip_revision' into integration 2025-12-28 13:26:08 -10:00
J. Nick Koston
90af7e3088 [esp32] Add minimum_chip_revision setting and log chip revision at startup 2025-12-28 13:20:06 -10:00
J. Nick Koston
07e844453d Merge branch 'esp8266_waveform' into integration 2025-12-27 22:02:28 -10:00
J. Nick Koston
080e461184 tweaks 2025-12-27 21:59:44 -10:00
J. Nick Koston
05f19ea644 tweaks 2025-12-27 21:56:02 -10:00
J. Nick Koston
8751c1d32c Merge branch 'esp8266_waveform' into integration 2025-12-27 21:38:58 -10:00
J. Nick Koston
ebe43228e3 tweaks 2025-12-27 21:33:08 -10:00
J. Nick Koston
0f8bef5543 fixes 2025-12-27 21:29:00 -10:00
J. Nick Koston
53fa89d0e3 tweaks 2025-12-27 21:27:34 -10:00
J. Nick Koston
ca3b9a0e55 [esp8266] Exclude unused waveform code to save ~596 bytes RAM 2025-12-27 21:24:24 -10:00
J. Nick Koston
f0894ab958 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 19:06:25 -10:00
J. Nick Koston
c410171a63 remove old way 2025-12-27 19:06:09 -10:00
J. Nick Koston
5f7863af21 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:58:47 -10:00
J. Nick Koston
95ae7caf24 mark final 2025-12-27 18:58:35 -10:00
J. Nick Koston
4d6bc262da Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:54:31 -10:00
J. Nick Koston
e698a88380 fix 2025-12-27 18:54:11 -10:00
J. Nick Koston
ee94ee7e59 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:51:00 -10:00
J. Nick Koston
30b169a4cf fix 2025-12-27 18:50:34 -10:00
J. Nick Koston
47c475a03c wip 2025-12-27 18:40:14 -10:00
J. Nick Koston
a522447bed Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:36:10 -10:00
J. Nick Koston
e15bac46cb missed one 2025-12-27 18:35:57 -10:00
J. Nick Koston
6f5900713c wip 2025-12-27 18:32:14 -10:00
J. Nick Koston
dafe9da1eb Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:24:15 -10:00
J. Nick Koston
b8d246b706 fix 2025-12-27 18:24:01 -10:00
J. Nick Koston
23d88933fd Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:20:47 -10:00
J. Nick Koston
274b1e26ce tweak 2025-12-27 18:20:29 -10:00
J. Nick Koston
dc51abbd82 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 18:18:55 -10:00
J. Nick Koston
0217c130dd tweak 2025-12-27 18:15:11 -10:00
J. Nick Koston
1290929684 tweak 2025-12-27 18:14:11 -10:00
J. Nick Koston
96b2888505 tweak 2025-12-27 18:06:57 -10:00
J. Nick Koston
d2bab26e67 tweak 2025-12-27 18:05:26 -10:00
J. Nick Koston
d404e37449 reduce 2025-12-27 17:49:25 -10:00
J. Nick Koston
f9659fc693 reduce 2025-12-27 17:49:04 -10:00
J. Nick Koston
ce71e7bccd Merge branch 'get_peername_stack_save_ram' into integration 2025-12-27 17:10:50 -10:00
J. Nick Koston
f4cb379d6b tweaks 2025-12-27 17:01:10 -10:00
J. Nick Koston
49e0e66aee Merge branch 'dev' into get_peername_stack_save_ram 2025-12-27 16:51:46 -10:00
J. Nick Koston
3d82118bd5 Merge branch 'dev' into api_avoid_copies 2025-12-27 16:45:43 -10:00
J. Nick Koston
92f44da2cf Merge branch 'tuya_format_hex' into integration 2025-12-27 16:34:37 -10:00
J. Nick Koston
db82a3f5f8 [tuya] Use stack buffers for hex logging to avoid heap allocations 2025-12-27 16:10:38 -10:00
J. Nick Koston
e6891d4027 Merge branch 'ldxxxx_no_heap' into integration 2025-12-27 15:54:01 -10:00
J. Nick Koston
60c6d94083 remove tests 2025-12-27 15:48:43 -10:00
J. Nick Koston
e1a5830d9f Merge branch 'zwave_no_alloc_hex' of https://github.com/esphome/esphome into zwave_no_alloc_hex 2025-12-27 15:46:23 -10:00
J. Nick Koston
783604b8b4 [ld2410][ld2412][ld2450] Use stack buffers for hex logging 2025-12-27 15:45:17 -10:00
J. Nick Koston
53ad49086d fixes 2025-12-27 15:40:32 -10:00
J. Nick Koston
a2d25b532a Merge branch 'zwave_no_alloc_hex' into integration 2025-12-27 15:23:43 -10:00
J. Nick Koston
05c51b6ced Add isolated tests for hex formatting functions 2025-12-27 15:18:47 -10:00
J. Nick Koston
89f326be30 reduce 2025-12-27 15:12:30 -10:00
J. Nick Koston
38850a9ab3 more dry 2025-12-27 15:08:44 -10:00
J. Nick Koston
4d4498e81f fix max 2025-12-27 14:57:42 -10:00
J. Nick Koston
d1707ac4d6 Merge branch 'zwave_no_alloc_hex' into integration 2025-12-27 14:39:36 -10:00
J. Nick Koston
61970bd1de [core] Add format_hex_pretty_to buffer helper and reduce code duplication 2025-12-27 14:34:33 -10:00
J. Nick Koston
09f03dcf0c Merge branch 'mqtt_ip_no_alloc' into integration 2025-12-27 14:08:18 -10:00
J. Nick Koston
adaebd4b4e [mqtt] Avoid heap allocations when logging IP addresses 2025-12-27 14:07:07 -10:00
J. Nick Koston
9f2d34bacb Merge remote-tracking branch 'origin/no_heap_alloc_start_dnsserver' into integration 2025-12-27 14:03:44 -10:00
J. Nick Koston
6f780a63ab Merge branch 'udp_multicast_avoid_heap' into integration 2025-12-27 14:02:12 -10:00
J. Nick Koston
9b2488cd8d [udp] Avoid heap allocations when joining multicast groups 2025-12-27 14:00:38 -10:00
J. Nick Koston
e76bc6b357 Merge remote-tracking branch 'origin/integration' into integration 2025-12-27 12:35:36 -10:00
J. Nick Koston
0867e96585 Merge branch 'esp-idf-5.5.2' into integration 2025-12-27 12:35:24 -10:00
J. Nick Koston
1618c69923 Merge remote-tracking branch 'upstream/dev' into esp-idf-5.5.2 2025-12-27 12:02:07 -10:00
Jonathan Swoboda
45e61f100c [core] Replace USE_ESP_IDF with USE_ESP32 across components (#12673)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-27 11:59:55 -10:00
J. Nick Koston
6dd1175fe7 Merge branch 'improv_stack_format' into integration 2025-12-27 11:30:02 -10:00
J. Nick Koston
fe651f1b8d Merge branch 'wifi_no_heap_logging_cap_portal' into integration 2025-12-27 11:29:53 -10:00
J. Nick Koston
3768a269ad nolint 2025-12-27 11:29:29 -10:00
J. Nick Koston
b9d80a5ef3 [esp32_improv] Use stack buffer for URL formatting to avoid heap allocation 2025-12-27 11:27:28 -10:00
J. Nick Koston
1aebe90ad5 [esp32_improv] Use stack buffer for URL formatting to avoid heap allocation 2025-12-27 11:26:24 -10:00
J. Nick Koston
06c4325525 lint 2025-12-27 11:21:44 -10:00
Jonathan Swoboda
343316ac2d [esp32] Bump to ESP-IDF 5.5.2, Arduino 3.3.5, platform 55.3.35
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-27 14:33:32 -05:00
J. Nick Koston
cc0b63a277 fix 2025-12-27 09:32:22 -10:00
J. Nick Koston
4271a64ce4 fix 2025-12-27 09:31:06 -10:00
J. Nick Koston
52c692c99b [wifi] Use stack buffers for IP address logging to avoid heap allocations 2025-12-27 09:26:44 -10:00
J. Nick Koston
a8fb40c946 [wifi] Use stack buffers for IP address logging to avoid heap allocations 2025-12-27 09:24:17 -10:00
J. Nick Koston
0b621bb0a3 [captive_portal] Use stack buffer for IP address logging in DNS server 2025-12-27 09:07:44 -10:00
J. Nick Koston
7bc7089fbe Merge branch 'wifi_alloc_during_connect' into integration 2025-12-27 08:58:11 -10:00
J. Nick Koston
32880e3d5a [wifi] Use wifi_ssid_to() to avoid heap allocations in automation and connection checks 2025-12-27 08:57:39 -10:00
J. Nick Koston
206793d4ab Merge remote-tracking branch 'upstream/dev' into integration 2025-12-27 08:52:13 -10:00
J. Nick Koston
5e99dd14ae [ethernet] Eliminate heap allocations in dump_config logging (#12665) 2025-12-27 08:36:35 -10:00
J. Nick Koston
a6097f4a0f [wifi] Eliminate heap allocations in dump_config logging (#12664)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-27 08:36:19 -10:00
J. Nick Koston
f243e609a5 [wifi] Use StringRef and std::span in WiFiConnectStateListener to avoid allocations (#12672) 2025-12-27 08:35:58 -10:00
J. Nick Koston
be0bf1e5b9 [lvgl] Fix lambdas in canvas actions called from outside LVGL context (#12671) 2025-12-27 08:35:36 -10:00
J. Nick Koston
a275f37135 [udp] Use stack buffer for listen address logging in dump_config (#12667) 2025-12-27 08:35:16 -10:00
J. Nick Koston
e9f2d75aab [core] Add format_hex_to helper for zero-allocation hex formatting (#12670) 2025-12-27 08:34:45 -10:00
J. Nick Koston
34067f8b15 [esp8266] Native OTA backend to reduce Arduino dependencies (#12675)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-27 08:29:15 -10:00
J. Nick Koston
47ae027026 Merge branch 'esp8266_native_framework_update' into integration 2025-12-26 23:04:31 -10:00
J. Nick Koston
cfe9e6204b preen 2025-12-26 23:01:18 -10:00
J. Nick Koston
547aa59c18 Merge branch 'esp8266_native_framework_update' into integration 2025-12-26 22:37:59 -10:00
J. Nick Koston
5b9c7d1322 Update esphome/components/ota/ota_backend_esp8266.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-26 22:36:12 -10:00
J. Nick Koston
d0ba608ffa add comment 2025-12-26 22:35:27 -10:00
J. Nick Koston
c91f56171b Update esphome/components/ota/ota_backend_esp8266.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-26 22:34:22 -10:00
J. Nick Koston
15ad89f66d Update esphome/components/ota/ota_backend_esp8266.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-26 22:33:38 -10:00
J. Nick Koston
8f0de69e9f Merge branch 'esp8266_native_framework_update' into integration 2025-12-26 22:23:40 -10:00
J. Nick Koston
37de782e3e guard 2025-12-26 22:13:10 -10:00
J. Nick Koston
a5574bbabe dry 2025-12-26 21:59:47 -10:00
J. Nick Koston
1bea4df45e guard 2025-12-26 21:51:09 -10:00
J. Nick Koston
57829ddd76 fixes 2025-12-26 20:23:13 -10:00
J. Nick Koston
99722fb04f fixes 2025-12-26 20:22:16 -10:00
J. Nick Koston
faa4cf7483 fixes 2025-12-26 20:19:25 -10:00
J. Nick Koston
16e96dfbc0 fixes 2025-12-26 20:18:25 -10:00
J. Nick Koston
062195be95 native framework updater PoC 2025-12-26 20:12:27 -10:00
J. Nick Koston
b2133c75f1 native framework updater PoC 2025-12-26 20:07:20 -10:00
J. Nick Koston
655a746e0d Merge branch 'wifi_listeners' into integration 2025-12-26 14:57:39 -10:00
J. Nick Koston
a2ea545e10 make the bot happy 2025-12-26 14:57:26 -10:00
J. Nick Koston
6fe5d14b3f Merge branch 'wifi_listeners' into integration 2025-12-26 14:44:41 -10:00
J. Nick Koston
f446860166 might as well make it span 2025-12-26 14:43:01 -10:00
J. Nick Koston
02e8603051 Merge branch 'wifi_listeners' into integration 2025-12-26 14:35:32 -10:00
J. Nick Koston
3fe4e18dc4 [wifi] Use StringRef for WiFiConnectStateListener to avoid heap allocation 2025-12-26 14:34:06 -10:00
J. Nick Koston
b221673ba7 Merge branch 'ethernet_logging_less_alloc' into integration 2025-12-26 13:44:44 -10:00
J. Nick Koston
e711cd0e41 dry it up 2025-12-26 13:39:57 -10:00
J. Nick Koston
307489cd59 missed one 2025-12-26 13:33:01 -10:00
J. Nick Koston
e7c0d13500 Merge branch 'dev' into ethernet_logging_less_alloc 2025-12-26 12:56:06 -10:00
J. Nick Koston
bdc087148a [wifi_info] Reduce heap allocations in text sensor formatting (#12660) 2025-12-26 12:52:41 -10:00
J. Nick Koston
5a2e0612a8 [web_server] Use C++17 nested namespace syntax (#12663) 2025-12-26 08:44:34 -10:00
J. Nick Koston
f1fecd22e3 [web_server] Move HTTP header strings to flash on ESP8266 (#12668) 2025-12-26 08:44:17 -10:00
J. Nick Koston
0919017d49 [wifi] Avoid unnecessary string copy in failed connection logging (#12659) 2025-12-26 08:44:03 -10:00
J. Nick Koston
963f594c9e [text_sensor] Return state by const reference to avoid copies (#12661) 2025-12-26 07:58:46 -10:00
J. Nick Koston
4f70663658 [alarm_control_panel] Use C++17 nested namespace and remove unused include (#12662) 2025-12-26 07:57:33 -10:00
J. Nick Koston
3f20a54240 Merge branch 'web_server_more_strings_ram' into integration 2025-12-25 23:07:17 -10:00
J. Nick Koston
e9e301c835 cleanup 2025-12-25 23:05:29 -10:00
J. Nick Koston
8c90477387 more 2025-12-25 23:02:22 -10:00
J. Nick Koston
a394fe8ad2 Merge branch 'web_server_more_strings_ram' into integration 2025-12-25 22:52:46 -10:00
J. Nick Koston
d642e9d85e [web_server] Move HTTP header strings to flash on ESP8266 2025-12-25 22:52:01 -10:00
J. Nick Koston
fa05018b2c Merge branch 'object_id_no_ram' into integration 2025-12-25 22:26:56 -10:00
J. Nick Koston
63d7ab0d40 Merge branch 'udp_listen_logging_alloc' into integration 2025-12-25 22:03:04 -10:00
J. Nick Koston
51f95c7f9a [udp] Use stack buffer for listen address logging in dump_config 2025-12-25 22:01:57 -10:00
J. Nick Koston
2ac67b59e8 Merge branch 'ethernet_logging_less_alloc' into integration 2025-12-25 21:51:39 -10:00
J. Nick Koston
0767df02d9 [ethernet] Eliminate heap allocations in dump_config logging 2025-12-25 21:50:54 -10:00
J. Nick Koston
984822388d Merge branch 'web_server_namespace' into integration 2025-12-25 21:25:32 -10:00
J. Nick Koston
cc49ec82bf [web_server] Use C++17 nested namespace syntax 2025-12-25 21:24:47 -10:00
J. Nick Koston
cc18092e7a Merge branch 'alarm_control_panel_cleanup' into integration 2025-12-25 21:17:59 -10:00
J. Nick Koston
825d12553e [alarm_control_panel] Use C++17 nested namespace and remove unused include 2025-12-25 21:17:13 -10:00
J. Nick Koston
0bd82b19b3 Merge branch 'text_sensor_avoid_copies' into integration 2025-12-25 21:10:41 -10:00
J. Nick Koston
460792e180 [text_sensor] Return state by const reference to avoid copies 2025-12-25 21:09:49 -10:00
J. Nick Koston
5411008c49 Merge branch 'wifi_info_less_alloc' into integration 2025-12-25 20:47:01 -10:00
J. Nick Koston
9e13f6ac4c copilot is wrong, add comment 2025-12-25 20:46:20 -10:00
J. Nick Koston
b8cb6fedb3 address copilot review comments 2025-12-25 20:38:50 -10:00
J. Nick Koston
68f36ae736 address copilot review comments 2025-12-25 20:38:38 -10:00
J. Nick Koston
6cbe3e306b Merge branch 'wifi_info_less_alloc' into integration 2025-12-25 16:03:31 -10:00
J. Nick Koston
cae7163741 fixes 2025-12-25 16:03:12 -10:00
J. Nick Koston
10aee92762 Merge branch 'wifi_avoid_copy_logging' into integration 2025-12-25 16:01:04 -10:00
J. Nick Koston
736a1bb019 Merge branch 'wifi_info_less_alloc' into integration 2025-12-25 16:00:58 -10:00
J. Nick Koston
ca652b2065 [wifi_info] Reduce heap allocations in text sensor formatting 2025-12-25 15:58:17 -10:00
J. Nick Koston
7608b8ee84 [wifi] Avoid unnecessary string copy in failed connection logging 2025-12-25 15:06:36 -10:00
J. Nick Koston
d490594609 Merge remote-tracking branch 'upstream/response_api' into integration 2025-12-25 14:51:28 -10:00
J. Nick Koston
8715a60b7a [api] Use StringRef in send_action_response and send_execute_service_response 2025-12-25 14:48:19 -10:00
J. Nick Koston
dd99c565ca Merge remote-tracking branch 'upstream/siren_zero_copy' into integration 2025-12-25 14:37:45 -10:00
J. Nick Koston
20df6a7f9a [api] Use pointer to FixedVector for siren tones field 2025-12-25 14:36:06 -10:00
J. Nick Koston
3e4631baa9 Merge remote-tracking branch 'upstream/bytes_zero_copy_default_api' into integration 2025-12-25 14:20:31 -10:00
J. Nick Koston
6af34f1e2a Merge remote-tracking branch 'upstream/handle_action_response_opt' into integration 2025-12-25 14:20:28 -10:00
J. Nick Koston
0ba15b51c6 Merge remote-tracking branch 'upstream/voice_assist_zero_copy' into integration 2025-12-25 14:20:22 -10:00
J. Nick Koston
8004602ef2 [voice_assistant] Use zero-copy buffer access for audio data` 2025-12-25 14:14:06 -10:00
J. Nick Koston
a3ec57eaf4 [api] Use StringRef in handle_action_response to avoid temporary string 2025-12-25 14:01:40 -10:00
J. Nick Koston
98460ac828 [api] Auto-generate zero-copy pointer access for incoming API bytes fields 2025-12-25 13:56:08 -10:00
J. Nick Koston
7c739592a8 Merge branch 'dev' into get_peername_stack_save_ram 2025-12-25 09:02:44 -10:00
J. Nick Koston
2b10408e28 Merge remote-tracking branch 'upstream/string_ref_for_all_incoming_api_strings' into integration 2025-12-25 09:02:03 -10:00
J. Nick Koston
33d1efe27c tidy 2025-12-24 22:21:00 -10:00
J. Nick Koston
0e9aaf1a8b fixes 2025-12-24 22:07:48 -10:00
J. Nick Koston
7f4fad74c2 fixes 2025-12-24 22:07:35 -10:00
J. Nick Koston
8b72c3c0ef [api] Auto-generate StringRef for incoming API string fields 2025-12-24 22:05:19 -10:00
dependabot[bot]
958a35e262 Bump aioesphomeapi from 43.5.0 to 43.6.0 (#12644)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-24 14:17:52 -10:00
J. Nick Koston
da1955fefc dry up tests 2025-12-23 07:54:52 -10:00
J. Nick Koston
8505a4dfaf dry up tests 2025-12-23 07:52:33 -10:00
J. Nick Koston
071e42d4e7 Merge remote-tracking branch 'origin/object_id_no_ram' into object_id_no_ram 2025-12-23 07:46:07 -10:00
J. Nick Koston
38beb613c2 simplify 2025-12-23 07:45:46 -10:00
J. Nick Koston
058c637b59 Merge branch 'dev' into object_id_no_ram 2025-12-23 06:59:16 -10:00
J. Nick Koston
0c566c6f00 [core] Deprecate get_object_id() and migrate remaining usages to get_object_id_to() (#12629) 2025-12-23 06:59:07 -10:00
Jonathan Swoboda
ba73289b28 Merge branch 'release' into dev 2025-12-23 11:17:15 -05:00
Jonathan Swoboda
99f7e9aeb7 Merge pull request #12632 from esphome/bump-2025.12.2
2025.12.2
2025-12-23 11:17:01 -05:00
Jonathan Swoboda
ebb6babb3d Fix hash 2025-12-23 09:26:38 -05:00
Jonathan Swoboda
0922f240e0 Bump version to 2025.12.2 2025-12-23 09:23:04 -05:00
Jonathan Swoboda
c8fb694dcb [cc1101] Fix packet mode RSSI/LQI (#12630)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-23 09:23:04 -05:00
J. Nick Koston
6054685dae [esp32_camera] Throttle frame logging to reduce overhead and improve throughput (#12586) 2025-12-23 09:23:04 -05:00
Anna Oake
61ec3508ed [cc1101] Fix option defaults and move them to YAML (#12608) 2025-12-23 09:23:04 -05:00
Leo Bergolth
086ec770ea send NIL ("-") as timestamp if time source is not valid (#12588) 2025-12-23 09:23:04 -05:00
Stuart Parmenter
b055f5b4bf [hub75] Bump esp-hub75 version to 0.1.7 (#12564) 2025-12-23 09:23:00 -05:00
Eduard Llull
726db746c8 [display_menu_base] Call on_value_ after updating the select (#12584) 2025-12-23 09:21:54 -05:00
Keith Burzinski
1922455fa7 [wifi] Fix for wifi_info when static IP is configured (#12576) 2025-12-23 09:21:54 -05:00
Thomas Rupprecht
dc943d7e7a [pca9685,sx126x,sx127x] Use frequency/float_range check (#12490)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-23 09:21:54 -05:00
Jonathan Swoboda
ffefa8929e [cc1101] Fix packet mode RSSI/LQI (#12630)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-23 09:05:48 -05:00
J. Nick Koston
89ef523990 tweak 2025-12-23 01:01:20 -10:00
J. Nick Koston
0ec741c425 one more case 2025-12-23 00:48:25 -10:00
J. Nick Koston
c265436b07 cover 2025-12-23 00:45:25 -10:00
J. Nick Koston
04a75cf200 cover 2025-12-23 00:24:45 -10:00
J. Nick Koston
83598d6798 cover 2025-12-23 00:21:20 -10:00
J. Nick Koston
fa39b6bebd fixes 2025-12-23 00:16:53 -10:00
J. Nick Koston
1beec0ecf1 bug for bug compat 2025-12-23 00:05:12 -10:00
J. Nick Koston
3ef4e0bc47 fixes 2025-12-23 00:00:03 -10:00
J. Nick Koston
bda2db9184 Merge branch 'migrate_remain_get_object_id' into object_id_no_ram 2025-12-22 23:19:25 -10:00
J. Nick Koston
3009da14f1 tweaks 2025-12-22 23:17:15 -10:00
J. Nick Koston
d334d0d458 tweaks 2025-12-22 23:16:28 -10:00
J. Nick Koston
25b340cbbf Merge branch 'migrate_remain_get_object_id' into object_id_no_ram 2025-12-22 23:13:47 -10:00
J. Nick Koston
fa2bc21d3d tweaks 2025-12-22 23:13:28 -10:00
J. Nick Koston
83d65cff5d Merge branch 'migrate_remain_get_object_id' into object_id_no_ram 2025-12-22 23:12:09 -10:00
J. Nick Koston
9205cb3d67 tweaks 2025-12-22 23:11:42 -10:00
J. Nick Koston
f9a4a8a82e tweaks 2025-12-22 23:11:12 -10:00
J. Nick Koston
2d6b9b3888 more cover 2025-12-22 22:06:48 -10:00
J. Nick Koston
da8e23f968 more cover 2025-12-22 21:58:58 -10:00
J. Nick Koston
4bec2dc75c tweak 2025-12-22 21:51:57 -10:00
J. Nick Koston
6d5ab00385 tweak 2025-12-22 21:42:50 -10:00
J. Nick Koston
3e1db740ea cover 2025-12-22 21:40:10 -10:00
J. Nick Koston
e13f48b348 preen 2025-12-22 20:10:36 -10:00
J. Nick Koston
9f2d2eed8c preen 2025-12-22 20:08:38 -10:00
J. Nick Koston
b6b871cb73 preen 2025-12-22 20:07:02 -10:00
J. Nick Koston
452246e1c5 [core] Remove object_id RAM storage - no longer in hot path after #12627 2025-12-22 20:01:57 -10:00
J. Nick Koston
7d5342bca5 [logger] Host: Use fwrite() with explicit length and remove platform branching (#12628) 2025-12-22 16:45:22 -10:00
J. Nick Koston
7944fe6993 [core] Deprecate get_object_id() and migrate remaining usages to get_object_id_to() 2025-12-22 15:13:59 -10:00
J. Nick Koston
b4c92dd8cb [logger] Zephyr: Use k_str_out() with known length instead of printk() (#12619) 2025-12-22 14:29:47 -10:00
eoasmxd
1b31253287 Add Event Component to UART (#11765)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-22 12:19:48 -10:00
J. Nick Koston
6ae3d9c769 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-22 12:09:02 -10:00
J. Nick Koston
af0d4d2c2c [web_server] Use stack buffers for value formatting to reduce flash usage (#12575) 2025-12-22 21:56:07 +00:00
J. Nick Koston
f238f93312 [core] Move comment to PROGMEM on ESP8266 (#12554) 2025-12-22 21:37:51 +00:00
J. Nick Koston
bdbe72b7f1 [web_server] Make internal JSON helper methods private (#12624) 2025-12-22 11:14:11 -10:00
J. Nick Koston
c8b531ac06 [safe_mode] Defer preference sync in clean_rtc to avoid blocking event loop (#12625) 2025-12-22 11:13:51 -10:00
J. Nick Koston
689e1d6ca0 Merge branch 'web_server_stack_format' into integration 2025-12-22 11:11:56 -10:00
J. Nick Koston
7b82b3b584 reduce churn 2025-12-22 11:11:16 -10:00
J. Nick Koston
36c0553cf7 Merge branch 'web_server_stack_format' into integration 2025-12-22 11:09:56 -10:00
J. Nick Koston
d3b3358527 inline it 2025-12-22 11:09:38 -10:00
J. Nick Koston
b950d65a7b Merge branch 'move_comment_build_info' into integration 2025-12-22 10:56:34 -10:00
J. Nick Koston
b2a6e6e078 undeprecate get_comment 2025-12-22 10:53:11 -10:00
J. Nick Koston
972cf01763 Merge remote-tracking branch 'origin/safe_mode_blocking_on_success' into integration 2025-12-22 10:49:24 -10:00
J. Nick Koston
029df4ff3d [safe_mode] Remove unnecessary blocking sync from successful boot reset 2025-12-22 10:48:10 -10:00
J. Nick Koston
21ba0e5a2b Merge remote-tracking branch 'origin/safe_mode_blocking_on_success' into integration 2025-12-22 10:46:10 -10:00
J. Nick Koston
8bb57f90de Merge branch 'web_server_json_priv' into integration 2025-12-22 10:45:59 -10:00
J. Nick Koston
145d09c8dd [safe_mode] Remove unnecessary blocking sync from successful boot reset 2025-12-22 10:41:47 -10:00
Jonathan Swoboda
918bc4b74f [esp32] Remove remaining using_esp_idf checks (#12623)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-22 15:41:14 -05:00
J. Nick Koston
5373393714 [safe_mode] Remove unnecessary blocking sync from successful boot reset 2025-12-22 10:39:30 -10:00
J. Nick Koston
21f6fefd98 [web_server] Make internal JSON helper methods private 2025-12-22 10:31:24 -10:00
J. Nick Koston
efc30ed198 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-22 10:13:57 -10:00
J. Nick Koston
63005eaa06 Merge remote-tracking branch 'swoboda1337/deprecate-using-esp-idf' into integration 2025-12-22 09:20:05 -10:00
Keith Burzinski
08c0f65f30 [sprinkler] Remove internal latching valve support (#12603) 2025-12-22 14:13:18 -05:00
Keith Burzinski
cd45fe0c3a [thermostat] Optimizations to reduce binary size (#12621) 2025-12-22 14:13:03 -05:00
Jonathan Swoboda
676fbf6161 Fix 2025-12-22 14:08:27 -05:00
Jonathan Swoboda
fb009f47f1 Deprecate again 2025-12-22 14:08:04 -05:00
Jonathan Swoboda
84b5d9b21c [core] Remove deprecated config options from before 2025 (#12622)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-22 14:00:12 -05:00
J. Nick Koston
b272966d19 Merge branch 'deprecate-using-esp-idf' into integration 2025-12-22 08:48:51 -10:00
J. Nick Koston
b0c99ec1ce Merge branch 'cleanup-old-deprecations' into integration 2025-12-22 08:48:47 -10:00
J. Nick Koston
218c8e4d75 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-22 08:48:37 -10:00
J. Nick Koston
2a53a89cee Merge branch 'dev' into esp8266_prefs_avoid_heap 2025-12-22 07:58:00 -10:00
J. Nick Koston
b191461929 Merge branch 'dev' into move_comment_build_info 2025-12-22 07:57:34 -10:00
J. Nick Koston
6383fe4598 [core] Add zero-allocation object_id methods (#12578) 2025-12-22 07:56:33 -10:00
J. Nick Koston
265ad9d264 [esp32_camera] Reduce loop overhead and improve frame latency with wake_loop_threadsafe (#12601) 2025-12-22 07:55:28 -10:00
J. Nick Koston
1bdbc4cb85 [esp32_ble] Avoid string allocation when setting BLE device name (#12579) 2025-12-22 07:54:55 -10:00
J. Nick Koston
1756fc31b0 [api] Use union for iterators to reduce APIConnection size by ~16 bytes (#12563) 2025-12-22 07:54:17 -10:00
Jonathan Swoboda
03db8e4f54 Fix 2025-12-22 12:22:04 -05:00
J. Nick Koston
74b075d3cf [codegen] Add static storage class to global variables for size optimization (#12616) 2025-12-22 07:03:17 -10:00
Jonathan Swoboda
ce86f01cba Change 2025-12-22 12:02:26 -05:00
Jonathan Swoboda
bee5847464 Fix 2025-12-22 11:34:49 -05:00
Jonathan Swoboda
4ffbdd9a3a Fix 2025-12-22 11:23:43 -05:00
Jonathan Swoboda
c5ac62676c Fix 2025-12-22 11:19:56 -05:00
Jonathan Swoboda
63b8fa004c [core] Fix mdns and network for using_esp_idf deprecation
- mdns: Remove ESPmDNS Arduino library for ESP32, use IDF component for both frameworks
- network: Use using_arduino for IPv6 to maintain Arduino behavior (always True)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 11:09:37 -05:00
Jonathan Swoboda
66b46ea81e [core] Deprecate using_esp_idf, replace with is_esp32
Arduino on ESP32 now builds ESP-IDF as a component, so add_idf_sdkconfig_option()
and add_idf_component() work with both Arduino and ESP-IDF frameworks.

The using_esp_idf property is deprecated and now emits a warning. All internal
usages have been replaced with is_esp32.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 11:00:27 -05:00
Jonathan Swoboda
fc019bf3e3 [core] Remove deprecated config options from before 2025
Remove old deprecated configuration options that have been showing
error messages for years:

- bedjet/climate: ble_client_id, time_id, receive_timeout (2022)
- bh1750: resolution, measurement_duration (2022)
- ethernet: enable_mdns (2021)
- wifi: enable_mdns (2021)
- i2c: multiplexer (2021)
- uart: invert (2021)
- tca9548a: scan (2021)
- tuya/light: rgb_datapoint, hsv_datapoint (2023)
- remote_base: receiver_id in triggers/dumpers, coolix data (2020-2023)
- sensor: last_reset_type (2021)
- template/switch: restore_state (2023)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 10:46:53 -05:00
J. Nick Koston
da872dcbf3 Merge branch 'web_server_stack_format' into integration 2025-12-21 22:26:12 -10:00
J. Nick Koston
a015cbedfe Merge branch 'dev' into api_avoid_copies 2025-12-21 22:03:47 -10:00
J. Nick Koston
c7006f8c33 Merge remote-tracking branch 'upstream/dev' into web_server_stack_format 2025-12-21 22:01:29 -10:00
Clint Armstrong
52eb08f48f [thermostat] Enhance timer behavior for immediate response to duration changes (#12610) 2025-12-21 23:52:17 -06:00
J. Nick Koston
fe84aba2ee Merge branch 'storage_class_optimize' into integration 2025-12-21 19:30:10 -10:00
J. Nick Koston
0d993691d4 [logger] RP2040: Use write() with known length instead of println() (#12615) 2025-12-21 17:59:30 -10:00
J. Nick Koston
f17a0000aa lvgl has a special case 2025-12-21 17:41:48 -10:00
J. Nick Koston
8db6ff4039 Merge branch 'storage_class_optimize' into integration 2025-12-21 17:33:16 -10:00
J. Nick Koston
ff808618da better to be a kw 2025-12-21 17:27:49 -10:00
J. Nick Koston
57baf7ac7b [codegen] Add static storage class to global variables for size optimization 2025-12-21 17:20:01 -10:00
J. Nick Koston
da8c4cd654 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-21 12:13:04 -10:00
Douwe
39926909af [water_heater] (1/4) Implement API/Core/component for new water_heater component (#12498)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-21 11:36:34 -10:00
J. Nick Koston
637e032528 [esp32_camera] Throttle frame logging to reduce overhead and improve throughput (#12586) 2025-12-21 09:04:43 -10:00
Anna Oake
d89eaf5bf6 [cc1101] Fix option defaults and move them to YAML (#12608) 2025-12-21 13:04:17 -05:00
J. Nick Koston
9aff4a15a3 Merge branch 'esp32_camera_latancy_reduce' into integration 2025-12-21 07:53:18 -10:00
J. Nick Koston
dbf494fd98 Merge branch 'fix_slow_esp32_camera_at_high_fps' into esp32_camera_latancy_reduce 2025-12-21 07:53:07 -10:00
J. Nick Koston
219cf26d98 tweak logging 2025-12-21 07:36:25 -10:00
J. Nick Koston
bf617c3279 [web_server] Replace str_sprintf with stack buffers (#12592) 2025-12-21 07:32:05 -10:00
J. Nick Koston
c70eab931e [api] Add zero-copy support for Home Assistant state response messages (#12585) 2025-12-21 07:31:54 -10:00
J. Nick Koston
a799ac6488 [syslog] Eliminate heap allocations in log path (#12589) 2025-12-21 07:10:27 -10:00
polyfloyd
5a36cea5ec Add nix files to gitignore (#12604) 2025-12-21 09:26:03 -05:00
J. Nick Koston
60756db06d [syslog] Use C++17 nested namespace syntax (#12594) 2025-12-21 02:47:37 -06:00
Keith Burzinski
2113858f89 [sprinkler] Squash a few bugs + minor optimization (#12436) 2025-12-21 02:45:24 -06:00
J. Nick Koston
14ea235939 Merge branch 'esp32_camera_latancy_reduce' into integration 2025-12-20 21:59:01 -10:00
J. Nick Koston
26f1be40dc pro 2025-12-20 21:58:24 -10:00
J. Nick Koston
0467fdbb61 Merge branch 'esp32_camera_latancy_reduce' into integration 2025-12-20 21:31:46 -10:00
J. Nick Koston
c1463a569c reorder 2025-12-20 21:31:30 -10:00
J. Nick Koston
6dd41a14c4 try send right away 2025-12-20 21:17:19 -10:00
J. Nick Koston
9855d86616 try send right away 2025-12-20 21:10:22 -10:00
J. Nick Koston
ffe459e666 [esp32_camera] Reduce loop overhead and improve frame latency with wake_loop_threadsafe 2025-12-20 15:30:24 -10:00
J. Nick Koston
1f15023d30 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-20 14:49:34 -10:00
dependabot[bot]
e89fe9b945 Bump aioesphomeapi from 43.4.0 to 43.5.0 (#12599)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 23:59:48 +00:00
dependabot[bot]
f1362cd9fe Bump aioesphomeapi from 43.3.0 to 43.4.0 (#12597)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-20 22:37:10 +00:00
Frédéric Metrich
bf554a58ef [const] Add CONF_ON_DATA and consolidate definitions (#12595)
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 12:17:09 -10:00
J. Nick Koston
9d01357e8a Merge branch 'ha_state_only_copy_state' into integration 2025-12-20 11:46:04 -10:00
J. Nick Koston
d6cf80f95a Merge remote-tracking branch 'origin/syslog_no_heap' into integration 2025-12-20 11:26:06 -10:00
J. Nick Koston
8d14c1ceb1 Merge remote-tracking branch 'origin/no_alloc_object_id' into integration 2025-12-20 11:25:54 -10:00
J. Nick Koston
9ca2b0adb7 Merge remote-tracking branch 'origin/syslog_ns' into integration 2025-12-20 11:25:40 -10:00
J. Nick Koston
945d5890b5 Revert "[improv_serial] Use stack buffer for RSSI formatting"
This reverts commit c0ab783ba2.
2025-12-20 11:25:22 -10:00
J. Nick Koston
2b53976b0f [syslog] Use C++17 nested namespace syntax 2025-12-20 11:23:21 -10:00
J. Nick Koston
589942f52c simplify logic 2025-12-20 11:11:54 -10:00
J. Nick Koston
a9c294bc03 copilot edge cases 2025-12-20 11:09:52 -10:00
J. Nick Koston
a0d1a10d17 Update tests/integration/test_syslog.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-20 11:00:31 -10:00
J. Nick Koston
496c09b333 bounds fixes 2025-12-20 11:00:03 -10:00
J. Nick Koston
1dfb808590 Merge branch 'improv_serial_stack_format' into integration 2025-12-20 10:58:24 -10:00
J. Nick Koston
c0ab783ba2 [improv_serial] Use stack buffer for RSSI formatting 2025-12-20 10:55:16 -10:00
J. Nick Koston
6b7115f40e Merge branch 'web_server_no_heap_churn_prints' into integration 2025-12-20 10:49:46 -10:00
J. Nick Koston
42610d5a6f 8266 2025-12-20 10:48:52 -10:00
J. Nick Koston
ad17c8524c Merge branch 'web_server_no_heap_churn_prints' into integration 2025-12-20 10:41:15 -10:00
J. Nick Koston
1a60ce8cc6 Merge branch 'dev' into no_alloc_object_id 2025-12-20 10:40:52 -10:00
J. Nick Koston
644e806afd [zwave_proxy] Add missing USE_API guards for clang-tidy (#12590) 2025-12-20 10:40:43 -10:00
J. Nick Koston
de3e72af04 [web_server] Replace str_sprintf with stack buffers 2025-12-20 10:39:19 -10:00
J. Nick Koston
43046b2c55 Merge remote-tracking branch 'origin/syslog_no_heap' into integration 2025-12-20 10:31:48 -10:00
J. Nick Koston
808f1ac078 Merge branch 'no_alloc_object_id' into integration 2025-12-20 10:31:40 -10:00
J. Nick Koston
c22eff24d8 [syslog] Eliminate heap allocations in log path 2025-12-20 10:24:46 -10:00
J. Nick Koston
f470cf5c87 add missing USE_API guard 2025-12-20 10:05:50 -10:00
Leo Bergolth
6c2d255230 send NIL ("-") as timestamp if time source is not valid (#12588) 2025-12-20 10:04:59 -10:00
J. Nick Koston
832d232814 Merge branch 'fix_slow_esp32_camera_at_high_fps' into integration 2025-12-20 09:13:13 -10:00
J. Nick Koston
6efb167b65 edge case 2025-12-20 09:12:55 -10:00
J. Nick Koston
4d99632a61 [esp32_camera] Throttle frame logging to reduce overhead and improve throughput 2025-12-20 09:02:39 -10:00
J. Nick Koston
6cb66559bc fix test 2025-12-20 08:42:52 -10:00
Stuart Parmenter
6f3bfc2060 [hub75] Bump esp-hub75 version to 0.1.7 (#12564) 2025-12-20 13:18:20 -05:00
J. Nick Koston
e812d8683a tests 2025-12-20 07:23:55 -10:00
J. Nick Koston
cc9f42cc9a [api] Add zero-copy support for Home Assistant state response messages 2025-12-20 07:22:36 -10:00
J. Nick Koston
89012f80a9 Merge branch 'dev' into api_avoid_copies 2025-12-20 06:48:24 -10:00
J. Nick Koston
9a54cc12ba Merge branch 'dev' into no_alloc_object_id 2025-12-20 06:47:49 -10:00
J. Nick Koston
40eb898814 [api] Add zero-copy support for noise encryption key requests (#12405) 2025-12-20 06:47:30 -10:00
J. Nick Koston
64269334ce [text_sensor] Avoid string copies in callbacks by passing const ref (#12503)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-20 06:46:13 -10:00
Eduard Llull
121375ff39 [display_menu_base] Call on_value_ after updating the select (#12584) 2025-12-20 10:59:14 -05:00
J. Nick Koston
48cdf9e036 [tests] Fix race condition in alarm control panel state transitions test (#12581) 2025-12-20 10:47:29 -05:00
J. Nick Koston
bed779b1c9 Merge branch 'alarm_control_flakey' into integration 2025-12-19 21:18:08 -10:00
J. Nick Koston
a31bef5390 [tests] Fix race condition in alarm control panel state transitions test 2025-12-19 21:01:31 -10:00
J. Nick Koston
2d792ddf40 Merge branch 'noise_api_zero_copy' into integration 2025-12-19 20:12:58 -10:00
J. Nick Koston
7365885464 Merge branch 'dev' into noise_api_zero_copy 2025-12-19 20:12:47 -10:00
J. Nick Koston
df5193ff73 fix merge 2025-12-19 20:11:21 -10:00
J. Nick Koston
2d6103f0d0 Merge branch 'text_sensor_avoid_copies_const_ref' into integration 2025-12-19 20:07:35 -10:00
J. Nick Koston
4036671583 Update esphome/components/sensor/sensor.cpp 2025-12-19 20:06:22 -10:00
J. Nick Koston
4a1db67566 Update esphome/components/sensor/sensor.cpp 2025-12-19 20:06:10 -10:00
J. Nick Koston
0814419d61 Update esphome/components/text_sensor/text_sensor.h 2025-12-19 20:05:30 -10:00
J. Nick Koston
c799ce05f7 Update esphome/components/text_sensor/text_sensor.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 20:05:11 -10:00
J. Nick Koston
8088f09902 Update esphome/components/text_sensor/text_sensor.h 2025-12-19 20:05:05 -10:00
J. Nick Koston
0cff5326bc Update esphome/components/text_sensor/text_sensor.cpp 2025-12-19 20:04:36 -10:00
J. Nick Koston
60d66365ad Update esphome/components/sensor/sensor.cpp 2025-12-19 20:04:17 -10:00
J. Nick Koston
f727edab58 Update esphome/components/text_sensor/text_sensor.cpp 2025-12-19 20:03:43 -10:00
J. Nick Koston
a0647cbe71 Update esphome/components/text_sensor/text_sensor.cpp 2025-12-19 20:03:14 -10:00
J. Nick Koston
0543d65969 Update esphome/components/text_sensor/text_sensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 20:02:54 -10:00
J. Nick Koston
4bfe09768c Update esphome/components/sensor/sensor.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 20:02:31 -10:00
J. Nick Koston
4d0a54d9f0 Update esphome/components/sensor/sensor.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 20:02:24 -10:00
J. Nick Koston
4739e9cabe Merge branch 'dev' into text_sensor_avoid_copies_const_ref 2025-12-19 19:13:33 -10:00
J. Nick Koston
4c4c6fb257 Merge branch 'parition_callbacks' into text_sensor_avoid_copies_const_ref 2025-12-19 19:12:10 -10:00
J. Nick Koston
3e313014e1 [core] Migrate entities to use lazy callbacks (#12580) 2025-12-19 19:04:21 -10:00
J. Nick Koston
68b7fbdecf Merge branch 'lazy_allocate_entity_callbacks' - add LazyCallbackManager for other entities 2025-12-19 17:19:39 -10:00
J. Nick Koston
e7ea17fcba [core] Migrate entities to use lazy callbacks 2025-12-19 17:13:27 -10:00
Martin Ebner
be6c1e4ec0 [sen5x][sgp4x] Move configuration keys from SEN5x and SGP4x to const.py (#12567)
Co-authored-by: Martin Ebner <martinebner@me.com>
2025-12-19 21:29:02 -05:00
Keith Burzinski
730bf206de [wifi] Fix for wifi_info when static IP is configured (#12576) 2025-12-19 21:25:16 -05:00
J. Nick Koston
4eea8082cd Merge branch 'name_with_suffix_ble' into integration 2025-12-19 16:01:24 -10:00
J. Nick Koston
78899831cf dry 2025-12-19 15:55:20 -10:00
J. Nick Koston
6cac302c01 Merge branch 'name_with_suffix_ble' into integration 2025-12-19 15:52:45 -10:00
J. Nick Koston
a76461cf5f [esp32_ble] Avoid string allocation when setting BLE device name 2025-12-19 15:50:25 -10:00
J. Nick Koston
6a9a6554e1 Merge branch 'no_alloc_object_id' into integration 2025-12-19 15:25:38 -10:00
J. Nick Koston
6904f0f3c4 fix 2025-12-19 15:25:25 -10:00
J. Nick Koston
7eca8905ea refactor 2025-12-19 15:13:16 -10:00
J. Nick Koston
01224f25f7 tweak 2025-12-19 15:08:02 -10:00
J. Nick Koston
cd6240541b [core] Add zero-allocation get_object_id_to() method 2025-12-19 15:03:27 -10:00
J. Nick Koston
94fcd18306 Merge remote-tracking branch 'upstream/dev' into integration
# Conflicts:
#	esphome/components/fan/fan_traits.h
#	esphome/components/http_request/ota/ota_http_request.cpp
#	tests/integration/test_alarm_control_panel_state_transitions.py
2025-12-19 14:22:19 -10:00
J. Nick Koston
da472f3f79 Merge branch 'dev' into noise_api_zero_copy 2025-12-19 12:46:07 -10:00
J. Nick Koston
c9fccdff25 [fan] Add zero-copy support for API preset mode commands (#12404)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 22:05:52 +00:00
J. Nick Koston
ada6c42f3f [alarm_control_panel] Remove redundant per-state callbacks (#12171)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-19 11:48:14 -10:00
J. Nick Koston
988b888c63 [ota] Replace std::function callbacks with listener interface (#12167) 2025-12-19 11:19:07 -10:00
J. Nick Koston
940afdbb12 [climate] Add zero-copy support for API custom fan mode and preset commands (#12402) 2025-12-19 11:18:50 -10:00
J. Nick Koston
81e91c2a8f [esp32_ble] Add stack-based UUID formatting to avoid heap allocations (#12510) 2025-12-19 11:18:32 -10:00
J. Nick Koston
ebc3d28ade [wifi] Replace optional with sentinel values to reduce RAM and clarify API (#12446) 2025-12-19 11:18:15 -10:00
J. Nick Koston
3fff2f2f0a Merge branch 'web_server_stack_format' into integration 2025-12-19 10:50:16 -10:00
J. Nick Koston
04eb64f361 safer 2025-12-19 10:49:19 -10:00
J. Nick Koston
4464e464b6 safer 2025-12-19 10:48:52 -10:00
Rene Guca
25cebedcfc [dht] Fix "Falling edge for bit 39 failed!" for Sonoff THS01 (#9225)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-19 15:42:39 -05:00
J. Nick Koston
20a12ca02a Merge branch 'web_server_stack_format' into integration 2025-12-19 10:20:38 -10:00
J. Nick Koston
b2a43a3a69 [web_server] Use stack buffers for value formatting to reduce flash usage 2025-12-19 10:18:58 -10:00
dependabot[bot]
98ed679b19 Bump ruff from 0.14.9 to 0.14.10 (#12572)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-19 19:22:56 +00:00
J. Nick Koston
097617cb4e Merge remote-tracking branch 'upstream/dev' into integration 2025-12-19 09:22:29 -10:00
dependabot[bot]
59b38d79b4 Bump docker/setup-buildx-action from 3.11.1 to 3.12.0 in the docker-actions group (#12574)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 09:18:52 -10:00
dependabot[bot]
26c16f4ca2 Bump voluptuous from 0.15.2 to 0.16.0 (#12573)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-19 09:18:33 -10:00
Jas Strong
940e619481 [aqi, hm3301, pmsx003] Air Quality Index improvements (#12203)
Co-authored-by: jas <jas@asspa.in>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-19 13:42:11 -05:00
J. Nick Koston
043204baa6 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-19 06:34:49 -10:00
J. Nick Koston
92157c89bc cleanup 2025-12-19 06:29:57 -10:00
J. Nick Koston
25f83384a4 cleanup 2025-12-19 06:29:36 -10:00
Jonathan Swoboda
eaca81c3ab Merge branch 'release' into dev 2025-12-19 10:53:18 -05:00
Jonathan Swoboda
93e38f2608 Merge pull request #12569 from esphome/bump-2025.12.1
2025.12.1
2025-12-19 10:53:05 -05:00
Jonathan Swoboda
3a888326d8 Bump version to 2025.12.1 2025-12-19 10:13:35 -05:00
Keith Burzinski
f0d0ea60a7 [esp32_ble, esp32_ble_tracker] Fix crash, error messages when ble.disable called during boot (#12560) 2025-12-19 10:13:35 -05:00
Jonathan Swoboda
7ca11764ab [template.alarm_control_panel] Fix compile without binary_sensor (#12548)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-19 10:13:35 -05:00
Jonathan Swoboda
3e38a5e630 [esp32_camera] Fix I2C driver conflict with other components (#12533)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-19 10:13:35 -05:00
Jonathan Swoboda
636be92c97 [bme68x_bsec2_i2c] Add MULTI_CONF support for multiple sensors (#12535)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-19 10:13:35 -05:00
Jack Wilsdon
195b1c6323 [pm1006] Fix "never" update interval detection (#12529) 2025-12-19 10:13:35 -05:00
Anna Oake
7e08092012 [cc1101] Fix default frequencies (#12539) 2025-12-19 10:13:35 -05:00
J. Nick Koston
86119c3439 Merge branch 'get_peername_stack_save_ram' into integration 2025-12-18 22:18:00 -10:00
J. Nick Koston
cf404c34d0 [api] Use stack buffers for peername logging to reduce per-connection memory 2025-12-18 22:13:27 -10:00
pixelgrb
f962497db1 [mmc5603] enable AUTO_SR_en to compensate for temperature drift (#12556)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-18 23:13:36 -05:00
J. Nick Koston
ce1c6721b1 Merge branch 'union_iter' into integration 2025-12-18 16:55:06 -10:00
J. Nick Koston
a7f82f5201 state machine 2025-12-18 16:50:41 -10:00
J. Nick Koston
38afc5149a [api] Use union for iterators to reduce APIConnection size by ~16 bytes 2025-12-18 16:18:45 -10:00
Keith Burzinski
7ae3a11d6b [esp32_ble, esp32_ble_tracker] Fix crash, error messages when ble.disable called during boot (#12560) 2025-12-18 19:42:47 -06:00
J. Nick Koston
7a5a768c04 Merge remote-tracking branch 'kbx81/20251218-ble-disable-fixes' into integration 2025-12-18 15:21:57 -10:00
kbx81
37e2a114db [esp32_ble, esp32_ble_tracker] Fix crash, error messages when ble.disable called during boot 2025-12-18 18:58:26 -06:00
J. Nick Koston
b5950d41b5 Merge remote-tracking branch 'upstream/move_comment_build_info' into integration 2025-12-18 11:19:51 -10:00
dependabot[bot]
1c50c2b672 Bump ruamel-yaml from 0.18.16 to 0.18.17 (#12555)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-18 11:19:19 -10:00
J. Nick Koston
3a69cb9c13 tidy 2025-12-18 07:53:48 -10:00
J. Nick Koston
5547f9f5d6 span 2025-12-18 06:58:32 -10:00
J. Nick Koston
12d8e2ada2 tweaks 2025-12-18 06:56:12 -10:00
J. Nick Koston
455091a03f tweaks 2025-12-18 06:55:02 -10:00
J. Nick Koston
23ee8bdcaf [core] Move comment to PROGMEM on ESP8266 2025-12-18 06:48:23 -10:00
Jonathan Swoboda
41fd1762e9 [core] Deprecate custom_components folder (#12552)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 11:46:16 -05:00
J. Nick Koston
cd93468225 [core] Move comment to PROGMEM on ESP8266 2025-12-18 06:41:23 -10:00
J. Nick Koston
2cf6ed2af7 [socket] Refactor socket implementations for memory efficiency and code quality (#12550) 2025-12-18 09:07:35 -07:00
J. Nick Koston
b47b7d43fd [api] Remove unused force parameter from encode_message (#12551) 2025-12-18 09:06:16 -07:00
Jonathan Swoboda
663a4304e0 [libretiny] Fix millis() ambiguity on BK72XX (#12534)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-18 07:50:31 -05:00
J. Nick Koston
bef017fd3e Merge branch 'encode_message_dead_code' into integration 2025-12-17 20:05:59 -10:00
J. Nick Koston
6707ac6a0f [api] Remove unused force parameter from encode_message 2025-12-17 20:03:40 -10:00
J. Nick Koston
ec55dcbe41 Merge branch 'socket_reorg_cleanup' into integration 2025-12-17 19:28:20 -10:00
J. Nick Koston
655f493eaa [socket] Refactor socket implementations for memory efficiency and code quality 2025-12-17 19:20:35 -10:00
J. Nick Koston
50f0f7595b Merge remote-tracking branch 'upstream/dev' into integration 2025-12-17 18:50:37 -10:00
Jonathan Swoboda
ca47bad90a [template.alarm_control_panel] Fix compile without binary_sensor (#12548)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 23:34:04 -05:00
J. Nick Koston
4f821a6d76 [wifi] Reduce scan logging to prevent blocking loop during connection (#12544) 2025-12-17 18:21:46 -10:00
J. Nick Koston
426305836d [esp32][libretiny] Avoid duplicate snprintf when syncing preferences (#12542) 2025-12-17 18:16:14 -10:00
J. Nick Koston
c6b33586c1 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-17 15:54:10 -10:00
dependabot[bot]
1b5af7d21d Bump github/codeql-action from 4.31.8 to 4.31.9 (#12524)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-17 15:22:19 -10:00
J. Nick Koston
a97f637cb9 Merge branch 'wifi_connect_blocked_loop_logging' into integration 2025-12-17 14:14:11 -10:00
J. Nick Koston
0185541000 [wifi] Reduce scan logging to prevent blocking loop during connection 2025-12-17 14:13:37 -10:00
David Woodhouse
9de7df7b5b Add build info to image (#12425)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-18 00:06:52 +00:00
J. Nick Koston
ce18b4c3ca Merge branch 'prefs_snprintf_once' into integration 2025-12-17 14:01:12 -10:00
J. Nick Koston
60b266e73d [esp32][libretiny] Avoid duplicate snprintf when syncing preferences 2025-12-17 14:00:19 -10:00
J. Nick Koston
4c8a2fe3d4 Merge branch 'fan_zero_copy' into noise_api_zero_copy 2025-12-17 16:41:26 -07:00
J. Nick Koston
190ebecd7b Merge branch 'climate_zero_copy' into fan_zero_copy 2025-12-17 16:41:18 -07:00
J. Nick Koston
71b6fc4baa Merge branch 'dev' into climate_zero_copy 2025-12-17 16:41:06 -07:00
J. Nick Koston
bec60c4da8 Merge branch 'dev' into api_avoid_copies 2025-12-17 16:40:39 -07:00
J. Nick Koston
df2936f686 Merge branch 'dev' into parition_callbacks 2025-12-17 16:40:30 -07:00
J. Nick Koston
1fb89e5223 Merge branch 'buildinfo' into integration 2025-12-17 13:27:58 -10:00
J. Nick Koston
8c185254ef give 6 months of get_compilation_time for back compat 2025-12-17 13:04:46 -10:00
David Woodhouse
14ecb906a1 Merge branch 'dev' into buildinfo 2025-12-17 22:59:57 +00:00
Jonathan Swoboda
2b337aa306 [esp32_camera] Fix I2C driver conflict with other components (#12533)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-17 17:37:59 -05:00
Jonathan Swoboda
4ddaff4027 [esp32] Dynamically embed managed component server certificates (#12509)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-17 17:26:56 -05:00
J. Nick Koston
91c504061b [select] Eliminate string allocation in state callbacks (#12505)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-17 12:19:26 -10:00
Jonathan Swoboda
dc8f7abce2 [bme68x_bsec2_i2c] Add MULTI_CONF support for multiple sensors (#12535)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 17:07:42 -05:00
Jonathan Swoboda
3d673ac55e [ci] Check changed headers in clang-tidy when using --changed (#12540)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 11:13:18 -10:00
Jack Wilsdon
b02696edc0 [pm1006] Fix "never" update interval detection (#12529) 2025-12-18 07:40:31 +11:00
David Woodhouse
0688abdbd8 Merge branch 'dev' into buildinfo 2025-12-17 20:35:06 +00:00
Anna Oake
f9720026d0 [cc1101] Fix default frequencies (#12539) 2025-12-17 14:19:18 -05:00
David Woodhouse
745f5b8dd2 Merge branch 'dev' into buildinfo 2025-12-17 19:15:48 +00:00
Jonathan Swoboda
d7b04a3d18 [nextion] Fix clang-tidy error on Zephyr for HTTPClient (#12538)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 13:59:49 -05:00
David Woodhouse
01d8775005 Merge branch 'dev' into buildinfo 2025-12-17 18:04:45 +00:00
Jonathan Swoboda
0e71fa97a7 [spi] Add SPIInterface stub for clang-tidy on unsupported platforms (#12532)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-17 12:18:25 -05:00
J. Nick Koston
7701371bb4 Merge branch 'fix-bk72xx-millis-ambiguity' into integration 2025-12-17 07:18:19 -10:00
J. Nick Koston
42e061c9ae [text] Avoid string copies in callbacks by passing const ref (#12504) 2025-12-17 12:00:19 -05:00
J. Nick Koston
94763ebdab [libretiny] Store preference keys as uint32_t, convert to string only at FlashDB boundary (#12500) 2025-12-17 11:59:40 -05:00
J. Nick Koston
f32bb618ac [esp32] Store preference keys as uint32_t, convert to string only at NVS boundary (#12494) 2025-12-17 11:59:35 -05:00
Edward Firmo
0707f383a6 [nextion] Use ESP-IDF for ESP32 Arduino (#9429)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-17 11:45:17 -05:00
Piotr Szulc
e91c6a79ea [deep_sleep] Deep sleep for BK72xx (#12267)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-17 11:45:05 -05:00
J. Nick Koston
63fc8b4e5a [core] Refactor str_snake_case and str_sanitize to use constexpr helpers (#12454) 2025-12-17 11:30:12 -05:00
J. Nick Koston
ab73ed76b8 [esphome] Improve OTA field alignment to save 4 bytes on 32-bit (#12461) 2025-12-17 11:29:58 -05:00
J. Nick Koston
bf6a03d1cf [factory_reset] Optimize memory by storing interval as uint16_t seconds (#12462) 2025-12-17 11:29:51 -05:00
J. Nick Koston
9928ab09cf [time] Convert to C++17 nested namespace syntax (#12463) 2025-12-17 11:29:43 -05:00
Jonathan Swoboda
eb2392b33a [libretiny] Fix millis() ambiguity on BK72XX
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-17 11:25:21 -05:00
David Woodhouse
7e36112687 Merge branch 'dev' into buildinfo 2025-12-17 09:32:40 +00:00
Thomas Rupprecht
56c1691d72 [pca9685,sx126x,sx127x] Use frequency/float_range check (#12490)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-16 22:52:28 -05:00
Roger Fachini
a065990ab9 [update] Add check action to trigger update checks (#12415) 2025-12-16 22:20:12 -05:00
Stuart Parmenter
084f517a20 [hub75] Add set_brightness action (#12521) 2025-12-16 22:12:33 -05:00
David Woodhouse
77d914e67f Merge branch 'dev' into buildinfo 2025-12-17 01:52:36 +00:00
Jonathan Swoboda
1122ec354f [esp32] Add OTA rollback support (#12460)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 20:07:57 -05:00
Jonathan Swoboda
431183eebc [ledc,mqtt,resampler] Remove unnecessary ESP-IDF framework restrictions (#12442)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 20:07:09 -05:00
Jonathan Swoboda
08beaf8750 [esp32] Remove Arduino-specific code from core.cpp (#12501)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 20:06:12 -05:00
David Woodhouse
f2f30337a0 Merge branch 'dev' into buildinfo 2025-12-17 00:44:15 +00:00
Jonathan Swoboda
18814f12dc [http_request] Use ESP-IDF for ESP32 Arduino (#12428)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 19:44:14 -05:00
Jonathan Swoboda
9cd888cef6 [spi] Use ESP-IDF driver for ESP32 Arduino (#12420)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 19:44:01 -05:00
Thomas Rupprecht
9727c7135c [openthread] channel range, fix typo, use C++17 nested namespace syntax (#12422) 2025-12-16 19:43:18 -05:00
Thomas Rupprecht
93621d85b0 [climate] Improve temperature unit regex (#12032) 2025-12-16 19:43:10 -05:00
Thomas Rupprecht
046ea922e8 [esp32] improve types and variable naming (#12423) 2025-12-16 19:42:52 -05:00
David Woodhouse
71f2331bc8 Fix clang-format: use lowercase buf_size variable name 2025-12-17 00:42:46 +00:00
Jeff Zigler
fab4efb469 [esp32] Fix serial logging on h2, c2 & c61 (#12522)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-16 19:42:12 -05:00
Jonathan Swoboda
efc5672567 Merge branch 'release' into dev 2025-12-16 18:57:37 -05:00
Jonathan Swoboda
0ea5f2fd81 Merge pull request #12525 from esphome/bump-2025.12.0
2025.12.0
2025-12-16 18:57:20 -05:00
David Woodhouse
8358ef0096 Use ESPHOME_strncpy_P in get_build_time_string()
Replace platform-specific ifdef with cross-platform ESPHOME_strncpy_P
macro for consistency.
2025-12-16 23:06:31 +00:00
David Woodhouse
f8c9cf8fd9 Use PROGMEM for version text sensor strings on ESP8266
Build version string incrementally from PROGMEM literals using
ESPHOME_strncpy_P and ESPHOME_strncat_P. Write hash and build time
directly into buffer without temporary variables. Calculate buffer
size based on actual components needed.

Add ESPHOME_strncat_P macro to progmem.h for cross-platform PROGMEM
string concatenation.
2025-12-16 23:05:07 +00:00
Jonathan Swoboda
fa3d998c3d Bump version to 2025.12.0 2025-12-16 17:15:50 -05:00
David Woodhouse
8429684fce Fix clang-format: use uppercase PREFIX constant name 2025-12-16 19:46:04 +00:00
David Woodhouse
a30052e7c0 Use PROGMEM for version text sensor strings on ESP8266
Build version string incrementally from PROGMEM literal prefix, avoiding
format strings in RAM. Copy from PROGMEM on ESP8266, use directly on
other platforms.
2025-12-16 19:22:42 +00:00
David Woodhouse
175250deb0 Use PROGMEM for MQTT version format string on ESP8266
Store format string in PROGMEM and copy to RAM buffer on ESP8266 before
use. On other platforms, use the format string directly. This saves RAM
on ESP8266 while maintaining the same functionality.
2025-12-16 19:20:50 +00:00
David Woodhouse
12734ba258 Revert "Use PROGMEM format strings to reduce RAM usage on ESP8266"
This reverts commit da67c47a76.
2025-12-16 19:03:13 +00:00
David Woodhouse
da67c47a76 Use PROGMEM format strings to reduce RAM usage on ESP8266
Replace str_sprintf() with snprintf_P() and PSTR() to keep format
strings in flash instead of RAM. Also removes 'config hash 0x' prefix
to save additional bytes.
2025-12-16 18:13:35 +00:00
David Woodhouse
38167c268f Add get_config_version_hash() and make hash functions constexpr
Add Application::get_config_version_hash() as a constexpr that returns
fnv1a_hash_extend(config_hash, ESPHOME_VERSION).

Make get_config_hash(), get_build_time(), fnv1a_hash(), and
fnv1a_hash_extend() constexpr inline functions.

Replace open-coded fnv1a_hash_extend(config_hash, ESPHOME_VERSION)
calls with get_config_version_hash() in sensor and wifi components.

Remove now-unnecessary version.h includes from component files.
2025-12-16 17:15:19 +00:00
David Woodhouse
7298db0a7e Add tests for source file removal detection in copy_src_tree
Add tests covering the logic that detects when source files are removed:
- test_copy_src_tree_detects_removed_source_file: Verifies that removing
  a regular source file triggers sources_changed flag
- test_copy_src_tree_ignores_removed_generated_file: Verifies that removing
  a generated file (like build_info_data.h) does not trigger sources_changed
2025-12-16 16:45:28 +00:00
J. Nick Koston
6eb8095480 Merge branch 'dev' into buildinfo 2025-12-16 10:29:51 -06:00
Jonathan Swoboda
5e630e9255 Merge branch 'beta' into dev 2025-12-16 11:26:08 -05:00
Jonathan Swoboda
864aaeec01 Merge pull request #12520 from esphome/bump-2025.12.0b5
2025.12.0b5
2025-12-16 11:25:57 -05:00
David Woodhouse
3679a81220 Merge branch 'dev' into buildinfo 2025-12-16 15:55:36 +00:00
Jonathan Swoboda
9c88e44300 Bump version to 2025.12.0b5 2025-12-16 10:35:31 -05:00
Jonathan Swoboda
4d6a93f92d [uart] Fix UART on default UART0 pins for ESP-IDF (#12519)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 10:35:31 -05:00
J. Nick Koston
7216120bfd [socket] Fix getpeername() returning local address instead of remote in LWIP raw TCP (#12475) 2025-12-16 10:35:31 -05:00
Jonathan Swoboda
1897551b28 [uart] Fix UART on default UART0 pins for ESP-IDF (#12519)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-16 10:17:17 -05:00
David Woodhouse
dfae9e5750 Merge branch 'dev' into buildinfo 2025-12-16 10:21:02 +00:00
J. Nick Koston
ead60bc5c4 [socket] Fix getpeername() returning local address instead of remote in LWIP raw TCP (#12475) 2025-12-16 00:48:30 -06:00
David Woodhouse
87f88b8a9a Add version.h includes to sensor components
Add missing version.h includes to sen5x, sgp30, and sgp4x components
for ESPHOME_VERSION definition.
2025-12-16 00:32:30 +00:00
David Woodhouse
ba79a8e6c8 Merge branch 'dev' into buildinfo 2025-12-16 00:19:29 +00:00
David Woodhouse
e8a3a8380d Remove stray debug 2025-12-16 00:18:56 +00:00
David Woodhouse
305a58cb84 Use config_hash in MQTT and version sensor
Change MQTT sw_version and version text sensor to display config_hash
instead of build_time_str. Format: "(config hash 0xXXXXXXXX)"

Version sensor with hide_timestamp=false also includes build time:
"(config hash 0xXXXXXXXX, built: YYYY-MM-DD HH:MM:SS +ZZZZ)"
2025-12-16 00:09:28 +00:00
David Woodhouse
f231fc856b Use fnv1a_hash_extend with config_hash and version for wifi preferences
Change wifi component to use fnv1a_hash_extend(config_hash, ESPHOME_VERSION)
instead of fnv1_hash(compilation_time) for the preferences hash.

This ensures wifi settings are invalidated on config or version changes,
not just on recompilation.
2025-12-16 00:05:43 +00:00
Jonathan Swoboda
7fe8e53f82 Merge branch 'beta' into dev 2025-12-15 19:01:12 -05:00
Jonathan Swoboda
8cf0ee38a3 Merge pull request #12513 from esphome/bump-2025.12.0b4
2025.12.0b4
2025-12-15 19:01:02 -05:00
David Woodhouse
69fa5020d2 Re-remove compilation_time_ from the app 2025-12-15 23:23:46 +00:00
David Woodhouse
f5592595bc Use fnv1a_hash_extend with config_hash and version for sensor baselines
Change sen5x, sgp30, and sgp4x components to use fnv1a_hash_extend()
starting with config_hash and ESPHOME_VERSION, then extending with the
sensor serial number. This replaces the previous use of fnv1_hash with
compilation_time.

This ensures baseline storage is invalidated on config or version
changes, not just on recompilation.
2025-12-15 23:22:23 +00:00
David Woodhouse
4a58ab6310 Restore switch to build_time_str in mqtt sw_version and version sensor 2025-12-15 23:14:25 +00:00
David Woodhouse
a5ff374540 Merge branch 'dev' of github.com:esphome/esphome into buildinfo 2025-12-15 23:12:40 +00:00
David Woodhouse
ffbbf37fc2 Revert "Revert API compilation_time to old locale-dependent format"
This reverts commit d2b5398fad.
2025-12-15 23:12:21 +00:00
Jonathan Swoboda
4c926cca60 Bump version to 2025.12.0b4 2025-12-15 18:09:42 -05:00
Pascal Vizeli
57634b612a [http_request] Fix infinite loop when server doesn't send Content-Length header (#12480)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 18:09:42 -05:00
Jonathan Swoboda
8dff7ee746 [esp32] Support all IDF component version operators in shorthand syntax (#12499)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-15 18:09:42 -05:00
Jonathan Swoboda
803bb742c9 [remote_base] Fix crash when ABBWelcome action has no data field (#12493)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-15 18:09:42 -05:00
J. Nick Koston
682acf81b2 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-15 15:35:46 -06:00
David Woodhouse
d2b5398fad Revert API compilation_time to old locale-dependent format
Keep the API DeviceInfo compilation_time field using the old
get_compilation_time_ref() format for backward compatibility.

The text sensor build_time_str continues to use the new ISO 8601 format.
2025-12-15 21:01:15 +00:00
David Woodhouse
839139df36 Add FNV-1a hash functions (#12502) 2025-12-15 20:23:54 +00:00
dependabot[bot]
24d7e9dd23 Bump tornado from 6.5.3 to 6.5.4 (#12508)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 20:08:16 +00:00
dependabot[bot]
1214bb6bad Bump aioesphomeapi from 43.2.1 to 43.3.0 (#12507)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 20:07:20 +00:00
J. Nick Koston
3ebbc1e769 overloads 2025-12-15 13:28:59 -06:00
J. Nick Koston
9578a02fe3 overloads 2025-12-15 13:27:51 -06:00
J. Nick Koston
68edb5c9a0 Merge branch 'noise_api_zero_copy' into integration 2025-12-15 13:19:52 -06:00
David Woodhouse
d911ae94fe Fix BUILD_TIME_STR_SIZE for ISO 8601 format
Increase buffer from 24 to 26 bytes to accommodate the ISO 8601 format
with timezone: "YYYY-MM-DD HH:MM:SS +ZZZZ" (25 chars + null terminator).

The old format "Dec 15 2025, 18:14:59" was 20 chars, but the new format
needs 25 chars. The 24-byte buffer was truncating the timezone to "+00"
instead of "+0000".
2025-12-15 18:53:56 +00:00
J. Nick Koston
487b66d92a Merge branch 'api_avoid_copies' into integration 2025-12-15 12:46:14 -06:00
J. Nick Koston
fc4869e2f9 Merge branch 'select_avoid_copies' into integration 2025-12-15 12:46:10 -06:00
J. Nick Koston
109e6c9719 Merge branch 'text_avoid_copies_const_ref' into integration 2025-12-15 12:46:06 -06:00
J. Nick Koston
3c42e534b3 Merge branch 'text_sensor_avoid_copies_const_ref' into integration 2025-12-15 12:46:02 -06:00
J. Nick Koston
b956c7798b [api] Avoid string copies in Home Assistant state subscription callbacks 2025-12-15 12:45:15 -06:00
J. Nick Koston
f8c0cd9ff6 [select] Eliminate string allocation in state callbacks 2025-12-15 12:39:52 -06:00
J. Nick Koston
e27c693051 [text] Avoid string copies in callbacks by passing const ref 2025-12-15 12:29:15 -06:00
J. Nick Koston
f6f1961e0e [text_sensor] Avoid string copies in callbacks by passing const ref 2025-12-15 12:24:34 -06:00
J. Nick Koston
ab0ca3006a Merge branch 'dev' into parition_callbacks 2025-12-15 12:20:54 -06:00
David Woodhouse
af1e0e6489 Merge branch 'dev' into buildinfo 2025-12-15 18:10:50 +00:00
Pascal Vizeli
260ffba2a5 [http_request] Fix infinite loop when server doesn't send Content-Length header (#12480)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 12:54:12 -05:00
J. Nick Koston
dab6b54e97 Merge branch 'fix-http-request-content-length' into integration 2025-12-15 11:48:06 -06:00
David Woodhouse
fd32139d89 Use new ISO format for compilation_time in API DeviceInfo
Change the API's DeviceInfo response to use the new ISO 8601 format
with timezone for compilation_time field by calling get_build_time_string()
instead of get_compilation_time_ref().

Update the placeholder build_info_data.h to match the new format.

Update integration test to expect the new format for compilation_time.
2025-12-15 17:44:35 +00:00
J. Nick Koston
245e7682c1 Merge remote-tracking branch 'swoboda1337/esp32-remove-arduino-core' into integration 2025-12-15 11:32:08 -06:00
Jonathan Swoboda
2e899dd010 [esp32] Support all IDF component version operators in shorthand syntax (#12499)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-15 12:07:02 -05:00
David Woodhouse
93bf1c8452 Merge branch 'dev' into buildinfo 2025-12-15 17:00:31 +00:00
David Woodhouse
0a63c50e1e Add test for build_info regeneration behaviour
Test verifies that:
- When source files change, build_info is regenerated with new timestamp
- When no files change, build_info is preserved with same timestamp

The test runs copy_src_tree() three times in the same environment:
1. Initial run creates build_info
2. Second run with no changes preserves the timestamp
3. Third run with changed source file regenerates with new timestamp
2025-12-15 16:59:51 +00:00
David Woodhouse
61cbd07e1d Add hmac-sha256 support (#12437)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-15 10:55:03 -06:00
David Woodhouse
87a125f303 Add test coverage for build_info.json change detection
Add tests to cover:
- Detection of config_hash changes in existing build_info.json
- Detection of esphome_version changes in existing build_info.json
- Handling of invalid/corrupted build_info.json files

These tests cover the exception handling and change detection logic
in copy_src_tree() that checks the existing build_info.json.
2025-12-15 16:45:15 +00:00
Jonathan Swoboda
e57e1f5094 Fix 2025-12-15 11:44:14 -05:00
David Woodhouse
09e9b58eb6 Change build_time_str format to ISO 8601 with timezone
Use YYYY-MM-DD HH:MM:SS +ZZZZ format instead of the locale-dependent
'%b %d %Y, %H:%M:%S' format. This provides:
- Unambiguous date format (YYYY-MM-DD)
- Timezone information
- Locale-independent formatting
- Better sortability and parseability

Example: "2025-12-15 16:30:27 +0000" instead of "Dec 15 2025, 16:30:27"

Tests validate the format using strptime with '%Y-%m-%d %H:%M:%S %z'.
2025-12-15 16:38:44 +00:00
David Woodhouse
c451fbd697 Postpone breaking changes for another PR
I think we need to put a little more thought into whether we really
want the build time in each of these, or whether it should be just
the config_hash (perhaps extended with version, and in some cases
the component's own serial number or other identifier).

So put the old compilation_time_ and its access methods back, so
this PR only adds the *new* fields. We can migrate users over and
then remove the compilation_time_ separately.
2025-12-15 16:26:15 +00:00
Jonathan Swoboda
853372a814 Fix 2025-12-15 10:48:48 -05:00
Jonathan Swoboda
db91ac9c75 Fix 2025-12-15 10:45:59 -05:00
David Woodhouse
d83fd263b0 Don't rebuild build_time_str
It's already in the JSON now
2025-12-15 15:44:12 +00:00
Jonathan Swoboda
415a1dd75a Merge branch 'dev' into esp32-remove-arduino-core 2025-12-15 10:43:14 -05:00
J. Nick Koston
ed4f90db8f Merge remote-tracking branch 'upstream/libretiny_prefs' into integration 2025-12-15 09:21:51 -06:00
J. Nick Koston
9dc06f04b1 Merge branch 'dev' into libretiny_prefs 2025-12-15 09:21:36 -06:00
Jonathan Swoboda
fe315a4cf8 Clean 2025-12-15 10:20:52 -05:00
Jonathan Swoboda
b9d59f5a00 [esp32] Remove Arduino-specific code from core.cpp, use initArduino
- Remove all USE_ARDUINO conditionals from core.cpp
- Add weak initArduino() stub that gets overridden when Arduino is present
- Call initArduino() in app_main() to initialize Arduino framework
- Remove CONFIG_AUTOSTART_ARDUINO (no longer needed)
- Fix deprecated hal/cpu_hal.h include, use esp_cpu.h instead
- Remove old ESP-IDF version conditionals (now IDF 5.x+ only)
- Clean up and sort includes alphabetically

This unifies the ESP32 startup code path - Arduino initialization is now
handled by calling initArduino() rather than using CONFIG_AUTOSTART_ARDUINO
which would start Arduino's own main loop.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-15 10:19:20 -05:00
J. Nick Koston
efc53ddd77 Merge remote-tracking branch 'upstream/esp32_prefs_uint32_str' into integration 2025-12-15 09:11:16 -06:00
J. Nick Koston
0bc81633bf at boundry 2025-12-15 09:06:33 -06:00
J. Nick Koston
cf20e0d772 libretiny prefs 2025-12-15 09:03:42 -06:00
David Woodhouse
bc5444cbe1 Merge branch 'dev' into buildinfo 2025-12-15 14:40:52 +00:00
Jonathan Swoboda
450962850a [remote_base] Fix crash when ABBWelcome action has no data field (#12493)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-15 09:29:51 -05:00
Pascal Vizeli
2dbaedbda2 Simplify condition check - remove redundant bufsize > 0 check
The bufsize > 0 check is redundant because the previous if statement
already handles all cases where bufsize <= 0, ensuring that by the time
we reach this condition, bufsize is always positive.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-15 12:17:47 +00:00
David Woodhouse
5eab42441e Fix dummy_main.cpp to match new pre_setup signature
Remove compilation timestamp argument as build time is now handled
through build_info_data.h instead of being passed to pre_setup().
2025-12-15 09:06:49 +00:00
David Woodhouse
0f22b23d9a clang-tidy CI fix
...but this is weird. Why are we copying into a local buffer
at all instead of just using the original string?
2025-12-15 17:11:04 +09:00
David Woodhouse
b27229d9b9 Merge branch 'dev' into buildinfo 2025-12-15 08:11:00 +00:00
J. Nick Koston
6a5dc6e7f5 Merge branch 'esp32_prefs_uint32_str' into integration 2025-12-14 22:29:28 -06:00
J. Nick Koston
ee5a3088b9 tweak 2025-12-14 22:17:45 -06:00
J. Nick Koston
6c166c904c [esp32] Replace std::string with char[12] for NVS preference keys 2025-12-14 22:06:42 -06:00
J. Nick Koston
995cf8be9c Merge remote-tracking branch 'upstream/dev' into integration 2025-12-14 21:34:22 -06:00
Jonathan Swoboda
6b088caf5d Merge branch 'beta' into dev 2025-12-14 19:18:10 -05:00
Jonathan Swoboda
3e6a65e7dc Merge pull request #12488 from esphome/bump-2025.12.0b3
2025.12.0b3
2025-12-14 19:17:58 -05:00
Jonathan Swoboda
3a101d8886 Bump version to 2025.12.0b3 2025-12-14 18:17:00 -05:00
J. Nick Koston
fa0f07bfe9 [wifi] Fix WiFi recovery after failed connection attempts (#12483) 2025-12-14 18:17:00 -05:00
mbohdal
fffa16e4d8 [ethernet] fix used pins validation in configuration of RMII pins (#12486) 2025-12-14 18:17:00 -05:00
guillempages
734710d22a [core] Use Arduino string macros only on ESP8266 (#12471) 2025-12-14 18:17:00 -05:00
J. Nick Koston
3a1be6822e [ota] Match client timeout to device timeout to prevent premature failures (#12484) 2025-12-14 18:17:00 -05:00
J. Nick Koston
c85b1b8609 [web_server_idf] Always enable LRU purge to prevent socket exhaustion (#12481) 2025-12-14 18:17:00 -05:00
J. Nick Koston
2e9ddd967c [wifi_signal] Skip publishing disconnected RSSI value (#12482) 2025-12-14 18:17:00 -05:00
J. Nick Koston
078afe9656 [dashboard] Add ESPHOME_TRUSTED_DOMAINS support to events WebSocket (#12479) 2025-12-14 18:17:00 -05:00
Jonathan Swoboda
46574fcbec [cc1101] Add packet mode support (#12474)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-14 18:17:00 -05:00
Jonathan Swoboda
359f45400f [core] Fix polling_component_schema and type consistency (#12478)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-14 18:16:59 -05:00
Clyde Stubbs
4da95ccd7e [packet_transport] Ensure retransmission at update intervals (#12472)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-14 18:16:59 -05:00
J. Nick Koston
c69d58273a [core] Fix CORE.raw_config not updated after package merge (#12456) 2025-12-14 18:16:59 -05:00
J. Nick Koston
ffce80f96c [wifi] Fix WiFi recovery after failed connection attempts (#12483) 2025-12-14 16:26:34 -06:00
mbohdal
fa5b14fad4 [ethernet] fix used pins validation in configuration of RMII pins (#12486) 2025-12-14 16:40:08 -05:00
J. Nick Koston
45f413de0e Merge branch 'wifi_timeout' into integration 2025-12-14 15:30:58 -06:00
J. Nick Koston
24e490ef26 Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 15:17:05 -06:00
J. Nick Koston
d9296a907d Revert "recovery"
This reverts commit 712da5c2ae.
2025-12-14 15:13:22 -06:00
J. Nick Koston
0a979cf26a Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 15:07:48 -06:00
J. Nick Koston
712da5c2ae recovery 2025-12-14 15:07:22 -06:00
J. Nick Koston
09573b5e5f Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 14:40:38 -06:00
J. Nick Koston
11c9e974ac tweak 2025-12-14 14:38:02 -06:00
J. Nick Koston
3786c84bbe Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 14:32:02 -06:00
J. Nick Koston
c8b48df8f2 tweak 2025-12-14 14:31:41 -06:00
J. Nick Koston
1de743d85e Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 14:25:41 -06:00
J. Nick Koston
f22396a097 fixes 2025-12-14 14:25:23 -06:00
J. Nick Koston
8cdee86334 Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 14:20:19 -06:00
J. Nick Koston
7801420eca one more failure more 2025-12-14 14:18:59 -06:00
guillempages
cee532a1e3 [core] Use Arduino string macros only on ESP8266 (#12471) 2025-12-15 07:15:19 +11:00
J. Nick Koston
8524b894d6 [ota] Match client timeout to device timeout to prevent premature failures (#12484) 2025-12-14 13:47:11 -06:00
J. Nick Koston
4928862622 esp32 has same bug 2025-12-14 13:42:59 -06:00
J. Nick Koston
6939b67e47 esp32 has same bug 2025-12-14 13:42:10 -06:00
J. Nick Koston
0b32add874 Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 13:38:05 -06:00
J. Nick Koston
616dae5bf9 fix missing s_sta_connecting = false; 2025-12-14 13:37:48 -06:00
J. Nick Koston
3a5e708c13 [web_server_idf] Always enable LRU purge to prevent socket exhaustion (#12481) 2025-12-14 13:31:19 -06:00
J. Nick Koston
96e418a8ca [wifi_signal] Skip publishing disconnected RSSI value (#12482) 2025-12-14 13:31:07 -06:00
J. Nick Koston
780a407b10 [dashboard] Add ESPHOME_TRUSTED_DOMAINS support to events WebSocket (#12479) 2025-12-14 13:30:55 -06:00
J. Nick Koston
bd539fa34f Merge branch 'wifi_fail_too_quickly_fix' into wifi_timeout 2025-12-14 13:27:09 -06:00
J. Nick Koston
8ce2cc564f make sure we are disconnected on timeout 2025-12-14 13:26:54 -06:00
J. Nick Koston
2696297428 Merge branch 'ota_timeout_fix' into wifi_timeout 2025-12-14 12:45:57 -06:00
J. Nick Koston
7eff3217aa [ota] Match client timeout to device timeout to prevent premature failures 2025-12-14 12:34:54 -06:00
Jonathan Swoboda
cfc0d8bdfc [cc1101] Add packet mode support (#12474)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-14 13:22:55 -05:00
J. Nick Koston
af04eaaba0 [wifi] Fix premature connection timeout on LibreTiny/Beken 2025-12-14 12:19:58 -06:00
Jonathan Swoboda
786d7266f5 [core] Fix polling_component_schema and type consistency (#12478)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-14 12:47:52 -05:00
Clyde Stubbs
ede64a9f47 [packet_transport] Ensure retransmission at update intervals (#12472)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-14 12:47:15 -05:00
Pascal Vizeli
c4d9ed7b70 [http_request] Fix infinite loop on read error in update component
The update component had the same infinite loop issue as the OTA component
when network read errors occurred. If container->read() returned an error
(negative value), it would be added to read_index and the loop would continue
indefinitely since get_bytes_read() would never reach content_length.

This fix breaks out of the read loop on any read error (read_bytes <= 0),
preventing watchdog resets and infinite loops during manifest downloads.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-14 17:06:53 +00:00
Pascal Vizeli
f20f3e0525 [http_request] Fix infinite loop when server doesn't send Content-Length header
This commit fixes an issue where the http_request component would enter
an infinite loop when an HTTP server doesn't send a Content-Length header
or closes the connection prematurely.

The read loop was assuming read operations would always return data, but:
1. When the stream pointer becomes invalid (connection closed), read() returns -1
2. When no more data is available, read() returns 0

Without these checks, the loop would continue indefinitely, causing:
- "Stream pointer vanished!" errors (Arduino platform)
- CPU spinning on zero-byte reads
- Watchdog timeouts

The fix adds validation checks to break out of read loops when
read() returns <= 0 (covering both error and end-of-stream conditions).

This is applied to:
- Response capture loops (http_request.h)
- OTA firmware download loop (ota_http_request.cpp)
- MD5 verification download loop (ota_http_request.cpp)

This allows graceful handling of non-compliant HTTP servers while
maintaining compatibility with properly formatted responses.

Fixes esphome/issues#6682

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-14 16:18:37 +00:00
J. Nick Koston
2bfa1aacd8 Merge branch 'skip_wifi_rssi_publish_when_discoed' into integration 2025-12-14 09:55:42 -06:00
J. Nick Koston
1b551b0897 [wifi_signal] Skip publishing disconnected RSSI value 2025-12-14 09:55:09 -06:00
J. Nick Koston
7e1bd289b3 Merge branch 'fix-polling-component-schema' into integration 2025-12-14 09:38:15 -06:00
J. Nick Koston
cf373edd81 Merge branch 'lwip_raw_tcp_impl_getpeername' into integration 2025-12-14 09:38:07 -06:00
J. Nick Koston
0d7fbb79b3 Merge branch 'events_trusted_domains' into integration 2025-12-14 09:38:01 -06:00
J. Nick Koston
c87771184e Merge branch 'fix-epaper-spi-update-interval-never' into integration 2025-12-14 09:37:56 -06:00
J. Nick Koston
1185abadc1 Merge branch 'always_lru_enable_idf_web_server' into integration 2025-12-14 09:37:49 -06:00
J. Nick Koston
6f6c65509d [web_server_idf] Always enable LRU purge to prevent socket exhaustion 2025-12-14 09:37:11 -06:00
J. Nick Koston
f50ffb2b92 cover 2025-12-14 09:09:24 -06:00
J. Nick Koston
4892bfb6e4 [dashboard] Add ESPHOME_TRUSTED_DOMAINS support to events WebSocket 2025-12-14 09:00:27 -06:00
Jonathan Swoboda
586e82bfa5 [core] Fix polling_component_schema and use SCHEDULER_DONT_RUN constant
- Fix polling_component_schema to use update_interval validator when
  default_update_interval is None (was using None as validator)
- Replace hardcoded 4294967295 with SCHEDULER_DONT_RUN constant in
  update_interval function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-14 09:41:56 -05:00
J. Nick Koston
512a7df007 [socket] Fix getpeername() returning local address instead of remote in LWIP raw TCP 2025-12-13 22:49:05 -06:00
J. Nick Koston
0e60aefdec Merge remote-tracking branch 'upstream/dev' into integration 2025-12-13 22:15:41 -06:00
David Woodhouse
1ebfd5b4eb Update test for new get_build_info behaviour
get_build_info() now always returns current time instead of preserving
the existing build_time. The timestamp preservation logic is now handled
in copy_src_tree() based on sources_changed flag.
2025-12-14 09:07:44 +09:00
David Woodhouse
4bde4dbdc8 Fix KeyError when build_info_data.h not in source_files_copy
Use pop(t, None) instead of pop(t) to handle case where
build_info_data.h might not be in the component resources.
2025-12-14 08:55:25 +09:00
David Woodhouse
841d9664d3 Fix build system to relink when source files change
- Make copy_file_if_changed() return bool indicating if file was copied
- Track sources_changed in copy_src_tree() to detect when source files change
- Only update build_info timestamp when sources/config/version change
- Exclude generated files (build_info_data.h) from sources_changed tracking
- Add build_info_data.h to ignore_targets to prevent copying from resources
- Track changes to generated headers (defines.h, esphome.h, version.h)
- Check for config_hash or version changes to trigger rebuild
- Pretty-print build_info.json with indentation and trailing newline
- Update mock_copy_file_if_changed to return True by default

This fixes the issue where changing a source file would recompile the .o
file but not relink the final program executable.
2025-12-14 08:51:59 +09:00
J. Nick Koston
16107ad788 bot comments 2025-12-13 10:34:09 -06:00
J. Nick Koston
8299656375 Update esphome/components/sgp4x/sgp4x.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:32:39 -06:00
J. Nick Koston
184ac0c1e7 Update esphome/components/sgp30/sgp30.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:32:33 -06:00
J. Nick Koston
6198618044 Update esphome/components/sen5x/sen5x.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-13 10:32:25 -06:00
J. Nick Koston
ba0f559856 better cover 2025-12-13 10:10:24 -06:00
J. Nick Koston
0539c5d4d2 cover 2025-12-13 10:02:54 -06:00
J. Nick Koston
bb35ed5f53 tidy 2025-12-13 09:54:07 -06:00
J. Nick Koston
de500450d9 coverage for hash order change 2025-12-13 09:45:17 -06:00
J. Nick Koston
b4a54f2df1 sort so config hash does not change 2025-12-13 09:40:26 -06:00
J. Nick Koston
cf8708b888 writer coverage 2025-12-13 09:28:52 -06:00
J. Nick Koston
15494c0d28 Merge branch 'buildinfo' of https://github.com/dwmw2/esphome into buildinfo 2025-12-13 09:25:32 -06:00
J. Nick Koston
4bf810fcd1 a bit of future proofing to avoid many dumps if it gets reused 2025-12-13 09:25:21 -06:00
J. Nick Koston
959a2e8ddd Merge branch 'dev' into buildinfo 2025-12-13 09:22:09 -06:00
J. Nick Koston
4b937b5228 some coverage 2025-12-13 09:21:53 -06:00
J. Nick Koston
0c7c1d3c57 check version as well 2025-12-13 09:13:28 -06:00
J. Nick Koston
d31be6ed9d check version as well 2025-12-13 09:10:40 -06:00
J. Nick Koston
dce5face4e simplify more 2025-12-13 09:01:39 -06:00
J. Nick Koston
6d91f1cd77 tests 2025-12-13 08:56:12 -06:00
J. Nick Koston
67937aeda4 tests 2025-12-13 08:55:26 -06:00
J. Nick Koston
1543f56f70 simplify approach 2025-12-13 08:53:51 -06:00
J. Nick Koston
e0ce66e011 [core] Fix CORE.raw_config not updated after package merge (#12456) 2025-12-13 07:38:31 -06:00
J. Nick Koston
2fc3ef61ea adjust 2025-12-12 21:42:07 -06:00
J. Nick Koston
145475e461 tidy 2025-12-12 21:31:43 -06:00
J. Nick Koston
b1fb705864 [esp8266] Avoid heap allocation in preferences save/load 2025-12-12 21:28:21 -06:00
David Woodhouse
15d2d3ff96 Update esphome/core/buildinfo.cpp
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-13 12:13:01 +09:00
David Woodhouse
d016302e36 Convert buildinfo.h to C++17 nested namespace syntax 2025-12-13 12:05:05 +09:00
David Woodhouse
fe798dff81 Update esphome/writer.py
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-13 12:03:43 +09:00
J. Nick Koston
75b8279361 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-12 21:03:28 -06:00
David Woodhouse
17db6bee3c Update esphome/__main__.py
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-13 12:03:12 +09:00
David Woodhouse
e7c8892d6d Merge branch 'dev' into buildinfo 2025-12-13 12:00:08 +09:00
David Woodhouse
12e0d6bdcc Create and use buildinfo.json instead of parsing linker script
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-13 11:57:04 +09:00
David Woodhouse
d8c52297ab Add type hints to _encode_string_symbols function 2025-12-13 11:54:24 +09:00
David Woodhouse
6fce0a6104 Add host platform support to MD5 component (#12458) 2025-12-13 02:50:34 +00:00
David Woodhouse
eda0a391ca Extract duplicate string encoding logic into helper function 2025-12-13 11:26:37 +09:00
David Woodhouse
94fefb1405 Limit OSError exception catch to file open operation only 2025-12-13 11:26:37 +09:00
David Woodhouse
da96ffb923 Convert buildinfo to C++17 nested namespace syntax 2025-12-13 11:26:37 +09:00
David Woodhouse
d7451257a5 Merge branch 'dev' into buildinfo 2025-12-13 11:20:39 +09:00
J. Nick Koston
b10a87c1b0 Merge branch 'factory_reset_waste' into integration 2025-12-12 20:14:42 -06:00
J. Nick Koston
f2505ce453 tidy 2025-12-12 20:14:31 -06:00
David Woodhouse
32797fbe00 Generate buildinfo.ld directly, use fnv1a_32bit_hash()
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-13 11:11:59 +09:00
J. Nick Koston
ec7143d835 Merge branch 'factory_reset_waste' into integration 2025-12-12 20:09:19 -06:00
J. Nick Koston
d77f9c96b9 [factory_reset] Optimize memory by storing interval as uint16_t seconds 2025-12-12 20:08:00 -06:00
J. Nick Koston
4329794924 Merge branch 'ota_align_password' into integration 2025-12-12 19:39:06 -06:00
J. Nick Koston
99b0b974ad [esphome] Improve OTA field alignment to save 4 bytes on 32-bit 2025-12-12 19:38:44 -06:00
J. Nick Koston
9dafafa07c Merge branch 'memory_api' into integration 2025-12-12 19:25:14 -06:00
J. Nick Koston
200cd8cace Merge branch 'str_helpers' into integration 2025-12-12 19:25:09 -06:00
Jonathan Swoboda
b8c00e6452 Merge branch 'dev' into fix-epaper-spi-update-interval-never 2025-12-12 17:25:02 -05:00
Jonathan Swoboda
1d081fd510 [epaper_spi] Fix update_interval: never validation error
- Add full_display_schema() function to display component to allow
  configurable default update_interval
- Fix epaper_spi to use 60s default update_interval instead of 1s
- Fix minimum update_interval validation to allow "never" value
- Keep FULL_DISPLAY_SCHEMA constant for backward compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-12 16:59:50 -05:00
David Woodhouse
a86095d865 Merge branch 'dev' into buildinfo 2025-12-13 06:24:20 +09:00
David Woodhouse
e728e8ed0c Apply clang-format suggestions to buildinfo.cpp
- Use <cstdint> instead of <stdint.h>
- Rename config_hash_struct to ConfigHashStruct for naming consistency
2025-12-13 06:17:28 +09:00
J. Nick Koston
80fda97c60 [core] Refactor str_snake_case and str_sanitize to use constexpr helpers 2025-12-12 13:13:07 -06:00
David Woodhouse
7d3afe5de0 Merge branch 'dev' into buildinfo 2025-12-13 01:45:43 +09:00
David Woodhouse
b5703523f9 nolint for the macros that have to be macros 2025-12-13 01:44:25 +09:00
David Woodhouse
07d784b0bf Pass config hash and build date in as strings via linker symbols
This saves the RAM we were using to build it at runtime.
2025-12-13 01:39:29 +09:00
David Woodhouse
25805da008 Merge branch 'dev' into buildinfo 2025-12-12 09:54:47 +09:00
David Woodhouse
ccebe613e2 Optimize buildinfo RAM usage on 32-bit platforms
Use direct symbol access on 32-bit platforms to avoid 8 bytes of RAM
overhead. Keep indirection workaround only on 64-bit platforms where
PC-relative relocations cause linking issues.
2025-12-12 01:51:12 +09:00
David Woodhouse
295b317809 Optimize get_build_time_string to avoid repeated formatting
Apply same concurrency fix as get_config_hash to prevent race
conditions when multiple threads access the function.
2025-12-11 22:54:19 +09:00
David Woodhouse
58fddeb74f Optimize get_config_hash to avoid repeated snprintf calls
Check if hash string is already formatted before calling snprintf,
since static variables in BSS are zero-initialized.
2025-12-11 22:53:03 +09:00
David Woodhouse
54ed6154eb Expand non-const comment 2025-12-11 22:49:32 +09:00
David Woodhouse
0b1ea8f2ca Add nolint for non-const buildinfo variables
Variables must remain non-const to prevent compiler optimization
that would bypass the indirection workaround for PC-relative
relocation issues.
2025-12-11 22:48:02 +09:00
David Woodhouse
478f12f75e Remove const from buildinfo static variables
The const qualifier allows compiler optimization that bypasses our
indirection workaround, causing PC-relative relocations that fail
on some platforms. Keep variables non-const to force data section
relocations.
2025-12-11 22:46:09 +09:00
David Woodhouse
cfdb5a82e2 Replace __DATE__/__TIME__ with buildinfo functions
- Add get_build_time_string() function to format build time consistently
- Replace __DATE__ ", " __TIME__ in App.pre_setup() with buildinfo call
- Eliminates dependency on compiler-provided date/time macros
- Ensures consistent build time across all build information displays
2025-12-11 22:24:30 +09:00
David Woodhouse
edc320fef8 Add buildinfo system with config hash and build time
To allow for more selective managed updates, allow the config hash and
build time to be built into the image itself.

To avoid triggering unneeded rebuilds, do this through a linker script
so that the new config hash and timestamp are included only if the
firmware is actually relinked.

Add a _check_and_emit_buildinfo() step after building, which prints
the information after the firmware was rebuilt. A subsequent commit
will emit a manifest here, or at least the HMAC-MD5 for signing OTA
updates using the hmac_key configured in this image.
2025-12-11 22:24:30 +09:00
J. Nick Koston
2d3ccab0b3 [api] Add zero-copy support for noise encryption key requests 2025-12-10 12:48:04 +01:00
J. Nick Koston
fdd560b165 [fan] Add zero-copy support for API preset mode commands 2025-12-10 12:40:35 +01:00
J. Nick Koston
6b810b340a fix 2025-12-10 12:38:04 +01:00
J. Nick Koston
3cd14fa39d [climate] Add zero-copy support for API custom fan mode and preset commands 2025-12-10 10:45:07 +01:00
1198 changed files with 45221 additions and 18004 deletions

View File

@@ -293,6 +293,12 @@ This document provides essential context for AI models interacting with this pro
* **Configuration Design:** Aim for simplicity with sensible defaults, while allowing for advanced customization. * **Configuration Design:** Aim for simplicity with sensible defaults, while allowing for advanced customization.
* **Embedded Systems Optimization:** ESPHome targets resource-constrained microcontrollers. Be mindful of flash size and RAM usage. * **Embedded Systems Optimization:** ESPHome targets resource-constrained microcontrollers. Be mindful of flash size and RAM usage.
**Why Heap Allocation Matters:**
ESP devices run for months with small heaps shared between Wi-Fi, BLE, LWIP, and application code. Over time, repeated allocations of different sizes fragment the heap. Failures happen when the largest contiguous block shrinks, even if total free heap is still large. We have seen field crashes caused by this.
**Heap allocation after `setup()` should be avoided unless absolutely unavoidable.** Every allocation/deallocation cycle contributes to fragmentation. ESPHome treats runtime heap allocation as a long-term reliability bug, not a performance issue. Helpers that hide allocation (`std::string`, `std::to_string`, string-returning helpers) are being deprecated and replaced with buffer and view based APIs.
**STL Container Guidelines:** **STL Container Guidelines:**
ESPHome runs on embedded systems with limited resources. Choose containers carefully: ESPHome runs on embedded systems with limited resources. Choose containers carefully:
@@ -322,15 +328,15 @@ This document provides essential context for AI models interacting with this pro
std::array<uint8_t, 256> buffer; std::array<uint8_t, 256> buffer;
``` ```
2. **Compile-time-known fixed sizes with vector-like API:** Use `StaticVector` from `esphome/core/helpers.h` for fixed-size stack allocation with `push_back()` interface. 2. **Compile-time-known fixed sizes with vector-like API:** Use `StaticVector` from `esphome/core/helpers.h` for compile-time fixed size with `push_back()` interface (no dynamic allocation).
```cpp ```cpp
// Bad - generates STL realloc code (_M_realloc_insert) // Bad - generates STL realloc code (_M_realloc_insert)
std::vector<ServiceRecord> services; std::vector<ServiceRecord> services;
services.reserve(5); // Still includes reallocation machinery services.reserve(5); // Still includes reallocation machinery
// Good - compile-time fixed size, stack allocated, no reallocation machinery // Good - compile-time fixed size, no dynamic allocation
StaticVector<ServiceRecord, MAX_SERVICES> services; // Allocates all MAX_SERVICES on stack StaticVector<ServiceRecord, MAX_SERVICES> services;
services.push_back(record1); // Tracks count but all slots allocated services.push_back(record1);
``` ```
Use `cg.add_define("MAX_SERVICES", count)` to set the size from Python configuration. Use `cg.add_define("MAX_SERVICES", count)` to set the size from Python configuration.
Like `std::array` but with vector-like API (`push_back()`, `size()`) and no STL reallocation code. Like `std::array` but with vector-like API (`push_back()`, `size()`) and no STL reallocation code.
@@ -372,22 +378,21 @@ This document provides essential context for AI models interacting with this pro
``` ```
Linear search on small datasets (1-16 elements) is often faster than hashing/tree overhead, but this depends on lookup frequency and access patterns. For frequent lookups in hot code paths, the O(1) vs O(n) complexity difference may still matter even for small datasets. `std::vector` with simple structs is usually fine—it's the heavy containers (`map`, `set`, `unordered_map`) that should be avoided for small datasets unless profiling shows otherwise. Linear search on small datasets (1-16 elements) is often faster than hashing/tree overhead, but this depends on lookup frequency and access patterns. For frequent lookups in hot code paths, the O(1) vs O(n) complexity difference may still matter even for small datasets. `std::vector` with simple structs is usually fine—it's the heavy containers (`map`, `set`, `unordered_map`) that should be avoided for small datasets unless profiling shows otherwise.
5. **Detection:** Look for these patterns in compiler output: 5. **Avoid `std::deque`:** It allocates in 512-byte blocks regardless of element size, guaranteeing at least 512 bytes of RAM usage immediately. This is a major source of crashes on memory-constrained devices.
6. **Detection:** Look for these patterns in compiler output:
- Large code sections with STL symbols (vector, map, set) - Large code sections with STL symbols (vector, map, set)
- `alloc`, `realloc`, `dealloc` in symbol names - `alloc`, `realloc`, `dealloc` in symbol names
- `_M_realloc_insert`, `_M_default_append` (vector reallocation) - `_M_realloc_insert`, `_M_default_append` (vector reallocation)
- Red-black tree code (`rb_tree`, `_Rb_tree`) - Red-black tree code (`rb_tree`, `_Rb_tree`)
- Hash table infrastructure (`unordered_map`, `hash`) - Hash table infrastructure (`unordered_map`, `hash`)
**When to optimize:** **Prioritize optimization effort for:**
- Core components (API, network, logger) - Core components (API, network, logger)
- Widely-used components (mdns, wifi, ble) - Widely-used components (mdns, wifi, ble)
- Components causing flash size complaints - Components causing flash size complaints
**When not to optimize:** Note: Avoiding heap allocation after `setup()` is always required regardless of component type. The prioritization above is about the effort spent on container optimization (e.g., migrating from `std::vector` to `StaticVector`).
- Single-use niche components
- Code where readability matters more than bytes
- Already using appropriate containers
* **State Management:** Use `CORE.data` for component state that needs to persist during configuration generation. Avoid module-level mutable globals. * **State Management:** Use `CORE.data` for component state that needs to persist during configuration generation. Avoid module-level mutable globals.

View File

@@ -1 +1 @@
766420905c06eeb6c5f360f68fd965e5ddd9c4a5db6b823263d3ad3accb64a07 d272a88e8ca28ae9340a9a03295a566432a52cb696501908f57764475bf7ca65

View File

@@ -0,0 +1,96 @@
---
name: pr-workflow
description: Create pull requests for esphome. Use when creating PRs, submitting changes, or preparing contributions.
allowed-tools: Read, Bash, Glob, Grep
---
# ESPHome PR Workflow
When creating a pull request for esphome, follow these steps:
## 1. Create Branch from Upstream
Always base your branch on **upstream** (not origin/fork) to ensure you have the latest code:
```bash
git fetch upstream
git checkout -b <branch-name> upstream/dev
```
## 2. Read the PR Template
Before creating a PR, read `.github/PULL_REQUEST_TEMPLATE.md` to understand required fields.
## 3. Create the PR
Use `gh pr create` with the **full template** filled in. Never skip or abbreviate sections.
Required fields:
- **What does this implement/fix?**: Brief description of changes
- **Types of changes**: Check ONE appropriate box (Bugfix, New feature, Breaking change, etc.)
- **Related issue**: Use `fixes <link>` syntax if applicable
- **Pull request in esphome-docs**: Link if docs are needed
- **Test Environment**: Check platforms you tested on
- **Example config.yaml**: Include working example YAML
- **Checklist**: Verify code is tested and tests added
## 4. Example PR Body
```markdown
# What does this implement/fix?
<describe your changes here>
## Types of changes
- [ ] Bugfix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Developer breaking change (an API change that could break external components)
- [ ] Code quality improvements to existing code or addition of tests
- [ ] Other
**Related issue or feature (if applicable):**
- fixes https://github.com/esphome/esphome/issues/XXX
**Pull request in [esphome-docs](https://github.com/esphome/esphome-docs) with documentation (if applicable):**
- esphome/esphome-docs#XXX
## Test Environment
- [x] ESP32
- [x] ESP32 IDF
- [ ] ESP8266
- [ ] RP2040
- [ ] BK72xx
- [ ] RTL87xx
- [ ] LN882x
- [ ] nRF52840
## Example entry for `config.yaml`:
```yaml
# Example config.yaml
component_name:
id: my_component
option: value
```
## Checklist:
- [x] The code change is tested and works locally.
- [x] Tests have been added to verify that the new code works (under `tests/` folder).
If user exposed functionality or configuration variables are added/changed:
- [ ] Documentation added/updated in [esphome-docs](https://github.com/esphome/esphome-docs).
```
## 5. Push and Create PR
```bash
git push -u origin <branch-name>
gh pr create --repo esphome/esphome --base dev --title "[component] Brief description"
```
Title should be prefixed with the component name in brackets, e.g. `[safe_mode] Add feature`.

View File

@@ -27,6 +27,7 @@
- [ ] RP2040 - [ ] RP2040
- [ ] BK72xx - [ ] BK72xx
- [ ] RTL87xx - [ ] RTL87xx
- [ ] LN882x
- [ ] nRF52840 - [ ] nRF52840
## Example entry for `config.yaml`: ## Example entry for `config.yaml`:

View File

@@ -22,7 +22,7 @@ runs:
python-version: ${{ inputs.python-version }} python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment - name: Restore Python virtual environment
id: cache-venv id: cache-venv
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: venv path: venv
# yamllint disable-line rule:line-length # yamllint disable-line rule:line-length

View File

@@ -49,7 +49,7 @@ jobs:
with: with:
python-version: "3.11" python-version: "3.11"
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Set TAG - name: Set TAG
run: | run: |

View File

@@ -47,7 +47,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment - name: Restore Python virtual environment
id: cache-venv id: cache-venv
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: venv path: venv
# yamllint disable-line rule:line-length # yamllint disable-line rule:line-length
@@ -157,7 +157,7 @@ jobs:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
- name: Save Python virtual environment cache - name: Save Python virtual environment cache
if: github.ref == 'refs/heads/dev' if: github.ref == 'refs/heads/dev'
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/save@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: venv path: venv
key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }} key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
@@ -193,7 +193,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }} cache-key: ${{ needs.common.outputs.cache-key }}
- name: Restore components graph cache - name: Restore components graph cache
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: .temp/components_graph.json path: .temp/components_graph.json
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }} key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
@@ -223,7 +223,7 @@ jobs:
echo "component-test-batches=$(echo "$output" | jq -c '.component_test_batches')" >> $GITHUB_OUTPUT echo "component-test-batches=$(echo "$output" | jq -c '.component_test_batches')" >> $GITHUB_OUTPUT
- name: Save components graph cache - name: Save components graph cache
if: github.ref == 'refs/heads/dev' if: github.ref == 'refs/heads/dev'
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/save@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: .temp/components_graph.json path: .temp/components_graph.json
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }} key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
@@ -245,7 +245,7 @@ jobs:
python-version: "3.13" python-version: "3.13"
- name: Restore Python virtual environment - name: Restore Python virtual environment
id: cache-venv id: cache-venv
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: venv path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }} key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
@@ -334,14 +334,14 @@ jobs:
- name: Cache platformio - name: Cache platformio
if: github.ref == 'refs/heads/dev' if: github.ref == 'refs/heads/dev'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
- name: Cache platformio - name: Cache platformio
if: github.ref != 'refs/heads/dev' if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }} key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
@@ -413,14 +413,14 @@ jobs:
- name: Cache platformio - name: Cache platformio
if: github.ref == 'refs/heads/dev' if: github.ref == 'refs/heads/dev'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio - name: Cache platformio
if: github.ref != 'refs/heads/dev' if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
@@ -502,14 +502,14 @@ jobs:
- name: Cache platformio - name: Cache platformio
if: github.ref == 'refs/heads/dev' if: github.ref == 'refs/heads/dev'
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio - name: Cache platformio
if: github.ref != 'refs/heads/dev' if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }} key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
@@ -735,7 +735,7 @@ jobs:
- name: Restore cached memory analysis - name: Restore cached memory analysis
id: cache-memory-analysis id: cache-memory-analysis
if: steps.check-script.outputs.skip != 'true' if: steps.check-script.outputs.skip != 'true'
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: memory-analysis-target.json path: memory-analysis-target.json
key: ${{ steps.cache-key.outputs.cache-key }} key: ${{ steps.cache-key.outputs.cache-key }}
@@ -759,7 +759,7 @@ jobs:
- name: Cache platformio - name: Cache platformio
if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true'
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }} key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
@@ -800,7 +800,7 @@ jobs:
- name: Save memory analysis to cache - name: Save memory analysis to cache
if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success' if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success'
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/save@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: memory-analysis-target.json path: memory-analysis-target.json
key: ${{ steps.cache-key.outputs.cache-key }} key: ${{ steps.cache-key.outputs.cache-key }}
@@ -847,7 +847,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }} python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }} cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio - name: Cache platformio
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1 uses: actions/cache/restore@8b402f58fbc84540c8b491a91e594a4576fec3d7 # v5.0.2
with: with:
path: ~/.platformio path: ~/.platformio
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }} key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}

View File

@@ -58,7 +58,7 @@ jobs:
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8 uses: github/codeql-action/init@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }} build-mode: ${{ matrix.build-mode }}
@@ -86,6 +86,6 @@ jobs:
exit 1 exit 1
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8 uses: github/codeql-action/analyze@cdefb33c0f6224e58673d9004f47f7cb3e328b89 # v4.31.10
with: with:
category: "/language:${{matrix.language}}" category: "/language:${{matrix.language}}"

View File

@@ -99,7 +99,7 @@ jobs:
python-version: "3.11" python-version: "3.11"
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log in to docker hub - name: Log in to docker hub
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0 uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
@@ -178,7 +178,7 @@ jobs:
merge-multiple: true merge-multiple: true
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
- name: Log in to docker hub - name: Log in to docker hub
if: matrix.registry == 'dockerhub' if: matrix.registry == 'dockerhub'

4
.gitignore vendored
View File

@@ -91,6 +91,10 @@ venv-*/
# mypy # mypy
.mypy_cache/ .mypy_cache/
# nix
/default.nix
/shell.nix
.pioenvs .pioenvs
.piolibdeps .piolibdeps
.pio .pio

View File

@@ -11,7 +11,7 @@ ci:
repos: repos:
- repo: https://github.com/astral-sh/ruff-pre-commit - repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version. # Ruff version.
rev: v0.14.9 rev: v0.14.13
hooks: hooks:
# Run the linter. # Run the linter.
- id: ruff - id: ruff

View File

@@ -42,6 +42,7 @@ esphome/components/animation/* @syndlex
esphome/components/anova/* @buxtronix esphome/components/anova/* @buxtronix
esphome/components/apds9306/* @aodrenah esphome/components/apds9306/* @aodrenah
esphome/components/api/* @esphome/core esphome/components/api/* @esphome/core
esphome/components/aqi/* @freekode @jasstrong @ximex
esphome/components/as5600/* @ammmze esphome/components/as5600/* @ammmze
esphome/components/as5600/sensor/* @ammmze esphome/components/as5600/sensor/* @ammmze
esphome/components/as7341/* @mrgnr esphome/components/as7341/* @mrgnr
@@ -90,6 +91,7 @@ esphome/components/bmp3xx_spi/* @latonita
esphome/components/bmp581/* @kahrendt esphome/components/bmp581/* @kahrendt
esphome/components/bp1658cj/* @Cossid esphome/components/bp1658cj/* @Cossid
esphome/components/bp5758d/* @Cossid esphome/components/bp5758d/* @Cossid
esphome/components/bthome_mithermometer/* @nagyrobi
esphome/components/button/* @esphome/core esphome/components/button/* @esphome/core
esphome/components/bytebuffer/* @clydebarrow esphome/components/bytebuffer/* @clydebarrow
esphome/components/camera/* @bdraco @DT-art1 esphome/components/camera/* @bdraco @DT-art1
@@ -133,7 +135,7 @@ esphome/components/display_menu_base/* @numo68
esphome/components/dps310/* @kbx81 esphome/components/dps310/* @kbx81
esphome/components/ds1307/* @badbadc0ffee esphome/components/ds1307/* @badbadc0ffee
esphome/components/ds2484/* @mrk-its esphome/components/ds2484/* @mrk-its
esphome/components/dsmr/* @glmnet @zuidwijk esphome/components/dsmr/* @glmnet @PolarGoose @zuidwijk
esphome/components/duty_time/* @dudanov esphome/components/duty_time/* @dudanov
esphome/components/ee895/* @Stock-M esphome/components/ee895/* @Stock-M
esphome/components/ektf2232/touchscreen/* @jesserockz esphome/components/ektf2232/touchscreen/* @jesserockz
@@ -215,6 +217,7 @@ esphome/components/hlk_fm22x/* @OnFreund
esphome/components/hlw8032/* @rici4kubicek esphome/components/hlw8032/* @rici4kubicek
esphome/components/hm3301/* @freekode esphome/components/hm3301/* @freekode
esphome/components/hmac_md5/* @dwmw2 esphome/components/hmac_md5/* @dwmw2
esphome/components/hmac_sha256/* @dwmw2
esphome/components/homeassistant/* @esphome/core @OttoWinter esphome/components/homeassistant/* @esphome/core @OttoWinter
esphome/components/homeassistant/number/* @landonr esphome/components/homeassistant/number/* @landonr
esphome/components/homeassistant/switch/* @Links2004 esphome/components/homeassistant/switch/* @Links2004
@@ -246,11 +249,13 @@ esphome/components/ina260/* @mreditor97
esphome/components/ina2xx_base/* @latonita esphome/components/ina2xx_base/* @latonita
esphome/components/ina2xx_i2c/* @latonita esphome/components/ina2xx_i2c/* @latonita
esphome/components/ina2xx_spi/* @latonita esphome/components/ina2xx_spi/* @latonita
esphome/components/infrared/* @kbx81
esphome/components/inkbird_ibsth1_mini/* @fkirill esphome/components/inkbird_ibsth1_mini/* @fkirill
esphome/components/inkplate/* @jesserockz @JosipKuci esphome/components/inkplate/* @jesserockz @JosipKuci
esphome/components/integration/* @OttoWinter esphome/components/integration/* @OttoWinter
esphome/components/internal_temperature/* @Mat931 esphome/components/internal_temperature/* @Mat931
esphome/components/interval/* @esphome/core esphome/components/interval/* @esphome/core
esphome/components/ir_rf_proxy/* @kbx81
esphome/components/jsn_sr04t/* @Mafus1 esphome/components/jsn_sr04t/* @Mafus1
esphome/components/json/* @esphome/core esphome/components/json/* @esphome/core
esphome/components/kamstrup_kmp/* @cfeenstra1024 esphome/components/kamstrup_kmp/* @cfeenstra1024
@@ -392,6 +397,7 @@ esphome/components/radon_eye_rd200/* @jeffeb3
esphome/components/rc522/* @glmnet esphome/components/rc522/* @glmnet
esphome/components/rc522_i2c/* @glmnet esphome/components/rc522_i2c/* @glmnet
esphome/components/rc522_spi/* @glmnet esphome/components/rc522_spi/* @glmnet
esphome/components/rd03d/* @jasstrong
esphome/components/resampler/speaker/* @kahrendt esphome/components/resampler/speaker/* @kahrendt
esphome/components/restart/* @esphome/core esphome/components/restart/* @esphome/core
esphome/components/rf_bridge/* @jesserockz esphome/components/rf_bridge/* @jesserockz
@@ -517,6 +523,7 @@ esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core esphome/components/uart/* @esphome/core
esphome/components/uart/button/* @ssieb esphome/components/uart/button/* @ssieb
esphome/components/uart/event/* @eoasmxd
esphome/components/uart/packet_transport/* @clydebarrow esphome/components/uart/packet_transport/* @clydebarrow
esphome/components/udp/* @clydebarrow esphome/components/udp/* @clydebarrow
esphome/components/ufire_ec/* @pvizeli esphome/components/ufire_ec/* @pvizeli
@@ -535,6 +542,7 @@ esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz @kahrendt esphome/components/voice_assistant/* @jesserockz @kahrendt
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54 esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher esphome/components/watchdog/* @oarcher
esphome/components/water_heater/* @dhoeben
esphome/components/waveshare_epaper/* @clydebarrow esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server/ota/* @esphome/core esphome/components/web_server/ota/* @esphome/core
esphome/components/web_server_base/* @esphome/core esphome/components/web_server_base/* @esphome/core
@@ -570,5 +578,6 @@ esphome/components/xpt2046/touchscreen/* @nielsnl68 @numo68
esphome/components/xxtea/* @clydebarrow esphome/components/xxtea/* @clydebarrow
esphome/components/zephyr/* @tomaszduda23 esphome/components/zephyr/* @tomaszduda23
esphome/components/zhlt01/* @cfeenstra1024 esphome/components/zhlt01/* @cfeenstra1024
esphome/components/zigbee/* @tomaszduda23
esphome/components/zio_ultrasonic/* @kahrendt esphome/components/zio_ultrasonic/* @kahrendt
esphome/components/zwave_proxy/* @kbx81 esphome/components/zwave_proxy/* @kbx81

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
# could be handy for archiving the generated documentation or if some version # could be handy for archiving the generated documentation or if some version
# control system is used. # control system is used.
PROJECT_NUMBER = 2026.1.0-dev PROJECT_NUMBER = 2026.2.0-dev
# Using the PROJECT_BRIEF tag one can provide an optional one line description # 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 # for a project that appears at the top of each page and should give viewer a

View File

@@ -1,6 +1,7 @@
include LICENSE include LICENSE
include README.md include README.md
include requirements.txt include requirements.txt
recursive-include esphome *.yaml
recursive-include esphome *.cpp *.h *.tcc *.c recursive-include esphome *.cpp *.h *.tcc *.c
recursive-include esphome *.py.script recursive-include esphome *.py.script
recursive-include esphome LICENSE.txt recursive-include esphome LICENSE.txt

View File

@@ -11,6 +11,16 @@ FROM base-source-${BUILD_TYPE} AS base
RUN git config --system --add safe.directory "*" RUN git config --system --add safe.directory "*"
# Install build tools for Python packages that require compilation
# (e.g., ruamel.yaml.clibz used by ESP-IDF's idf-component-manager)
RUN if command -v apk > /dev/null; then \
apk add --no-cache build-base; \
else \
apt-get update \
&& apt-get install -y --no-install-recommends build-essential \
&& rm -rf /var/lib/apt/lists/*; \
fi
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 ENV PIP_DISABLE_PIP_VERSION_CHECK=1
RUN pip install --no-cache-dir -U pip uv==0.6.14 RUN pip install --no-cache-dir -U pip uv==0.6.14

View File

@@ -1,5 +1,6 @@
# PYTHON_ARGCOMPLETE_OK # PYTHON_ARGCOMPLETE_OK
import argparse import argparse
from collections.abc import Callable
from datetime import datetime from datetime import datetime
import functools import functools
import getpass import getpass
@@ -62,6 +63,9 @@ from esphome.util import (
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
# Maximum buffer size for serial log reading to prevent unbounded memory growth
SERIAL_BUFFER_MAX_SIZE = 65536
# Special non-component keys that appear in configs # Special non-component keys that appear in configs
_NON_COMPONENT_KEYS = frozenset( _NON_COMPONENT_KEYS = frozenset(
{ {
@@ -219,8 +223,13 @@ def choose_upload_log_host(
else: else:
resolved.append(device) resolved.append(device)
if not resolved: if not resolved:
if CORE.dashboard:
hint = "If you know the IP, set 'use_address' in your network config."
else:
hint = "If you know the IP, try --device <IP>"
raise EsphomeError( raise EsphomeError(
f"All specified devices {defaults} could not be resolved. Is the device connected to the network?" f"All specified devices {defaults} could not be resolved. "
f"Is the device connected to the network? {hint}"
) )
return resolved return resolved
@@ -431,25 +440,37 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
while tries < 5: while tries < 5:
try: try:
with ser: with ser:
buffer = b""
ser.timeout = 0.1 # 100ms timeout for non-blocking reads
while True: while True:
try: try:
raw = ser.readline() # Read all available data and timestamp it
chunk = ser.read(ser.in_waiting or 1)
if not chunk:
continue
time_ = datetime.now()
milliseconds = time_.microsecond // 1000
time_str = f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}.{milliseconds:03}]"
# Add to buffer and process complete lines
# Limit buffer size to prevent unbounded memory growth
# if device sends data without newlines
buffer += chunk
if len(buffer) > SERIAL_BUFFER_MAX_SIZE:
buffer = buffer[-SERIAL_BUFFER_MAX_SIZE:]
while b"\n" in buffer:
raw_line, buffer = buffer.split(b"\n", 1)
line = raw_line.replace(b"\r", b"").decode(
"utf8", "backslashreplace"
)
safe_print(parser.parse_line(line, time_str))
backtrace_state = platformio_api.process_stacktrace(
config, line, backtrace_state=backtrace_state
)
except serial.SerialException: except serial.SerialException:
_LOGGER.error("Serial port closed!") _LOGGER.error("Serial port closed!")
return 0 return 0
line = (
raw.replace(b"\r", b"")
.replace(b"\n", b"")
.decode("utf8", "backslashreplace")
)
time_ = datetime.now()
nanoseconds = time_.microsecond // 1000
time_str = f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}.{nanoseconds:03}]"
safe_print(parser.parse_line(line, time_str))
backtrace_state = platformio_api.process_stacktrace(
config, line, backtrace_state=backtrace_state
)
except serial.SerialException: except serial.SerialException:
tries += 1 tries += 1
time.sleep(1) time.sleep(1)
@@ -518,10 +539,49 @@ def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
rc = platformio_api.run_compile(config, CORE.verbose) rc = platformio_api.run_compile(config, CORE.verbose)
if rc != 0: if rc != 0:
return rc return rc
# Check if firmware was rebuilt and emit build_info + create manifest
_check_and_emit_build_info()
idedata = platformio_api.get_idedata(config) idedata = platformio_api.get_idedata(config)
return 0 if idedata is not None else 1 return 0 if idedata is not None else 1
def _check_and_emit_build_info() -> None:
"""Check if firmware was rebuilt and emit build_info."""
import json
firmware_path = CORE.firmware_bin
build_info_json_path = CORE.relative_build_path("build_info.json")
# Check if both files exist
if not firmware_path.exists() or not build_info_json_path.exists():
return
# Check if firmware is newer than build_info (indicating a relink occurred)
if firmware_path.stat().st_mtime <= build_info_json_path.stat().st_mtime:
return
# Read build_info from JSON
try:
with open(build_info_json_path, encoding="utf-8") as f:
build_info = json.load(f)
except (OSError, json.JSONDecodeError) as e:
_LOGGER.debug("Failed to read build_info: %s", e)
return
config_hash = build_info.get("config_hash")
build_time_str = build_info.get("build_time_str")
if config_hash is None or build_time_str is None:
return
# Emit build_info with human-readable time
_LOGGER.info(
"Build Info: config_hash=0x%08x build_time_str=%s", config_hash, build_time_str
)
def upload_using_esptool( def upload_using_esptool(
config: ConfigType, port: str, file: str, speed: int config: ConfigType, port: str, file: str, speed: int
) -> str | int: ) -> str | int:
@@ -757,7 +817,13 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
exit_code = compile_program(args, config) exit_code = compile_program(args, config)
if exit_code != 0: if exit_code != 0:
return exit_code return exit_code
_LOGGER.info("Successfully compiled program.") if CORE.is_host:
from esphome.platformio_api import get_idedata
program_path = str(get_idedata(config).firmware_elf_path)
_LOGGER.info("Successfully compiled program to path '%s'", program_path)
else:
_LOGGER.info("Successfully compiled program.")
return 0 return 0
@@ -807,10 +873,8 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
if CORE.is_host: if CORE.is_host:
from esphome.platformio_api import get_idedata from esphome.platformio_api import get_idedata
idedata = get_idedata(config) program_path = str(get_idedata(config).firmware_elf_path)
if idedata is None: _LOGGER.info("Running program from path '%s'", program_path)
return 1
program_path = idedata.raw["prog_path"]
return run_external_process(program_path) return run_external_process(program_path)
# Get devices, resolving special identifiers like OTA # Get devices, resolving special identifiers like OTA
@@ -880,11 +944,21 @@ def command_dashboard(args: ArgsProtocol) -> int | None:
return dashboard.start_dashboard(args) return dashboard.start_dashboard(args)
def command_update_all(args: ArgsProtocol) -> int | None: def run_multiple_configs(
files: list, command_builder: Callable[[str], list[str]]
) -> int:
"""Run a command for each configuration file in a subprocess.
Args:
files: List of configuration files to process.
command_builder: Callable that takes a file path and returns a command list.
Returns:
Number of failed files.
"""
import click import click
success = {} success = {}
files = list_yaml_files(args.configuration)
twidth = 60 twidth = 60
def print_bar(middle_text): def print_bar(middle_text):
@@ -894,17 +968,19 @@ def command_update_all(args: ArgsProtocol) -> int | None:
safe_print(f"{half_line}{middle_text}{half_line}") safe_print(f"{half_line}{middle_text}{half_line}")
for f in files: for f in files:
safe_print(f"Updating {color(AnsiFore.CYAN, str(f))}") f_path = Path(f) if not isinstance(f, Path) else f
if any(f_path.name == x for x in SECRETS_FILES):
_LOGGER.warning("Skipping secrets file %s", f_path)
continue
safe_print(f"Processing {color(AnsiFore.CYAN, str(f))}")
safe_print("-" * twidth) safe_print("-" * twidth)
safe_print() safe_print()
if CORE.dashboard:
rc = run_external_process( cmd = command_builder(f)
"esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA" rc = run_external_process(*cmd)
)
else:
rc = run_external_process(
"esphome", "run", f, "--no-logs", "--device", "OTA"
)
if rc == 0: if rc == 0:
print_bar(f"[{color(AnsiFore.BOLD_GREEN, 'SUCCESS')}] {str(f)}") print_bar(f"[{color(AnsiFore.BOLD_GREEN, 'SUCCESS')}] {str(f)}")
success[f] = True success[f] = True
@@ -919,6 +995,8 @@ def command_update_all(args: ArgsProtocol) -> int | None:
print_bar(f"[{color(AnsiFore.BOLD_WHITE, 'SUMMARY')}]") print_bar(f"[{color(AnsiFore.BOLD_WHITE, 'SUMMARY')}]")
failed = 0 failed = 0
for f in files: for f in files:
if f not in success:
continue # Skipped file
if success[f]: if success[f]:
safe_print(f" - {str(f)}: {color(AnsiFore.GREEN, 'SUCCESS')}") safe_print(f" - {str(f)}: {color(AnsiFore.GREEN, 'SUCCESS')}")
else: else:
@@ -927,6 +1005,17 @@ def command_update_all(args: ArgsProtocol) -> int | None:
return failed return failed
def command_update_all(args: ArgsProtocol) -> int | None:
files = list_yaml_files(args.configuration)
def build_command(f):
if CORE.dashboard:
return ["esphome", "--dashboard", "run", f, "--no-logs", "--device", "OTA"]
return ["esphome", "run", f, "--no-logs", "--device", "OTA"]
return run_multiple_configs(files, build_command)
def command_idedata(args: ArgsProtocol, config: ConfigType) -> int: def command_idedata(args: ArgsProtocol, config: ConfigType) -> int:
import json import json
@@ -981,6 +1070,7 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
idedata.objdump_path, idedata.objdump_path,
idedata.readelf_path, idedata.readelf_path,
external_components, external_components,
idedata=idedata,
) )
analyzer.analyze() analyzer.analyze()
@@ -1487,38 +1577,48 @@ def run_esphome(argv):
_LOGGER.info("ESPHome %s", const.__version__) _LOGGER.info("ESPHome %s", const.__version__)
for conf_path in args.configuration: # Multiple configurations: use subprocesses to avoid state leakage
conf_path = Path(conf_path) # between compilations (e.g., LVGL touchscreen state in module globals)
if any(conf_path.name == x for x in SECRETS_FILES): if len(args.configuration) > 1:
_LOGGER.warning("Skipping secrets file %s", conf_path) # Build command by reusing argv, replacing all configs with single file
continue # argv[0] is the program path, skip it since we prefix with "esphome"
def build_command(f):
return (
["esphome"]
+ [arg for arg in argv[1:] if arg not in args.configuration]
+ [str(f)]
)
CORE.config_path = conf_path return run_multiple_configs(args.configuration, build_command)
CORE.dashboard = args.dashboard
# For logs command, skip updating external components # Single configuration
skip_external = args.command == "logs" conf_path = Path(args.configuration[0])
config = read_config( if any(conf_path.name == x for x in SECRETS_FILES):
dict(args.substitution) if args.substitution else {}, _LOGGER.warning("Skipping secrets file %s", conf_path)
skip_external_update=skip_external, return 0
)
if config is None:
return 2
CORE.config = config
if args.command not in POST_CONFIG_ACTIONS: CORE.config_path = conf_path
safe_print(f"Unknown command {args.command}") CORE.dashboard = args.dashboard
try: # For logs command, skip updating external components
rc = POST_CONFIG_ACTIONS[args.command](args, config) skip_external = args.command == "logs"
except EsphomeError as e: config = read_config(
_LOGGER.error(e, exc_info=args.verbose) dict(args.substitution) if args.substitution else {},
return 1 skip_external_update=skip_external,
if rc != 0: )
return rc if config is None:
return 2
CORE.config = config
CORE.reset() if args.command not in POST_CONFIG_ACTIONS:
return 0 safe_print(f"Unknown command {args.command}")
return 1
try:
return POST_CONFIG_ACTIONS[args.command](args, config)
except EsphomeError as e:
_LOGGER.error(e, exc_info=args.verbose)
return 1
def main(): def main():

View File

@@ -22,6 +22,7 @@ from .helpers import (
map_section_name, map_section_name,
parse_symbol_line, parse_symbol_line,
) )
from .toolchain import find_tool, resolve_tool_path, run_tool
if TYPE_CHECKING: if TYPE_CHECKING:
from esphome.platformio_api import IDEData from esphome.platformio_api import IDEData
@@ -53,6 +54,9 @@ _NAMESPACE_STD = "std::"
# Type alias for symbol information: (symbol_name, size, component) # Type alias for symbol information: (symbol_name, size, component)
SymbolInfoType = tuple[str, int, str] SymbolInfoType = tuple[str, int, str]
# RAM sections - symbols in these sections consume RAM
RAM_SECTIONS = frozenset([".data", ".bss"])
@dataclass @dataclass
class MemorySection: class MemorySection:
@@ -60,7 +64,20 @@ class MemorySection:
name: str name: str
symbols: list[SymbolInfoType] = field(default_factory=list) symbols: list[SymbolInfoType] = field(default_factory=list)
total_size: int = 0 total_size: int = 0 # Actual section size from ELF headers
symbol_size: int = 0 # Sum of symbol sizes (may be less than total_size)
@dataclass
class SDKSymbol:
"""Represents a symbol from an SDK library that's not in the ELF symbol table."""
name: str
size: int
library: str # Name of the .a file (e.g., "libpp.a")
section: str # ".bss" or ".data"
is_local: bool # True if static/local symbol (lowercase in nm output)
demangled: str = "" # Demangled name (populated after analysis)
@dataclass @dataclass
@@ -115,9 +132,19 @@ class MemoryAnalyzer:
readelf_path = readelf_path or idedata.readelf_path readelf_path = readelf_path or idedata.readelf_path
_LOGGER.debug("Using toolchain paths from PlatformIO idedata") _LOGGER.debug("Using toolchain paths from PlatformIO idedata")
# Validate paths exist, fall back to find_tool if they don't
# This handles cases like Zephyr where cc_path doesn't include full path
# and the toolchain prefix may differ (e.g., arm-zephyr-eabi- vs arm-none-eabi-)
objdump_path = resolve_tool_path("objdump", objdump_path, objdump_path)
readelf_path = resolve_tool_path("readelf", readelf_path, objdump_path)
self.objdump_path = objdump_path or "objdump" self.objdump_path = objdump_path or "objdump"
self.readelf_path = readelf_path or "readelf" self.readelf_path = readelf_path or "readelf"
self.external_components = external_components or set() self.external_components = external_components or set()
self._idedata = idedata
# Derive nm path from objdump path using shared toolchain utility
self.nm_path = find_tool("nm", self.objdump_path)
self.sections: dict[str, MemorySection] = {} self.sections: dict[str, MemorySection] = {}
self.components: dict[str, ComponentMemory] = defaultdict( self.components: dict[str, ComponentMemory] = defaultdict(
@@ -128,15 +155,25 @@ class MemoryAnalyzer:
self._esphome_core_symbols: list[ self._esphome_core_symbols: list[
tuple[str, str, int] tuple[str, str, int]
] = [] # Track core symbols ] = [] # Track core symbols
self._component_symbols: dict[str, list[tuple[str, str, int]]] = defaultdict( # Track symbols for all components: (symbol_name, demangled, size, section)
self._component_symbols: dict[str, list[tuple[str, str, int, str]]] = (
defaultdict(list)
)
# Track RAM symbols separately for detailed analysis: (symbol_name, demangled, size, section)
self._ram_symbols: dict[str, list[tuple[str, str, int, str]]] = defaultdict(
list list
) # Track symbols for all components )
# Track ELF symbol names for SDK cross-reference
self._elf_symbol_names: set[str] = set()
# SDK symbols not in ELF (static/local symbols from closed-source libs)
self._sdk_symbols: list[SDKSymbol] = []
def analyze(self) -> dict[str, ComponentMemory]: def analyze(self) -> dict[str, ComponentMemory]:
"""Analyze the ELF file and return component memory usage.""" """Analyze the ELF file and return component memory usage."""
self._parse_sections() self._parse_sections()
self._parse_symbols() self._parse_symbols()
self._categorize_symbols() self._categorize_symbols()
self._analyze_sdk_libraries()
return dict(self.components) return dict(self.components)
def _parse_sections(self) -> None: def _parse_sections(self) -> None:
@@ -190,6 +227,8 @@ class MemoryAnalyzer:
continue continue
self.sections[section].symbols.append((name, size, "")) self.sections[section].symbols.append((name, size, ""))
self.sections[section].symbol_size += size
self._elf_symbol_names.add(name)
seen_addresses.add(address) seen_addresses.add(address)
def _categorize_symbols(self) -> None: def _categorize_symbols(self) -> None:
@@ -233,8 +272,13 @@ class MemoryAnalyzer:
if size > 0: if size > 0:
demangled = self._demangle_symbol(symbol_name) demangled = self._demangle_symbol(symbol_name)
self._component_symbols[component].append( self._component_symbols[component].append(
(symbol_name, demangled, size) (symbol_name, demangled, size, section_name)
) )
# Track RAM symbols separately for detailed RAM analysis
if section_name in RAM_SECTIONS:
self._ram_symbols[component].append(
(symbol_name, demangled, size, section_name)
)
def _identify_component(self, symbol_name: str) -> str: def _identify_component(self, symbol_name: str) -> str:
"""Identify which component a symbol belongs to.""" """Identify which component a symbol belongs to."""
@@ -328,6 +372,247 @@ class MemoryAnalyzer:
return "Other Core" return "Other Core"
def get_unattributed_ram(self) -> tuple[int, int, int]:
"""Get unattributed RAM sizes (SDK/framework overhead).
Returns:
Tuple of (unattributed_bss, unattributed_data, total_unattributed)
These are bytes in RAM sections that have no corresponding symbols.
"""
bss_section = self.sections.get(".bss")
data_section = self.sections.get(".data")
unattributed_bss = 0
unattributed_data = 0
if bss_section:
unattributed_bss = max(0, bss_section.total_size - bss_section.symbol_size)
if data_section:
unattributed_data = max(
0, data_section.total_size - data_section.symbol_size
)
return unattributed_bss, unattributed_data, unattributed_bss + unattributed_data
def _find_sdk_library_dirs(self) -> list[Path]:
"""Find SDK library directories based on platform.
Returns:
List of paths to SDK library directories containing .a files.
"""
sdk_dirs: list[Path] = []
if self._idedata is None:
return sdk_dirs
# Get the CC path to determine the framework location
cc_path = getattr(self._idedata, "cc_path", None)
if not cc_path:
return sdk_dirs
cc_path = Path(cc_path)
# For ESP8266 Arduino framework
# CC is like: ~/.platformio/packages/toolchain-xtensa/bin/xtensa-lx106-elf-gcc
# SDK libs are in: ~/.platformio/packages/framework-arduinoespressif8266/tools/sdk/lib/
if "xtensa-lx106" in str(cc_path):
platformio_dir = cc_path.parent.parent.parent
esp8266_sdk = (
platformio_dir
/ "framework-arduinoespressif8266"
/ "tools"
/ "sdk"
/ "lib"
)
if esp8266_sdk.exists():
sdk_dirs.append(esp8266_sdk)
# Also check for NONOSDK subdirectories (closed-source libs)
sdk_dirs.extend(
subdir
for subdir in esp8266_sdk.iterdir()
if subdir.is_dir() and subdir.name.startswith("NONOSDK")
)
# For ESP32 IDF framework
# CC is like: ~/.platformio/packages/toolchain-xtensa-esp-elf/bin/xtensa-esp32-elf-gcc
# or: ~/.platformio/packages/toolchain-riscv32-esp/bin/riscv32-esp-elf-gcc
elif "xtensa-esp" in str(cc_path) or "riscv32-esp" in str(cc_path):
# Detect ESP32 variant from CC path or defines
variant = self._detect_esp32_variant()
if variant:
platformio_dir = cc_path.parent.parent.parent
espidf_dir = platformio_dir / "framework-espidf" / "components"
if espidf_dir.exists():
# Find all directories named after the variant that contain .a files
# This handles various ESP-IDF library layouts:
# - components/*/lib/<variant>/
# - components/*/<variant>/
# - components/*/lib/lib/<variant>/
# - components/*/*/lib_*/<variant>/
sdk_dirs.extend(
variant_dir
for variant_dir in espidf_dir.rglob(variant)
if variant_dir.is_dir() and any(variant_dir.glob("*.a"))
)
return sdk_dirs
def _detect_esp32_variant(self) -> str | None:
"""Detect ESP32 variant from idedata defines.
Returns:
Variant string like 'esp32', 'esp32s2', 'esp32c3', etc. or None.
"""
if self._idedata is None:
return None
defines = getattr(self._idedata, "defines", [])
if not defines:
return None
# ESPHome always adds USE_ESP32_VARIANT_xxx defines
variant_prefix = "USE_ESP32_VARIANT_"
for define in defines:
if define.startswith(variant_prefix):
# Extract variant name and convert to lowercase
# USE_ESP32_VARIANT_ESP32 -> esp32
# USE_ESP32_VARIANT_ESP32S3 -> esp32s3
return define[len(variant_prefix) :].lower()
return None
def _parse_sdk_library(
self, lib_path: Path
) -> tuple[list[tuple[str, int, str, bool]], set[str]]:
"""Parse a single SDK library for symbols.
Args:
lib_path: Path to the .a library file
Returns:
Tuple of:
- List of BSS/DATA symbols: (symbol_name, size, section, is_local)
- Set of global BSS/DATA symbol names (for checking if RAM is linked)
"""
ram_symbols: list[tuple[str, int, str, bool]] = []
global_ram_symbols: set[str] = set()
result = run_tool([self.nm_path, "--size-sort", str(lib_path)], timeout=10)
if result is None:
return ram_symbols, global_ram_symbols
for line in result.stdout.splitlines():
parts = line.split()
if len(parts) < 3:
continue
try:
size = int(parts[0], 16)
sym_type = parts[1]
name = parts[2]
# Only collect BSS (b/B) and DATA (d/D) for RAM analysis
if sym_type in ("b", "B"):
section = ".bss"
is_local = sym_type == "b"
ram_symbols.append((name, size, section, is_local))
# Track global RAM symbols (B/D) for linking check
if sym_type == "B":
global_ram_symbols.add(name)
elif sym_type in ("d", "D"):
section = ".data"
is_local = sym_type == "d"
ram_symbols.append((name, size, section, is_local))
if sym_type == "D":
global_ram_symbols.add(name)
except (ValueError, IndexError):
continue
return ram_symbols, global_ram_symbols
def _analyze_sdk_libraries(self) -> None:
"""Analyze SDK libraries to find symbols not in the ELF.
This finds static/local symbols from closed-source SDK libraries
that consume RAM but don't appear in the final ELF symbol table.
Only includes symbols from libraries that have RAM actually linked
(at least one global BSS/DATA symbol in the ELF).
"""
sdk_dirs = self._find_sdk_library_dirs()
if not sdk_dirs:
_LOGGER.debug("No SDK library directories found")
return
_LOGGER.debug("Analyzing SDK libraries in %d directories", len(sdk_dirs))
# Track seen symbols to avoid duplicates from multiple SDK versions
seen_symbols: set[str] = set()
for sdk_dir in sdk_dirs:
for lib_path in sorted(sdk_dir.glob("*.a")):
lib_name = lib_path.name
ram_symbols, global_ram_symbols = self._parse_sdk_library(lib_path)
# Check if this library's RAM is actually linked by seeing if any
# of its global BSS/DATA symbols appear in the ELF
if not global_ram_symbols & self._elf_symbol_names:
# No RAM from this library is in the ELF - skip it
continue
for name, size, section, is_local in ram_symbols:
# Skip if already in ELF or already seen from another lib
if name in self._elf_symbol_names or name in seen_symbols:
continue
# Only track symbols with non-zero size
if size > 0:
self._sdk_symbols.append(
SDKSymbol(
name=name,
size=size,
library=lib_name,
section=section,
is_local=is_local,
)
)
seen_symbols.add(name)
# Demangle SDK symbols for better readability
if self._sdk_symbols:
sdk_names = [sym.name for sym in self._sdk_symbols]
demangled_map = batch_demangle(sdk_names, objdump_path=self.objdump_path)
for sym in self._sdk_symbols:
sym.demangled = demangled_map.get(sym.name, sym.name)
# Sort by size descending for reporting
self._sdk_symbols.sort(key=lambda s: s.size, reverse=True)
total_sdk_ram = sum(s.size for s in self._sdk_symbols)
_LOGGER.debug(
"Found %d SDK symbols not in ELF, totaling %d bytes",
len(self._sdk_symbols),
total_sdk_ram,
)
def get_sdk_ram_symbols(self) -> list[SDKSymbol]:
"""Get SDK symbols that consume RAM but aren't in the ELF symbol table.
Returns:
List of SDKSymbol objects sorted by size descending.
"""
return self._sdk_symbols
def get_sdk_ram_by_library(self) -> dict[str, list[SDKSymbol]]:
"""Get SDK RAM symbols grouped by library.
Returns:
Dictionary mapping library name to list of symbols.
"""
by_lib: dict[str, list[SDKSymbol]] = defaultdict(list)
for sym in self._sdk_symbols:
by_lib[sym.library].append(sym)
return dict(by_lib)
if __name__ == "__main__": if __name__ == "__main__":
from .cli import main from .cli import main

View File

@@ -1,17 +1,25 @@
"""CLI interface for memory analysis with report generation.""" """CLI interface for memory analysis with report generation."""
from __future__ import annotations
from collections import defaultdict from collections import defaultdict
from collections.abc import Callable
import json import json
import sys import sys
from typing import TYPE_CHECKING
from . import ( from . import (
_COMPONENT_API, _COMPONENT_API,
_COMPONENT_CORE, _COMPONENT_CORE,
_COMPONENT_PREFIX_ESPHOME, _COMPONENT_PREFIX_ESPHOME,
_COMPONENT_PREFIX_EXTERNAL, _COMPONENT_PREFIX_EXTERNAL,
RAM_SECTIONS,
MemoryAnalyzer, MemoryAnalyzer,
) )
if TYPE_CHECKING:
from . import ComponentMemory
class MemoryAnalyzerCLI(MemoryAnalyzer): class MemoryAnalyzerCLI(MemoryAnalyzer):
"""Memory analyzer with CLI-specific report generation.""" """Memory analyzer with CLI-specific report generation."""
@@ -20,6 +28,8 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
SYMBOL_SIZE_THRESHOLD: int = ( SYMBOL_SIZE_THRESHOLD: int = (
100 # Show symbols larger than this in detailed analysis 100 # Show symbols larger than this in detailed analysis
) )
# Lower threshold for RAM symbols (RAM is more constrained)
RAM_SYMBOL_SIZE_THRESHOLD: int = 24
# Column width constants # Column width constants
COL_COMPONENT: int = 29 COL_COMPONENT: int = 29
@@ -84,6 +94,60 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
COL_CORE_PERCENT, COL_CORE_PERCENT,
) )
def _add_section_header(self, lines: list[str], title: str) -> None:
"""Add a section header with title centered between separator lines."""
lines.append("")
lines.append("=" * self.TABLE_WIDTH)
lines.append(title.center(self.TABLE_WIDTH))
lines.append("=" * self.TABLE_WIDTH)
lines.append("")
def _add_top_consumers(
self,
lines: list[str],
title: str,
components: list[tuple[str, ComponentMemory]],
get_size: Callable[[ComponentMemory], int],
total: int,
memory_type: str,
limit: int = 25,
) -> None:
"""Add a formatted list of top memory consumers to the report.
Args:
lines: List of report lines to append the output to.
title: Section title to print before the list.
components: Sequence of (name, ComponentMemory) tuples to analyze.
get_size: Callable that takes a ComponentMemory and returns the
size in bytes to use for ranking and display.
total: Total size in bytes for computing percentage usage.
memory_type: Label for the memory region (e.g., "flash" or "RAM").
limit: Maximum number of components to include in the list.
"""
lines.append("")
lines.append(f"{title}:")
for i, (name, mem) in enumerate(components[:limit]):
size = get_size(mem)
if size > 0:
percentage = (size / total * 100) if total > 0 else 0
lines.append(
f"{i + 1}. {name} ({size:,} B) - {percentage:.1f}% of analyzed {memory_type}"
)
def _format_symbol_with_section(
self, demangled: str, size: int, section: str | None = None
) -> str:
"""Format a symbol entry, optionally adding a RAM section label.
If section is one of the RAM sections (.data or .bss), a label like
" [data]" or " [bss]" is appended. For non-RAM sections or when
section is None, no section label is added.
"""
section_label = ""
if section in RAM_SECTIONS:
section_label = f" [{section[1:]}]" # .data -> [data], .bss -> [bss]
return f"{demangled} ({size:,} B){section_label}"
def generate_report(self, detailed: bool = False) -> str: def generate_report(self, detailed: bool = False) -> str:
"""Generate a formatted memory report.""" """Generate a formatted memory report."""
components = sorted( components = sorted(
@@ -124,43 +188,70 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
f"{total_flash:>{self.COL_TOTAL_FLASH - 2},} B | {total_ram:>{self.COL_TOTAL_RAM - 2},} B" f"{total_flash:>{self.COL_TOTAL_FLASH - 2},} B | {total_ram:>{self.COL_TOTAL_RAM - 2},} B"
) )
# Top consumers # Show unattributed RAM (SDK/framework overhead)
lines.append("") unattributed_bss, unattributed_data, unattributed_total = (
lines.append("Top Flash Consumers:") self.get_unattributed_ram()
for i, (name, mem) in enumerate(components[:25]): )
if mem.flash_total > 0: if unattributed_total > 0:
percentage = ( lines.append("")
(mem.flash_total / total_flash * 100) if total_flash > 0 else 0 lines.append(
) f"Unattributed RAM: {unattributed_total:,} B (SDK/framework overhead)"
lines.append( )
f"{i + 1}. {name} ({mem.flash_total:,} B) - {percentage:.1f}% of analyzed flash" if unattributed_bss > 0 and unattributed_data > 0:
) lines.append(
f" .bss: {unattributed_bss:,} B | .data: {unattributed_data:,} B"
lines.append("") )
lines.append("Top RAM Consumers:")
ram_components = sorted(components, key=lambda x: x[1].ram_total, reverse=True) # Show SDK symbol breakdown if available
for i, (name, mem) in enumerate(ram_components[:25]): sdk_by_lib = self.get_sdk_ram_by_library()
if mem.ram_total > 0: if sdk_by_lib:
percentage = (mem.ram_total / total_ram * 100) if total_ram > 0 else 0 lines.append("")
lines.append( lines.append("SDK library breakdown (static symbols not in ELF):")
f"{i + 1}. {name} ({mem.ram_total:,} B) - {percentage:.1f}% of analyzed RAM" # Sort libraries by total size
) lib_totals = [
(lib, sum(s.size for s in syms), syms)
lines.append("") for lib, syms in sdk_by_lib.items()
lines.append( ]
"Note: This analysis covers symbols in the ELF file. Some runtime allocations may not be included." lib_totals.sort(key=lambda x: x[1], reverse=True)
for lib_name, lib_total, syms in lib_totals:
if lib_total == 0:
continue
lines.append(f" {lib_name}: {lib_total:,} B")
# Show top symbols from this library
for sym in sorted(syms, key=lambda s: s.size, reverse=True)[:3]:
section_label = sym.section.lstrip(".")
# Use demangled name (falls back to original if not demangled)
display_name = sym.demangled or sym.name
if len(display_name) > 50:
display_name = f"{display_name[:47]}..."
lines.append(
f" {sym.size:>6,} B [{section_label}] {display_name}"
)
# Top consumers
self._add_top_consumers(
lines,
"Top Flash Consumers",
components,
lambda m: m.flash_total,
total_flash,
"flash",
)
ram_components = sorted(components, key=lambda x: x[1].ram_total, reverse=True)
self._add_top_consumers(
lines,
"Top RAM Consumers",
ram_components,
lambda m: m.ram_total,
total_ram,
"RAM",
) )
lines.append("=" * self.TABLE_WIDTH)
# Add ESPHome core detailed analysis if there are core symbols # Add ESPHome core detailed analysis if there are core symbols
if self._esphome_core_symbols: if self._esphome_core_symbols:
lines.append("") self._add_section_header(lines, f"{_COMPONENT_CORE} Detailed Analysis")
lines.append("=" * self.TABLE_WIDTH)
lines.append(
f"{_COMPONENT_CORE} Detailed Analysis".center(self.TABLE_WIDTH)
)
lines.append("=" * self.TABLE_WIDTH)
lines.append("")
# Group core symbols by subcategory # Group core symbols by subcategory
core_subcategories: dict[str, list[tuple[str, str, int]]] = defaultdict( core_subcategories: dict[str, list[tuple[str, str, int]]] = defaultdict(
@@ -212,7 +303,11 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):" f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):"
) )
for i, (symbol, demangled, size) in enumerate(large_core_symbols): for i, (symbol, demangled, size) in enumerate(large_core_symbols):
lines.append(f"{i + 1}. {demangled} ({size:,} B)") # Core symbols only track (symbol, demangled, size) without section info,
# so we don't show section labels here
lines.append(
f"{i + 1}. {self._format_symbol_with_section(demangled, size)}"
)
lines.append("=" * self.TABLE_WIDTH) lines.append("=" * self.TABLE_WIDTH)
@@ -268,11 +363,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
for comp_name, comp_mem in components_to_analyze: for comp_name, comp_mem in components_to_analyze:
if not (comp_symbols := self._component_symbols.get(comp_name, [])): if not (comp_symbols := self._component_symbols.get(comp_name, [])):
continue continue
lines.append("") self._add_section_header(lines, f"{comp_name} Detailed Analysis")
lines.append("=" * self.TABLE_WIDTH)
lines.append(f"{comp_name} Detailed Analysis".center(self.TABLE_WIDTH))
lines.append("=" * self.TABLE_WIDTH)
lines.append("")
# Sort symbols by size # Sort symbols by size
sorted_symbols = sorted(comp_symbols, key=lambda x: x[2], reverse=True) sorted_symbols = sorted(comp_symbols, key=lambda x: x[2], reverse=True)
@@ -283,19 +374,69 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
# Show all symbols above threshold for better visibility # Show all symbols above threshold for better visibility
large_symbols = [ large_symbols = [
(sym, dem, size) (sym, dem, size, sec)
for sym, dem, size in sorted_symbols for sym, dem, size, sec in sorted_symbols
if size > self.SYMBOL_SIZE_THRESHOLD if size > self.SYMBOL_SIZE_THRESHOLD
] ]
lines.append( lines.append(
f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_symbols)} symbols):" f"{comp_name} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_symbols)} symbols):"
) )
for i, (symbol, demangled, size) in enumerate(large_symbols): for i, (symbol, demangled, size, section) in enumerate(large_symbols):
lines.append(f"{i + 1}. {demangled} ({size:,} B)") lines.append(
f"{i + 1}. {self._format_symbol_with_section(demangled, size, section)}"
)
lines.append("=" * self.TABLE_WIDTH) lines.append("=" * self.TABLE_WIDTH)
# Detailed RAM analysis by component (at end, before RAM strings analysis)
self._add_section_header(lines, "RAM Symbol Analysis by Component")
# Show top 15 RAM consumers with their large symbols
for name, mem in ram_components[:15]:
if mem.ram_total == 0:
continue
ram_syms = self._ram_symbols.get(name, [])
if not ram_syms:
continue
# Sort by size descending
sorted_ram_syms = sorted(ram_syms, key=lambda x: x[2], reverse=True)
large_ram_syms = [
s for s in sorted_ram_syms if s[2] > self.RAM_SYMBOL_SIZE_THRESHOLD
]
lines.append(f"{name} ({mem.ram_total:,} B total RAM):")
# Show breakdown by section type
data_size = sum(s[2] for s in ram_syms if s[3] == ".data")
bss_size = sum(s[2] for s in ram_syms if s[3] == ".bss")
lines.append(f" .data (initialized): {data_size:,} B")
lines.append(f" .bss (uninitialized): {bss_size:,} B")
if large_ram_syms:
lines.append(
f" Symbols > {self.RAM_SYMBOL_SIZE_THRESHOLD} B ({len(large_ram_syms)}):"
)
for symbol, demangled, size, section in large_ram_syms[:10]:
# Format section label consistently by stripping leading dot
section_label = section.lstrip(".") if section else ""
# Add ellipsis if name is truncated
demangled_display = (
f"{demangled[:70]}..." if len(demangled) > 70 else demangled
)
lines.append(
f" {size:>6,} B [{section_label}] {demangled_display}"
)
if len(large_ram_syms) > 10:
lines.append(f" ... and {len(large_ram_syms) - 10} more")
lines.append("")
lines.append(
"Note: This analysis covers symbols in the ELF file. Some runtime allocations may not be included."
)
lines.append("=" * self.TABLE_WIDTH)
return "\n".join(lines) return "\n".join(lines)
def to_json(self) -> str: def to_json(self) -> str:

View File

@@ -7,11 +7,63 @@ ESPHOME_COMPONENT_PATTERN = re.compile(r"esphome::([a-zA-Z0-9_]+)::")
# Section mapping for ELF file sections # Section mapping for ELF file sections
# Maps standard section names to their various platform-specific variants # Maps standard section names to their various platform-specific variants
# Note: Order matters! More specific patterns (.bss) must come before general ones (.dram)
# because ESP-IDF uses names like ".dram0.bss" which would match ".dram" otherwise
#
# Platform-specific sections:
# - ESP8266/ESP32: .iram*, .dram*
# - LibreTiny RTL87xx: .xip.code_* (flash), .ram.code_* (RAM)
# - LibreTiny BK7231: .itcm.code (fast RAM), .vectors (interrupt vectors)
# - LibreTiny LN882X: .flash_text, .flash_copy* (flash code)
# - Zephyr/nRF52: text, rodata, datas, bss (no leading dots)
SECTION_MAPPING = { SECTION_MAPPING = {
".text": frozenset([".text", ".iram"]), ".text": frozenset(
".rodata": frozenset([".rodata"]), [
".data": frozenset([".data", ".dram"]), ".text",
".bss": frozenset([".bss"]), ".iram",
# LibreTiny RTL87xx XIP (eXecute In Place) flash code
".xip.code",
# LibreTiny RTL87xx RAM code
".ram.code_text",
# LibreTiny BK7231 fast RAM code and vectors
".itcm.code",
".vectors",
# LibreTiny LN882X flash code
".flash_text",
".flash_copy",
# Zephyr/nRF52 sections (no leading dots)
"text",
"rom_start",
]
),
".rodata": frozenset(
[
".rodata",
# LibreTiny RTL87xx read-only data in RAM
".ram.code_rodata",
# Zephyr/nRF52 sections (no leading dots)
"rodata",
]
),
# .bss patterns - must be before .data to catch ".dram0.bss"
".bss": frozenset(
[
".bss",
# LibreTiny LN882X BSS
".bss_ram",
# Zephyr/nRF52 sections (no leading dots)
"bss",
"noinit",
]
),
".data": frozenset(
[
".data",
".dram",
# Zephyr/nRF52 sections (no leading dots)
"datas",
]
),
} }
# Section to ComponentMemory attribute mapping # Section to ComponentMemory attribute mapping
@@ -88,6 +140,77 @@ SYMBOL_PATTERNS = {
"sys_mbox_new", "sys_mbox_new",
"sys_arch_mbox_tryfetch", "sys_arch_mbox_tryfetch",
], ],
# LibreTiny/Beken BK7231 radio calibration
"bk_radio_cal": [
"bk7011_",
"calibration_main",
"gcali_",
"rwnx_cal",
],
# LibreTiny/Beken WiFi MAC layer
"bk_wifi_mac": [
"rxu_", # RX upper layer
"txu_", # TX upper layer
"txl_", # TX lower layer
"rxl_", # RX lower layer
"scanu_", # Scan unit
"mm_hw_", # MAC management hardware
"mm_bcn", # MAC management beacon
"mm_tim", # MAC management TIM
"mm_check", # MAC management checks
"sm_connect", # Station management
"me_beacon", # Management entity beacon
"me_build", # Management entity build
"hapd_", # Host AP daemon
"chan_pre_", # Channel management
"handle_probe_", # Probe handling
],
# LibreTiny/Beken system control
"bk_system": [
"sctrl_", # System control
"icu_ctrl", # Interrupt control unit
"gdma_ctrl", # DMA control
"mpb_ctrl", # MPB control
"uf2_", # UF2 OTA
"bkreg_", # Beken registers
],
# LibreTiny/Beken BLE stack
"bk_ble": [
"gapc_", # GAP client
"gattc_", # GATT client
"attc_", # ATT client
"attmdb_", # ATT database
"atts_", # ATT server
"l2cc_", # L2CAP
"prf_env", # Profile environment
],
# LibreTiny/Beken scheduler
"bk_scheduler": [
"sch_plan_", # Scheduler plan
"sch_prog_", # Scheduler program
"sch_arb_", # Scheduler arbiter
],
# LibreTiny/Beken DMA descriptors
"bk_dma": [
"rx_payload_desc",
"rx_dma_hdrdesc",
"tx_hw_desc",
"host_event_data",
"host_cmd_data",
],
# ARM EABI compiler runtime (LibreTiny uses ARM Cortex-M)
"arm_runtime": [
"__aeabi_",
"__adddf3",
"__subdf3",
"__muldf3",
"__divdf3",
"__addsf3",
"__subsf3",
"__mulsf3",
"__divsf3",
"__gnu_unwind",
],
"xtensa": ["xt_", "_xt_", "xPortEnterCriticalTimeout"], "xtensa": ["xt_", "_xt_", "xPortEnterCriticalTimeout"],
"heap": ["heap_", "multi_heap"], "heap": ["heap_", "multi_heap"],
"spi_flash": ["spi_flash"], "spi_flash": ["spi_flash"],
@@ -782,7 +905,22 @@ SYMBOL_PATTERNS = {
"math_internal": ["__mdiff", "__lshift", "__mprec_tens", "quorem"], "math_internal": ["__mdiff", "__lshift", "__mprec_tens", "quorem"],
"character_class": ["__chclass"], "character_class": ["__chclass"],
"camellia": ["camellia_", "camellia_feistel"], "camellia": ["camellia_", "camellia_feistel"],
"crypto_tables": ["FSb", "FSb2", "FSb3", "FSb4"], "crypto_tables": [
"FSb",
"FSb2",
"FSb3",
"FSb4",
"Te0", # AES encryption table
"Td0", # AES decryption table
"crc32_table", # CRC32 lookup table
"crc_tab", # CRC lookup table
],
"crypto_hash": [
"SHA1Transform", # SHA1 hash function
"MD5Transform", # MD5 hash function
"SHA256",
"SHA512",
],
"event_buffer": ["g_eb_list_desc", "eb_space"], "event_buffer": ["g_eb_list_desc", "eb_space"],
"base_node": ["base_node_", "base_node_add_handler"], "base_node": ["base_node_", "base_node_add_handler"],
"file_descriptor": ["s_fd_table"], "file_descriptor": ["s_fd_table"],

View File

@@ -94,13 +94,13 @@ def parse_symbol_line(line: str) -> tuple[str, str, int, str] | None:
return None return None
# Find section, size, and name # Find section, size, and name
# Try each part as a potential section name
for i, part in enumerate(parts): for i, part in enumerate(parts):
if not part.startswith("."): # Skip parts that are clearly flags, addresses, or other metadata
continue # Sections start with '.' (standard ELF) or are known section names (Zephyr)
section = map_section_name(part) section = map_section_name(part)
if not section: if not section:
break continue
# Need at least size field after section # Need at least size field after section
if i + 1 >= len(parts): if i + 1 >= len(parts):

View File

@@ -3,8 +3,13 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
import os
from pathlib import Path from pathlib import Path
import subprocess import subprocess
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Sequence
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@@ -13,10 +18,82 @@ TOOLCHAIN_PREFIXES = [
"xtensa-lx106-elf-", # ESP8266 "xtensa-lx106-elf-", # ESP8266
"xtensa-esp32-elf-", # ESP32 "xtensa-esp32-elf-", # ESP32
"xtensa-esp-elf-", # ESP32 (newer IDF) "xtensa-esp-elf-", # ESP32 (newer IDF)
"arm-zephyr-eabi-", # nRF52/Zephyr SDK
"arm-none-eabi-", # Generic ARM (RP2040, etc.)
"", # System default (no prefix) "", # System default (no prefix)
] ]
def _find_in_platformio_packages(tool_name: str) -> str | None:
"""Search for a tool in PlatformIO package directories.
This handles cases like Zephyr SDK where tools are installed in nested
directories that aren't in PATH.
Args:
tool_name: Name of the tool (e.g., "readelf", "objdump")
Returns:
Full path to the tool or None if not found
"""
# Get PlatformIO packages directory
platformio_home = Path(os.path.expanduser("~/.platformio/packages"))
if not platformio_home.exists():
return None
# Search patterns for toolchains that might contain the tool
# Order matters - more specific patterns first
search_patterns = [
# Zephyr SDK deeply nested structure (4 levels)
# e.g., toolchain-gccarmnoneeabi/zephyr-sdk-0.17.4/arm-zephyr-eabi/bin/arm-zephyr-eabi-objdump
f"toolchain-*/*/*/bin/*-{tool_name}",
# Zephyr SDK nested structure (3 levels)
f"toolchain-*/*/bin/*-{tool_name}",
f"toolchain-*/bin/*-{tool_name}",
# Standard PlatformIO toolchain structure
f"toolchain-*/bin/*{tool_name}",
]
for pattern in search_patterns:
matches = list(platformio_home.glob(pattern))
if matches:
# Sort to get consistent results, prefer arm-zephyr-eabi over arm-none-eabi
matches.sort(key=lambda p: ("zephyr" not in str(p), str(p)))
tool_path = str(matches[0])
_LOGGER.debug("Found %s in PlatformIO packages: %s", tool_name, tool_path)
return tool_path
return None
def resolve_tool_path(
tool_name: str,
derived_path: str | None,
objdump_path: str | None = None,
) -> str | None:
"""Resolve a tool path, falling back to find_tool if derived path doesn't exist.
Args:
tool_name: Name of the tool (e.g., "objdump", "readelf")
derived_path: Path derived from idedata (may not exist for some platforms)
objdump_path: Path to objdump binary to derive other tool paths from
Returns:
Resolved path to the tool, or the original derived_path if it exists
"""
if derived_path and not Path(derived_path).exists():
found = find_tool(tool_name, objdump_path)
if found:
_LOGGER.debug(
"Derived %s path %s not found, using %s",
tool_name,
derived_path,
found,
)
return found
return derived_path
def find_tool( def find_tool(
tool_name: str, tool_name: str,
objdump_path: str | None = None, objdump_path: str | None = None,
@@ -24,7 +101,8 @@ def find_tool(
"""Find a toolchain tool by name. """Find a toolchain tool by name.
First tries to derive the tool path from objdump_path (if provided), First tries to derive the tool path from objdump_path (if provided),
then falls back to searching for platform-specific tools. then searches PlatformIO package directories (for cross-compile toolchains),
and finally falls back to searching for platform-specific tools in PATH.
Args: Args:
tool_name: Name of the tool (e.g., "objdump", "nm", "c++filt") tool_name: Name of the tool (e.g., "objdump", "nm", "c++filt")
@@ -43,7 +121,13 @@ def find_tool(
_LOGGER.debug("Found %s at: %s", tool_name, potential_path) _LOGGER.debug("Found %s at: %s", tool_name, potential_path)
return potential_path return potential_path
# Try platform-specific tools # Search in PlatformIO packages directory first (handles Zephyr SDK, etc.)
# This must come before PATH search because system tools (e.g., /usr/bin/objdump)
# are for the host architecture, not the target (ARM, Xtensa, etc.)
if found := _find_in_platformio_packages(tool_name):
return found
# Try platform-specific tools in PATH (fallback for when tools are installed globally)
for prefix in TOOLCHAIN_PREFIXES: for prefix in TOOLCHAIN_PREFIXES:
cmd = f"{prefix}{tool_name}" cmd = f"{prefix}{tool_name}"
try: try:
@@ -55,3 +139,35 @@ def find_tool(
_LOGGER.warning("Could not find %s tool", tool_name) _LOGGER.warning("Could not find %s tool", tool_name)
return None return None
def run_tool(
cmd: Sequence[str],
timeout: int = 30,
) -> subprocess.CompletedProcess[str] | None:
"""Run a toolchain command and return the result.
Args:
cmd: Command and arguments to run
timeout: Timeout in seconds
Returns:
CompletedProcess on success, None on failure
"""
try:
return subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=timeout,
check=False,
)
except subprocess.TimeoutExpired:
_LOGGER.warning("Command timed out: %s", " ".join(cmd))
return None
except FileNotFoundError:
_LOGGER.warning("Command not found: %s", cmd[0])
return None
except OSError as e:
_LOGGER.warning("Failed to run command %s: %s", cmd[0], e)
return None

View File

@@ -69,6 +69,7 @@ from esphome.cpp_types import ( # noqa: F401
JsonObjectConst, JsonObjectConst,
Parented, Parented,
PollingComponent, PollingComponent,
StringRef,
arduino_json_ns, arduino_json_ns,
bool_, bool_,
const_char_ptr, const_char_ptr,

View File

@@ -30,7 +30,9 @@ void A01nyubComponent::check_buffer_() {
ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters); ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters);
this->publish_state(meters); this->publish_state(meters);
} else { } else {
ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str()); char hex_buf[format_hex_pretty_size(4)];
ESP_LOGW(TAG, "Invalid data read from sensor: %s",
format_hex_pretty_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
} }
} else { } else {
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]); ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);

View File

@@ -29,7 +29,9 @@ void A02yyuwComponent::check_buffer_() {
ESP_LOGV(TAG, "Distance from sensor: %f mm", distance); ESP_LOGV(TAG, "Distance from sensor: %f mm", distance);
this->publish_state(distance); this->publish_state(distance);
} else { } else {
ESP_LOGW(TAG, "Invalid data read from sensor: %s", format_hex_pretty(this->buffer_).c_str()); char hex_buf[format_hex_pretty_size(4)];
ESP_LOGW(TAG, "Invalid data read from sensor: %s",
format_hex_pretty_to(hex_buf, this->buffer_.data(), this->buffer_.size()));
} }
} else { } else {
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]); ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);

View File

@@ -90,13 +90,16 @@ void AbsoluteHumidityComponent::loop() {
this->status_set_error(LOG_STR("Invalid saturation vapor pressure equation selection!")); this->status_set_error(LOG_STR("Invalid saturation vapor pressure equation selection!"));
return; return;
} }
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
// Calculate absolute humidity // Calculate absolute humidity
const float absolute_humidity = vapor_density(es, hr, temperature_k); const float absolute_humidity = vapor_density(es, hr, temperature_k);
ESP_LOGD(TAG,
"Saturation vapor pressure %f kPa\n"
"Publishing absolute humidity %f g/m³",
es, absolute_humidity);
// Publish absolute humidity // Publish absolute humidity
ESP_LOGD(TAG, "Publishing absolute humidity %f g/m³", absolute_humidity);
this->status_clear_warning(); this->status_clear_warning();
this->publish_state(absolute_humidity); this->publish_state(absolute_humidity);
} }

View File

@@ -1,5 +1,3 @@
#ifdef USE_ARDUINO
#include "ac_dimmer.h" #include "ac_dimmer.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
@@ -9,12 +7,12 @@
#ifdef USE_ESP8266 #ifdef USE_ESP8266
#include <core_esp8266_waveform.h> #include <core_esp8266_waveform.h>
#endif #endif
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include <esp32-hal-timer.h> #ifdef USE_ESP32
#include "hw_timer_esp_idf.h"
#endif #endif
namespace esphome { namespace esphome::ac_dimmer {
namespace ac_dimmer {
static const char *const TAG = "ac_dimmer"; static const char *const TAG = "ac_dimmer";
@@ -27,7 +25,14 @@ static AcDimmerDataStore *all_dimmers[32]; // NOLINT(cppcoreguidelines-avoid-no
/// However other factors like gate driver propagation time /// However other factors like gate driver propagation time
/// are also considered and a really low value is not important /// are also considered and a really low value is not important
/// See also: https://github.com/esphome/issues/issues/1632 /// See also: https://github.com/esphome/issues/issues/1632
static const uint32_t GATE_ENABLE_TIME = 50; static constexpr uint32_t GATE_ENABLE_TIME = 50;
#ifdef USE_ESP32
/// Timer frequency in Hz (1 MHz = 1µs resolution)
static constexpr uint32_t TIMER_FREQUENCY_HZ = 1000000;
/// Timer interrupt interval in microseconds
static constexpr uint64_t TIMER_INTERVAL_US = 50;
#endif
/// Function called from timer interrupt /// Function called from timer interrupt
/// Input is current time in microseconds (micros()) /// Input is current time in microseconds (micros())
@@ -154,7 +159,7 @@ void IRAM_ATTR HOT AcDimmerDataStore::s_gpio_intr(AcDimmerDataStore *store) {
#ifdef USE_ESP32 #ifdef USE_ESP32
// ESP32 implementation, uses basically the same code but needs to wrap // ESP32 implementation, uses basically the same code but needs to wrap
// timer_interrupt() function to auto-reschedule // timer_interrupt() function to auto-reschedule
static hw_timer_t *dimmer_timer = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) static HWTimer *dimmer_timer = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
void IRAM_ATTR HOT AcDimmerDataStore::s_timer_intr() { timer_interrupt(); } void IRAM_ATTR HOT AcDimmerDataStore::s_timer_intr() { timer_interrupt(); }
#endif #endif
@@ -194,15 +199,15 @@ void AcDimmer::setup() {
setTimer1Callback(&timer_interrupt); setTimer1Callback(&timer_interrupt);
#endif #endif
#ifdef USE_ESP32 #ifdef USE_ESP32
// timer frequency of 1mhz dimmer_timer = timer_begin(TIMER_FREQUENCY_HZ);
dimmer_timer = timerBegin(1000000); timer_attach_interrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr);
timerAttachInterrupt(dimmer_timer, &AcDimmerDataStore::s_timer_intr);
// For ESP32, we can't use dynamic interval calculation because the timerX functions // For ESP32, we can't use dynamic interval calculation because the timerX functions
// are not callable from ISR (placed in flash storage). // are not callable from ISR (placed in flash storage).
// Here we just use an interrupt firing every 50 µs. // Here we just use an interrupt firing every 50 µs.
timerAlarm(dimmer_timer, 50, true, 0); timer_alarm(dimmer_timer, TIMER_INTERVAL_US, true, 0);
#endif #endif
} }
void AcDimmer::write_state(float state) { void AcDimmer::write_state(float state) {
state = std::acos(1 - (2 * state)) / std::numbers::pi; // RMS power compensation state = std::acos(1 - (2 * state)) / std::numbers::pi; // RMS power compensation
auto new_value = static_cast<uint16_t>(roundf(state * 65535)); auto new_value = static_cast<uint16_t>(roundf(state * 65535));
@@ -210,14 +215,15 @@ void AcDimmer::write_state(float state) {
this->store_.init_cycle = this->init_with_half_cycle_; this->store_.init_cycle = this->init_with_half_cycle_;
this->store_.value = new_value; this->store_.value = new_value;
} }
void AcDimmer::dump_config() { void AcDimmer::dump_config() {
ESP_LOGCONFIG(TAG, "AcDimmer:");
LOG_PIN(" Output Pin: ", this->gate_pin_);
LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_);
ESP_LOGCONFIG(TAG, ESP_LOGCONFIG(TAG,
"AcDimmer:\n"
" Min Power: %.1f%%\n" " Min Power: %.1f%%\n"
" Init with half cycle: %s", " Init with half cycle: %s",
this->store_.min_power / 10.0f, YESNO(this->init_with_half_cycle_)); this->store_.min_power / 10.0f, YESNO(this->init_with_half_cycle_));
LOG_PIN(" Output Pin: ", this->gate_pin_);
LOG_PIN(" Zero-Cross Pin: ", this->zero_cross_pin_);
if (method_ == DIM_METHOD_LEADING_PULSE) { if (method_ == DIM_METHOD_LEADING_PULSE) {
ESP_LOGCONFIG(TAG, " Method: leading pulse"); ESP_LOGCONFIG(TAG, " Method: leading pulse");
} else if (method_ == DIM_METHOD_LEADING) { } else if (method_ == DIM_METHOD_LEADING) {
@@ -230,7 +236,4 @@ void AcDimmer::dump_config() {
ESP_LOGV(TAG, " Estimated Frequency: %.3fHz", 1e6f / this->store_.cycle_time_us / 2); ESP_LOGV(TAG, " Estimated Frequency: %.3fHz", 1e6f / this->store_.cycle_time_us / 2);
} }
} // namespace ac_dimmer } // namespace esphome::ac_dimmer
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -1,13 +1,10 @@
#pragma once #pragma once
#ifdef USE_ARDUINO
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/components/output/float_output.h" #include "esphome/components/output/float_output.h"
namespace esphome { namespace esphome::ac_dimmer {
namespace ac_dimmer {
enum DimMethod { DIM_METHOD_LEADING_PULSE = 0, DIM_METHOD_LEADING, DIM_METHOD_TRAILING }; enum DimMethod { DIM_METHOD_LEADING_PULSE = 0, DIM_METHOD_LEADING, DIM_METHOD_TRAILING };
@@ -64,7 +61,4 @@ class AcDimmer : public output::FloatOutput, public Component {
DimMethod method_; DimMethod method_;
}; };
} // namespace ac_dimmer } // namespace esphome::ac_dimmer
} // namespace esphome
#endif // USE_ARDUINO

View File

@@ -0,0 +1,152 @@
#ifdef USE_ESP32
#include "hw_timer_esp_idf.h"
#include "freertos/FreeRTOS.h"
#include "esphome/core/log.h"
#include "driver/gptimer.h"
#include "esp_clk_tree.h"
#include "soc/clk_tree_defs.h"
static const char *const TAG = "hw_timer_esp_idf";
namespace esphome::ac_dimmer {
// GPTimer divider constraints from ESP-IDF documentation
static constexpr uint32_t GPTIMER_DIVIDER_MIN = 2;
static constexpr uint32_t GPTIMER_DIVIDER_MAX = 65536;
using voidFuncPtr = void (*)();
using voidFuncPtrArg = void (*)(void *);
struct InterruptConfigT {
voidFuncPtr fn{nullptr};
void *arg{nullptr};
};
struct HWTimer {
gptimer_handle_t timer_handle{nullptr};
InterruptConfigT interrupt_handle{};
bool timer_started{false};
};
HWTimer *timer_begin(uint32_t frequency) {
esp_err_t err = ESP_OK;
uint32_t counter_src_hz = 0;
uint32_t divider = 0;
soc_module_clk_t clk;
for (auto clk_candidate : SOC_GPTIMER_CLKS) {
clk = clk_candidate;
esp_clk_tree_src_get_freq_hz(clk, ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED, &counter_src_hz);
divider = counter_src_hz / frequency;
if ((divider >= GPTIMER_DIVIDER_MIN) && (divider <= GPTIMER_DIVIDER_MAX)) {
break;
} else {
divider = 0;
}
}
if (divider == 0) {
ESP_LOGE(TAG, "Resolution not possible; aborting");
return nullptr;
}
gptimer_config_t config = {
.clk_src = static_cast<gptimer_clock_source_t>(clk),
.direction = GPTIMER_COUNT_UP,
.resolution_hz = frequency,
.flags = {.intr_shared = true},
};
HWTimer *timer = new HWTimer();
err = gptimer_new_timer(&config, &timer->timer_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "GPTimer creation failed; error %d", err);
delete timer;
return nullptr;
}
err = gptimer_enable(timer->timer_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "GPTimer enable failed; error %d", err);
gptimer_del_timer(timer->timer_handle);
delete timer;
return nullptr;
}
err = gptimer_start(timer->timer_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "GPTimer start failed; error %d", err);
gptimer_disable(timer->timer_handle);
gptimer_del_timer(timer->timer_handle);
delete timer;
return nullptr;
}
timer->timer_started = true;
return timer;
}
bool IRAM_ATTR timer_fn_wrapper(gptimer_handle_t timer, const gptimer_alarm_event_data_t *edata, void *args) {
auto *isr = static_cast<InterruptConfigT *>(args);
if (isr->fn) {
if (isr->arg) {
reinterpret_cast<voidFuncPtrArg>(isr->fn)(isr->arg);
} else {
isr->fn();
}
}
// Return false to indicate that no higher-priority task was woken and no context switch is requested.
return false;
}
static void timer_attach_interrupt_functional_arg(HWTimer *timer, void (*user_func)(void *), void *arg) {
if (timer == nullptr) {
ESP_LOGE(TAG, "Timer handle is nullptr");
return;
}
gptimer_event_callbacks_t cbs = {
.on_alarm = timer_fn_wrapper,
};
timer->interrupt_handle.fn = reinterpret_cast<voidFuncPtr>(user_func);
timer->interrupt_handle.arg = arg;
if (timer->timer_started) {
gptimer_stop(timer->timer_handle);
}
gptimer_disable(timer->timer_handle);
esp_err_t err = gptimer_register_event_callbacks(timer->timer_handle, &cbs, &timer->interrupt_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Timer Attach Interrupt failed; error %d", err);
}
gptimer_enable(timer->timer_handle);
if (timer->timer_started) {
gptimer_start(timer->timer_handle);
}
}
void timer_attach_interrupt(HWTimer *timer, voidFuncPtr user_func) {
timer_attach_interrupt_functional_arg(timer, reinterpret_cast<voidFuncPtrArg>(user_func), nullptr);
}
void timer_alarm(HWTimer *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count) {
if (timer == nullptr) {
ESP_LOGE(TAG, "Timer handle is nullptr");
return;
}
gptimer_alarm_config_t alarm_cfg = {
.alarm_count = alarm_value,
.reload_count = reload_count,
.flags = {.auto_reload_on_alarm = autoreload},
};
esp_err_t err = gptimer_set_alarm_action(timer->timer_handle, &alarm_cfg);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Timer Alarm Write failed; error %d", err);
}
}
} // namespace esphome::ac_dimmer
#endif

View File

@@ -0,0 +1,17 @@
#pragma once
#ifdef USE_ESP32
#include "driver/gptimer_types.h"
namespace esphome::ac_dimmer {
struct HWTimer;
HWTimer *timer_begin(uint32_t frequency);
void timer_attach_interrupt(HWTimer *timer, void (*user_func)());
void timer_alarm(HWTimer *timer, uint64_t alarm_value, bool autoreload, uint64_t reload_count);
} // namespace esphome::ac_dimmer
#endif

View File

@@ -3,6 +3,7 @@ import esphome.codegen as cg
from esphome.components import output from esphome.components import output
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER from esphome.const import CONF_ID, CONF_METHOD, CONF_MIN_POWER
from esphome.core import CORE
CODEOWNERS = ["@glmnet"] CODEOWNERS = ["@glmnet"]
@@ -31,11 +32,16 @@ CONFIG_SCHEMA = cv.All(
), ),
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.only_with_arduino,
) )
async def to_code(config): async def to_code(config):
if CORE.is_esp8266:
# ac_dimmer uses setTimer1Callback which requires the waveform generator
from esphome.components.esp8266.const import require_waveform
require_waveform()
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)

View File

@@ -121,23 +121,21 @@ void ADCSensor::setup() {
void ADCSensor::dump_config() { void ADCSensor::dump_config() {
LOG_SENSOR("", "ADC Sensor", this); LOG_SENSOR("", "ADC Sensor", this);
LOG_PIN(" Pin: ", this->pin_); LOG_PIN(" Pin: ", this->pin_);
ESP_LOGCONFIG(TAG,
" Channel: %d\n"
" Unit: %s\n"
" Attenuation: %s\n"
" Samples: %i\n"
" Sampling mode: %s",
this->channel_, LOG_STR_ARG(adc_unit_to_str(this->adc_unit_)),
this->autorange_ ? "Auto" : LOG_STR_ARG(attenuation_to_str(this->attenuation_)), this->sample_count_,
LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
ESP_LOGCONFIG( ESP_LOGCONFIG(
TAG, TAG,
" Channel: %d\n"
" Unit: %s\n"
" Attenuation: %s\n"
" Samples: %i\n"
" Sampling mode: %s\n"
" Setup Status:\n" " Setup Status:\n"
" Handle Init: %s\n" " Handle Init: %s\n"
" Config: %s\n" " Config: %s\n"
" Calibration: %s\n" " Calibration: %s\n"
" Overall Init: %s", " Overall Init: %s",
this->channel_, LOG_STR_ARG(adc_unit_to_str(this->adc_unit_)),
this->autorange_ ? "Auto" : LOG_STR_ARG(attenuation_to_str(this->attenuation_)), this->sample_count_,
LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)),
this->setup_flags_.handle_init_complete ? "OK" : "FAILED", this->setup_flags_.config_complete ? "OK" : "FAILED", this->setup_flags_.handle_init_complete ? "OK" : "FAILED", this->setup_flags_.config_complete ? "OK" : "FAILED",
this->setup_flags_.calibration_complete ? "OK" : "FAILED", this->setup_flags_.init_complete ? "OK" : "FAILED"); this->setup_flags_.calibration_complete ? "OK" : "FAILED", this->setup_flags_.init_complete ? "OK" : "FAILED");

View File

@@ -25,11 +25,13 @@ class AddressableLightDisplay : public display::DisplayBuffer {
if (enabled_ && !enabled) { // enabled -> disabled if (enabled_ && !enabled) { // enabled -> disabled
// - Tell the parent light to refresh, effectively wiping the display. Also // - Tell the parent light to refresh, effectively wiping the display. Also
// restores the previous effect (if any). // restores the previous effect (if any).
light_state_->make_call().set_effect(this->last_effect_).perform(); if (this->last_effect_index_.has_value()) {
light_state_->make_call().set_effect(*this->last_effect_index_).perform();
}
} else if (!enabled_ && enabled) { // disabled -> enabled } else if (!enabled_ && enabled) { // disabled -> enabled
// - Save the current effect. // - Save the current effect index.
this->last_effect_ = light_state_->get_effect_name(); this->last_effect_index_ = light_state_->get_current_effect_index();
// - Disable any current effect. // - Disable any current effect.
light_state_->make_call().set_effect(0).perform(); light_state_->make_call().set_effect(0).perform();
} }
@@ -56,7 +58,7 @@ class AddressableLightDisplay : public display::DisplayBuffer {
int32_t width_; int32_t width_;
int32_t height_; int32_t height_;
std::vector<Color> addressable_light_buffer_; std::vector<Color> addressable_light_buffer_;
optional<std::string> last_effect_; optional<uint32_t> last_effect_index_;
optional<std::function<int(int, int)>> pixel_mapper_f_; optional<std::function<int(int, int)>> pixel_mapper_f_;
}; };
} // namespace addressable_light } // namespace addressable_light

View File

@@ -162,11 +162,13 @@ void ADE7880::update() {
} }
void ADE7880::dump_config() { void ADE7880::dump_config() {
ESP_LOGCONFIG(TAG, "ADE7880:"); ESP_LOGCONFIG(TAG,
"ADE7880:\n"
" Frequency: %.0f Hz",
this->frequency_);
LOG_PIN(" IRQ0 Pin: ", this->irq0_pin_); LOG_PIN(" IRQ0 Pin: ", this->irq0_pin_);
LOG_PIN(" IRQ1 Pin: ", this->irq1_pin_); LOG_PIN(" IRQ1 Pin: ", this->irq1_pin_);
LOG_PIN(" RESET Pin: ", this->reset_pin_); LOG_PIN(" RESET Pin: ", this->reset_pin_);
ESP_LOGCONFIG(TAG, " Frequency: %.0f Hz", this->frequency_);
if (this->channel_a_ != nullptr) { if (this->channel_a_ != nullptr) {
ESP_LOGCONFIG(TAG, " Phase A:"); ESP_LOGCONFIG(TAG, " Phase A:");

View File

@@ -227,7 +227,7 @@ CONFIG_SCHEMA = cv.All(
{ {
cv.GenerateID(): cv.declare_id(ADE7880), cv.GenerateID(): cv.declare_id(ADE7880),
cv.Optional(CONF_FREQUENCY, default="50Hz"): cv.All( cv.Optional(CONF_FREQUENCY, default="50Hz"): cv.All(
cv.frequency, cv.Range(min=45.0, max=66.0) cv.frequency, cv.float_range(min=45.0, max=66.0)
), ),
cv.Optional(CONF_IRQ0_PIN): pins.internal_gpio_input_pin_schema, cv.Optional(CONF_IRQ0_PIN): pins.internal_gpio_input_pin_schema,
cv.Required(CONF_IRQ1_PIN): pins.internal_gpio_input_pin_schema, cv.Required(CONF_IRQ1_PIN): pins.internal_gpio_input_pin_schema,

View File

@@ -21,10 +21,12 @@ void ADS1115Sensor::update() {
void ADS1115Sensor::dump_config() { void ADS1115Sensor::dump_config() {
LOG_SENSOR(" ", "ADS1115 Sensor", this); LOG_SENSOR(" ", "ADS1115 Sensor", this);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); ESP_LOGCONFIG(TAG,
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); " Multiplexer: %u\n"
ESP_LOGCONFIG(TAG, " Resolution: %u", this->resolution_); " Gain: %u\n"
ESP_LOGCONFIG(TAG, " Sample rate: %u", this->samplerate_); " Resolution: %u\n"
" Sample rate: %u",
this->multiplexer_, this->gain_, this->resolution_, this->samplerate_);
} }
} // namespace ads1115 } // namespace ads1115

View File

@@ -9,8 +9,10 @@ static const char *const TAG = "ads1118.sensor";
void ADS1118Sensor::dump_config() { void ADS1118Sensor::dump_config() {
LOG_SENSOR(" ", "ADS1118 Sensor", this); LOG_SENSOR(" ", "ADS1118 Sensor", this);
ESP_LOGCONFIG(TAG, " Multiplexer: %u", this->multiplexer_); ESP_LOGCONFIG(TAG,
ESP_LOGCONFIG(TAG, " Gain: %u", this->gain_); " Multiplexer: %u\n"
" Gain: %u",
this->multiplexer_, this->gain_);
} }
float ADS1118Sensor::sample() { float ADS1118Sensor::sample() {

View File

@@ -20,7 +20,8 @@ bool AirthingsListener::parse_device(const esp32_ble_tracker::ESPBTDevice &devic
sn |= ((uint32_t) it.data[2] << 16); sn |= ((uint32_t) it.data[2] << 16);
sn |= ((uint32_t) it.data[3] << 24); sn |= ((uint32_t) it.data[3] << 24);
ESP_LOGD(TAG, "Found AirThings device Serial:%" PRIu32 " (MAC: %s)", sn, device.address_str().c_str()); char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
ESP_LOGD(TAG, "Found AirThings device Serial:%" PRIu32 " (MAC: %s)", sn, device.address_str_to(addr_buf));
return true; return true;
} }
} }

View File

@@ -1,4 +1,5 @@
#include "airthings_wave_base.h" #include "airthings_wave_base.h"
#include "esphome/components/esp32_ble/ble_uuid.h"
// All information related to reading battery information came from the sensors.airthings_wave // All information related to reading battery information came from the sensors.airthings_wave
// project by Sverre Hamre (https://github.com/sverrham/sensor.airthings_wave) // project by Sverre Hamre (https://github.com/sverrham/sensor.airthings_wave)
@@ -93,8 +94,10 @@ void AirthingsWaveBase::update() {
bool AirthingsWaveBase::request_read_values_() { bool AirthingsWaveBase::request_read_values_() {
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_);
if (chr == nullptr) { if (chr == nullptr) {
ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), char service_buf[esp32_ble::UUID_STR_LEN];
this->sensors_data_characteristic_uuid_.to_string().c_str()); char char_buf[esp32_ble::UUID_STR_LEN];
ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_str(service_buf),
this->sensors_data_characteristic_uuid_.to_str(char_buf));
return false; return false;
} }
@@ -117,17 +120,20 @@ bool AirthingsWaveBase::request_battery_() {
auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->access_control_point_characteristic_uuid_); auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->access_control_point_characteristic_uuid_);
if (chr == nullptr) { if (chr == nullptr) {
char service_buf[esp32_ble::UUID_STR_LEN];
char char_buf[esp32_ble::UUID_STR_LEN];
ESP_LOGW(TAG, "No access control point characteristic found at service %s char %s", ESP_LOGW(TAG, "No access control point characteristic found at service %s char %s",
this->service_uuid_.to_string().c_str(), this->service_uuid_.to_str(service_buf), this->access_control_point_characteristic_uuid_.to_str(char_buf));
this->access_control_point_characteristic_uuid_.to_string().c_str());
return false; return false;
} }
auto *descr = this->parent()->get_descriptor(this->service_uuid_, this->access_control_point_characteristic_uuid_, auto *descr = this->parent()->get_descriptor(this->service_uuid_, this->access_control_point_characteristic_uuid_,
CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_UUID); CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_UUID);
if (descr == nullptr) { if (descr == nullptr) {
ESP_LOGW(TAG, "No CCC descriptor found at service %s char %s", this->service_uuid_.to_string().c_str(), char service_buf[esp32_ble::UUID_STR_LEN];
this->access_control_point_characteristic_uuid_.to_string().c_str()); char char_buf[esp32_ble::UUID_STR_LEN];
ESP_LOGW(TAG, "No CCC descriptor found at service %s char %s", this->service_uuid_.to_str(service_buf),
this->access_control_point_characteristic_uuid_.to_str(char_buf));
return false; return false;
} }

View File

@@ -8,8 +8,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
static const char *const TAG = "alarm_control_panel"; static const char *const TAG = "alarm_control_panel";
@@ -32,7 +31,8 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) {
this->last_update_ = millis(); this->last_update_ = millis();
if (state != this->current_state_) { if (state != this->current_state_) {
auto prev_state = this->current_state_; auto prev_state = this->current_state_;
ESP_LOGD(TAG, "Set state to: %s, previous: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(state)), ESP_LOGD(TAG, "'%s' >> %s (was %s)", this->get_name().c_str(),
LOG_STR_ARG(alarm_control_panel_state_to_string(state)),
LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state))); LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state)));
this->current_state_ = state; this->current_state_ = state;
// Single state callback - triggers check get_state() for specific states // Single state callback - triggers check get_state() for specific states
@@ -67,53 +67,29 @@ void AlarmControlPanel::add_on_ready_callback(std::function<void()> &&callback)
this->ready_callback_.add(std::move(callback)); this->ready_callback_.add(std::move(callback));
} }
void AlarmControlPanel::arm_away(optional<std::string> code) { void AlarmControlPanel::arm_with_code_(AlarmControlPanelCall &(AlarmControlPanelCall::*arm_method)(),
const char *code) {
auto call = this->make_call(); auto call = this->make_call();
call.arm_away(); (call.*arm_method)();
if (code.has_value()) if (code != nullptr)
call.set_code(code.value()); call.set_code(code);
call.perform(); call.perform();
} }
void AlarmControlPanel::arm_home(optional<std::string> code) { void AlarmControlPanel::arm_away(const char *code) { this->arm_with_code_(&AlarmControlPanelCall::arm_away, code); }
auto call = this->make_call();
call.arm_home(); void AlarmControlPanel::arm_home(const char *code) { this->arm_with_code_(&AlarmControlPanelCall::arm_home, code); }
if (code.has_value())
call.set_code(code.value()); void AlarmControlPanel::arm_night(const char *code) { this->arm_with_code_(&AlarmControlPanelCall::arm_night, code); }
call.perform();
void AlarmControlPanel::arm_vacation(const char *code) {
this->arm_with_code_(&AlarmControlPanelCall::arm_vacation, code);
} }
void AlarmControlPanel::arm_night(optional<std::string> code) { void AlarmControlPanel::arm_custom_bypass(const char *code) {
auto call = this->make_call(); this->arm_with_code_(&AlarmControlPanelCall::arm_custom_bypass, code);
call.arm_night();
if (code.has_value())
call.set_code(code.value());
call.perform();
} }
void AlarmControlPanel::arm_vacation(optional<std::string> code) { void AlarmControlPanel::disarm(const char *code) { this->arm_with_code_(&AlarmControlPanelCall::disarm, code); }
auto call = this->make_call();
call.arm_vacation();
if (code.has_value())
call.set_code(code.value());
call.perform();
}
void AlarmControlPanel::arm_custom_bypass(optional<std::string> code) { } // namespace esphome::alarm_control_panel
auto call = this->make_call();
call.arm_custom_bypass();
if (code.has_value())
call.set_code(code.value());
call.perform();
}
void AlarmControlPanel::disarm(optional<std::string> code) {
auto call = this->make_call();
call.disarm();
if (code.has_value())
call.set_code(code.value());
call.perform();
}
} // namespace alarm_control_panel
} // namespace esphome

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <map>
#include "alarm_control_panel_call.h" #include "alarm_control_panel_call.h"
#include "alarm_control_panel_state.h" #include "alarm_control_panel_state.h"
@@ -9,8 +7,7 @@
#include "esphome/core/entity_base.h" #include "esphome/core/entity_base.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
enum AlarmControlPanelFeature : uint8_t { enum AlarmControlPanelFeature : uint8_t {
// Matches Home Assistant values // Matches Home Assistant values
@@ -79,37 +76,53 @@ class AlarmControlPanel : public EntityBase {
* *
* @param code The code * @param code The code
*/ */
void arm_away(optional<std::string> code = nullopt); void arm_away(const char *code = nullptr);
void arm_away(const optional<std::string> &code) {
this->arm_away(code.has_value() ? code.value().c_str() : nullptr);
}
/** arm the alarm in home mode /** arm the alarm in home mode
* *
* @param code The code * @param code The code
*/ */
void arm_home(optional<std::string> code = nullopt); void arm_home(const char *code = nullptr);
void arm_home(const optional<std::string> &code) {
this->arm_home(code.has_value() ? code.value().c_str() : nullptr);
}
/** arm the alarm in night mode /** arm the alarm in night mode
* *
* @param code The code * @param code The code
*/ */
void arm_night(optional<std::string> code = nullopt); void arm_night(const char *code = nullptr);
void arm_night(const optional<std::string> &code) {
this->arm_night(code.has_value() ? code.value().c_str() : nullptr);
}
/** arm the alarm in vacation mode /** arm the alarm in vacation mode
* *
* @param code The code * @param code The code
*/ */
void arm_vacation(optional<std::string> code = nullopt); void arm_vacation(const char *code = nullptr);
void arm_vacation(const optional<std::string> &code) {
this->arm_vacation(code.has_value() ? code.value().c_str() : nullptr);
}
/** arm the alarm in custom bypass mode /** arm the alarm in custom bypass mode
* *
* @param code The code * @param code The code
*/ */
void arm_custom_bypass(optional<std::string> code = nullopt); void arm_custom_bypass(const char *code = nullptr);
void arm_custom_bypass(const optional<std::string> &code) {
this->arm_custom_bypass(code.has_value() ? code.value().c_str() : nullptr);
}
/** disarm the alarm /** disarm the alarm
* *
* @param code The code * @param code The code
*/ */
void disarm(optional<std::string> code = nullopt); void disarm(const char *code = nullptr);
void disarm(const optional<std::string> &code) { this->disarm(code.has_value() ? code.value().c_str() : nullptr); }
/** Get the state /** Get the state
* *
@@ -121,6 +134,8 @@ class AlarmControlPanel : public EntityBase {
protected: protected:
friend AlarmControlPanelCall; friend AlarmControlPanelCall;
// Helper to reduce code duplication for arm/disarm methods
void arm_with_code_(AlarmControlPanelCall &(AlarmControlPanelCall::*arm_method)(), const char *code);
// in order to store last panel state in flash // in order to store last panel state in flash
ESPPreferenceObject pref_; ESPPreferenceObject pref_;
// current state // current state
@@ -132,14 +147,13 @@ class AlarmControlPanel : public EntityBase {
// the call control function // the call control function
virtual void control(const AlarmControlPanelCall &call) = 0; virtual void control(const AlarmControlPanelCall &call) = 0;
// state callback - triggers check get_state() for specific state // state callback - triggers check get_state() for specific state
CallbackManager<void()> state_callback_{}; LazyCallbackManager<void()> state_callback_{};
// clear callback - fires when leaving TRIGGERED state // clear callback - fires when leaving TRIGGERED state
CallbackManager<void()> cleared_callback_{}; LazyCallbackManager<void()> cleared_callback_{};
// chime callback // chime callback
CallbackManager<void()> chime_callback_{}; LazyCallbackManager<void()> chime_callback_{};
// ready callback // ready callback
CallbackManager<void()> ready_callback_{}; LazyCallbackManager<void()> ready_callback_{};
}; };
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -4,15 +4,16 @@
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
static const char *const TAG = "alarm_control_panel"; static const char *const TAG = "alarm_control_panel";
AlarmControlPanelCall::AlarmControlPanelCall(AlarmControlPanel *parent) : parent_(parent) {} AlarmControlPanelCall::AlarmControlPanelCall(AlarmControlPanel *parent) : parent_(parent) {}
AlarmControlPanelCall &AlarmControlPanelCall::set_code(const std::string &code) { AlarmControlPanelCall &AlarmControlPanelCall::set_code(const char *code) {
this->code_ = code; if (code != nullptr) {
this->code_ = std::string(code);
}
return *this; return *this;
} }
@@ -99,5 +100,4 @@ void AlarmControlPanelCall::perform() {
} }
} }
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -6,8 +6,7 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
class AlarmControlPanel; class AlarmControlPanel;
@@ -15,7 +14,8 @@ class AlarmControlPanelCall {
public: public:
AlarmControlPanelCall(AlarmControlPanel *parent); AlarmControlPanelCall(AlarmControlPanel *parent);
AlarmControlPanelCall &set_code(const std::string &code); AlarmControlPanelCall &set_code(const char *code);
AlarmControlPanelCall &set_code(const std::string &code) { return this->set_code(code.c_str()); }
AlarmControlPanelCall &arm_away(); AlarmControlPanelCall &arm_away();
AlarmControlPanelCall &arm_home(); AlarmControlPanelCall &arm_home();
AlarmControlPanelCall &arm_night(); AlarmControlPanelCall &arm_night();
@@ -36,5 +36,4 @@ class AlarmControlPanelCall {
void validate_(); void validate_();
}; };
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -1,7 +1,6 @@
#include "alarm_control_panel_state.h" #include "alarm_control_panel_state.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state) { const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state) {
switch (state) { switch (state) {
@@ -30,5 +29,4 @@ const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState stat
} }
} }
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -3,8 +3,7 @@
#include <cstdint> #include <cstdint>
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
enum AlarmControlPanelState : uint8_t { enum AlarmControlPanelState : uint8_t {
ACP_STATE_DISARMED = 0, ACP_STATE_DISARMED = 0,
@@ -25,5 +24,4 @@ enum AlarmControlPanelState : uint8_t {
*/ */
const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state); const LogString *alarm_control_panel_state_to_string(AlarmControlPanelState state);
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -3,8 +3,7 @@
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
#include "alarm_control_panel.h" #include "alarm_control_panel.h"
namespace esphome { namespace esphome::alarm_control_panel {
namespace alarm_control_panel {
/// Trigger on any state change /// Trigger on any state change
class StateTrigger : public Trigger<> { class StateTrigger : public Trigger<> {
@@ -67,15 +66,7 @@ template<typename... Ts> class ArmAwayAction : public Action<Ts...> {
TEMPLATABLE_VALUE(std::string, code) TEMPLATABLE_VALUE(std::string, code)
void play(const Ts &...x) override { void play(const Ts &...x) override { this->alarm_control_panel_->arm_away(this->code_.optional_value(x...)); }
auto call = this->alarm_control_panel_->make_call();
auto code = this->code_.optional_value(x...);
if (code.has_value()) {
call.set_code(code.value());
}
call.arm_away();
call.perform();
}
protected: protected:
AlarmControlPanel *alarm_control_panel_; AlarmControlPanel *alarm_control_panel_;
@@ -87,15 +78,7 @@ template<typename... Ts> class ArmHomeAction : public Action<Ts...> {
TEMPLATABLE_VALUE(std::string, code) TEMPLATABLE_VALUE(std::string, code)
void play(const Ts &...x) override { void play(const Ts &...x) override { this->alarm_control_panel_->arm_home(this->code_.optional_value(x...)); }
auto call = this->alarm_control_panel_->make_call();
auto code = this->code_.optional_value(x...);
if (code.has_value()) {
call.set_code(code.value());
}
call.arm_home();
call.perform();
}
protected: protected:
AlarmControlPanel *alarm_control_panel_; AlarmControlPanel *alarm_control_panel_;
@@ -107,15 +90,7 @@ template<typename... Ts> class ArmNightAction : public Action<Ts...> {
TEMPLATABLE_VALUE(std::string, code) TEMPLATABLE_VALUE(std::string, code)
void play(const Ts &...x) override { void play(const Ts &...x) override { this->alarm_control_panel_->arm_night(this->code_.optional_value(x...)); }
auto call = this->alarm_control_panel_->make_call();
auto code = this->code_.optional_value(x...);
if (code.has_value()) {
call.set_code(code.value());
}
call.arm_night();
call.perform();
}
protected: protected:
AlarmControlPanel *alarm_control_panel_; AlarmControlPanel *alarm_control_panel_;
@@ -165,5 +140,4 @@ template<typename... Ts> class AlarmControlPanelCondition : public Condition<Ts.
AlarmControlPanel *parent_; AlarmControlPanel *parent_;
}; };
} // namespace alarm_control_panel } // namespace esphome::alarm_control_panel
} // namespace esphome

View File

@@ -15,10 +15,8 @@ namespace alpha3 {
namespace espbt = esphome::esp32_ble_tracker; namespace espbt = esphome::esp32_ble_tracker;
static const espbt::ESPBTUUID ALPHA3_GENI_SERVICE_UUID = espbt::ESPBTUUID::from_uint16(0xfe5d); static const espbt::ESPBTUUID ALPHA3_GENI_SERVICE_UUID = espbt::ESPBTUUID::from_uint16(0xfe5d);
static const espbt::ESPBTUUID ALPHA3_GENI_CHARACTERISTIC_UUID = static const espbt::ESPBTUUID ALPHA3_GENI_CHARACTERISTIC_UUID = espbt::ESPBTUUID::from_raw(
espbt::ESPBTUUID::from_raw({static_cast<char>(0xa9), 0x7b, static_cast<char>(0xb8), static_cast<char>(0x85), 0x0, {0xa9, 0x7b, 0xb8, 0x85, 0x00, 0x1a, 0x28, 0xaa, 0x2a, 0x43, 0x6e, 0x03, 0xd1, 0xff, 0x9c, 0x85});
0x1a, 0x28, static_cast<char>(0xaa), 0x2a, 0x43, 0x6e, 0x3, static_cast<char>(0xd1),
static_cast<char>(0xff), static_cast<char>(0x9c), static_cast<char>(0x85)});
static const int16_t GENI_RESPONSE_HEADER_LENGTH = 13; static const int16_t GENI_RESPONSE_HEADER_LENGTH = 13;
static const size_t GENI_RESPONSE_TYPE_LENGTH = 8; static const size_t GENI_RESPONSE_TYPE_LENGTH = 8;

View File

@@ -1,21 +1,12 @@
#include "am43_base.h" #include "am43_base.h"
#include "esphome/core/helpers.h"
#include <cstring> #include <cstring>
#include <cstdio>
namespace esphome { namespace esphome {
namespace am43 { namespace am43 {
const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a}; const uint8_t START_PACKET[5] = {0x00, 0xff, 0x00, 0x00, 0x9a};
std::string pkt_to_hex(const uint8_t *data, uint16_t len) {
char buf[64];
memset(buf, 0, 64);
for (int i = 0; i < len; i++)
sprintf(&buf[i * 2], "%02x", data[i]);
std::string ret = buf;
return ret;
}
Am43Packet *Am43Encoder::get_battery_level_request() { Am43Packet *Am43Encoder::get_battery_level_request() {
uint8_t data = 0x1; uint8_t data = 0x1;
return this->encode_(0xA2, &data, 1); return this->encode_(0xA2, &data, 1);
@@ -73,7 +64,9 @@ Am43Packet *Am43Encoder::encode_(uint8_t command, uint8_t *data, uint8_t length)
memcpy(&this->packet_.data[7], data, length); memcpy(&this->packet_.data[7], data, length);
this->packet_.length = length + 7; this->packet_.length = length + 7;
this->checksum_(); this->checksum_();
ESP_LOGV("am43", "ENC(%d): 0x%s", packet_.length, pkt_to_hex(packet_.data, packet_.length).c_str()); char hex_buf[format_hex_size(sizeof(this->packet_.data))];
ESP_LOGV("am43", "ENC(%d): 0x%s", this->packet_.length,
format_hex_to(hex_buf, this->packet_.data, this->packet_.length));
return &this->packet_; return &this->packet_;
} }
@@ -88,7 +81,8 @@ void Am43Decoder::decode(const uint8_t *data, uint16_t length) {
this->has_set_state_response_ = false; this->has_set_state_response_ = false;
this->has_position_ = false; this->has_position_ = false;
this->has_pin_response_ = false; this->has_pin_response_ = false;
ESP_LOGV("am43", "DEC(%d): 0x%s", length, pkt_to_hex(data, length).c_str()); char hex_buf[format_hex_size(24)]; // Max expected packet size
ESP_LOGV("am43", "DEC(%d): 0x%s", length, format_hex_to(hex_buf, data, length));
if (length < 2 || data[0] != 0x9a) if (length < 2 || data[0] != 0x9a)
return; return;

View File

@@ -67,8 +67,10 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
case ESP_GATTC_SEARCH_CMPL_EVT: { case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID); auto *chr = this->parent_->get_characteristic(ANOVA_SERVICE_UUID, ANOVA_CHARACTERISTIC_UUID);
if (chr == nullptr) { if (chr == nullptr) {
ESP_LOGW(TAG, "[%s] No control service found at device, not an Anova..?", this->get_name().c_str()); ESP_LOGW(TAG,
ESP_LOGW(TAG, "[%s] Note, this component does not currently support Anova Nano.", this->get_name().c_str()); "[%s] No control service found at device, not an Anova..?\n"
"[%s] Note, this component does not currently support Anova Nano.",
this->get_name().c_str(), this->get_name().c_str());
break; break;
} }
this->char_handle_ = chr->handle; this->char_handle_ = chr->handle;

View File

@@ -18,31 +18,31 @@ AnovaPacket *AnovaCodec::clean_packet_() {
AnovaPacket *AnovaCodec::get_read_device_status_request() { AnovaPacket *AnovaCodec::get_read_device_status_request() {
this->current_query_ = READ_DEVICE_STATUS; this->current_query_ = READ_DEVICE_STATUS;
sprintf((char *) this->packet_.data, "%s", CMD_READ_DEVICE_STATUS); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_DEVICE_STATUS);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_read_target_temp_request() { AnovaPacket *AnovaCodec::get_read_target_temp_request() {
this->current_query_ = READ_TARGET_TEMPERATURE; this->current_query_ = READ_TARGET_TEMPERATURE;
sprintf((char *) this->packet_.data, "%s", CMD_READ_TARGET_TEMP); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_TARGET_TEMP);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_read_current_temp_request() { AnovaPacket *AnovaCodec::get_read_current_temp_request() {
this->current_query_ = READ_CURRENT_TEMPERATURE; this->current_query_ = READ_CURRENT_TEMPERATURE;
sprintf((char *) this->packet_.data, "%s", CMD_READ_CURRENT_TEMP); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_CURRENT_TEMP);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_read_unit_request() { AnovaPacket *AnovaCodec::get_read_unit_request() {
this->current_query_ = READ_UNIT; this->current_query_ = READ_UNIT;
sprintf((char *) this->packet_.data, "%s", CMD_READ_UNIT); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_UNIT);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_read_data_request() { AnovaPacket *AnovaCodec::get_read_data_request() {
this->current_query_ = READ_DATA; this->current_query_ = READ_DATA;
sprintf((char *) this->packet_.data, "%s", CMD_READ_DATA); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_READ_DATA);
return this->clean_packet_(); return this->clean_packet_();
} }
@@ -50,25 +50,25 @@ AnovaPacket *AnovaCodec::get_set_target_temp_request(float temperature) {
this->current_query_ = SET_TARGET_TEMPERATURE; this->current_query_ = SET_TARGET_TEMPERATURE;
if (this->fahrenheit_) if (this->fahrenheit_)
temperature = ctof(temperature); temperature = ctof(temperature);
sprintf((char *) this->packet_.data, CMD_SET_TARGET_TEMP, temperature); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), CMD_SET_TARGET_TEMP, temperature);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_set_unit_request(char unit) { AnovaPacket *AnovaCodec::get_set_unit_request(char unit) {
this->current_query_ = SET_UNIT; this->current_query_ = SET_UNIT;
sprintf((char *) this->packet_.data, CMD_SET_TEMP_UNIT, unit); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), CMD_SET_TEMP_UNIT, unit);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_start_request() { AnovaPacket *AnovaCodec::get_start_request() {
this->current_query_ = START; this->current_query_ = START;
sprintf((char *) this->packet_.data, CMD_START); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_START);
return this->clean_packet_(); return this->clean_packet_();
} }
AnovaPacket *AnovaCodec::get_stop_request() { AnovaPacket *AnovaCodec::get_stop_request() {
this->current_query_ = STOP; this->current_query_ = STOP;
sprintf((char *) this->packet_.data, CMD_STOP); snprintf((char *) this->packet_.data, sizeof(this->packet_.data), "%s", CMD_STOP);
return this->clean_packet_(); return this->clean_packet_();
} }

View File

@@ -4,6 +4,7 @@ import logging
from esphome import automation from esphome import automation
from esphome.automation import Condition from esphome.automation import Condition
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.logger import request_log_listener
from esphome.config_helpers import get_logger_level from esphome.config_helpers import get_logger_level
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
@@ -226,32 +227,6 @@ def _encryption_schema(config):
return ENCRYPTION_SCHEMA(config) return ENCRYPTION_SCHEMA(config)
def _validate_api_config(config: ConfigType) -> ConfigType:
"""Validate API configuration with mutual exclusivity check and deprecation warning."""
# Check if both password and encryption are configured
has_password = CONF_PASSWORD in config and config[CONF_PASSWORD]
has_encryption = CONF_ENCRYPTION in config
if has_password and has_encryption:
raise cv.Invalid(
"The 'password' and 'encryption' options are mutually exclusive. "
"The API client only supports one authentication method at a time. "
"Please remove one of them. "
"Note: 'password' authentication is deprecated and will be removed in version 2026.1.0. "
"We strongly recommend using 'encryption' instead for better security."
)
# Warn about password deprecation
if has_password:
_LOGGER.warning(
"API 'password' authentication has been deprecated since May 2022 and will be removed in version 2026.1.0. "
"Please migrate to the 'encryption' configuration. "
"See https://esphome.io/components/api/#configuration-variables"
)
return config
def _consume_api_sockets(config: ConfigType) -> ConfigType: def _consume_api_sockets(config: ConfigType) -> ConfigType:
"""Register socket needs for API component.""" """Register socket needs for API component."""
from esphome.components import socket from esphome.components import socket
@@ -268,7 +243,17 @@ CONFIG_SCHEMA = cv.All(
{ {
cv.GenerateID(): cv.declare_id(APIServer), cv.GenerateID(): cv.declare_id(APIServer),
cv.Optional(CONF_PORT, default=6053): cv.port, cv.Optional(CONF_PORT, default=6053): cv.port,
cv.Optional(CONF_PASSWORD, default=""): cv.string_strict, # Removed in 2026.1.0 - kept to provide helpful error message
cv.Optional(CONF_PASSWORD): cv.invalid(
"The 'password' option has been removed in ESPHome 2026.1.0.\n"
"Password authentication was deprecated in May 2022.\n"
"Please migrate to encryption for secure API communication:\n\n"
"api:\n"
" encryption:\n"
" key: !secret api_encryption_key\n\n"
"Generate a key with: openssl rand -base64 32\n"
"Or visit https://esphome.io/components/api/#configuration-variables"
),
cv.Optional( cv.Optional(
CONF_REBOOT_TIMEOUT, default="15min" CONF_REBOOT_TIMEOUT, default="15min"
): cv.positive_time_period_milliseconds, ): cv.positive_time_period_milliseconds,
@@ -330,7 +315,6 @@ CONFIG_SCHEMA = cv.All(
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.rename_key(CONF_SERVICES, CONF_ACTIONS), cv.rename_key(CONF_SERVICES, CONF_ACTIONS),
_validate_api_config,
_consume_api_sockets, _consume_api_sockets,
) )
@@ -343,10 +327,10 @@ async def to_code(config: ConfigType) -> None:
# Track controller registration for StaticVector sizing # Track controller registration for StaticVector sizing
CORE.register_controller() CORE.register_controller()
# Request a log listener slot for API log streaming
request_log_listener()
cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_port(config[CONF_PORT]))
if config[CONF_PASSWORD]:
cg.add_define("USE_API_PASSWORD")
cg.add(var.set_password(config[CONF_PASSWORD]))
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY])) cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
if CONF_LISTEN_BACKLOG in config: if CONF_LISTEN_BACKLOG in config:

View File

@@ -7,10 +7,7 @@ service APIConnection {
option (needs_setup_connection) = false; option (needs_setup_connection) = false;
option (needs_authentication) = false; option (needs_authentication) = false;
} }
rpc authenticate (AuthenticationRequest) returns (AuthenticationResponse) { // REMOVED in ESPHome 2026.1.0: rpc authenticate (AuthenticationRequest) returns (AuthenticationResponse)
option (needs_setup_connection) = false;
option (needs_authentication) = false;
}
rpc disconnect (DisconnectRequest) returns (DisconnectResponse) { rpc disconnect (DisconnectRequest) returns (DisconnectResponse) {
option (needs_setup_connection) = false; option (needs_setup_connection) = false;
option (needs_authentication) = false; option (needs_authentication) = false;
@@ -69,6 +66,8 @@ service APIConnection {
rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {} rpc zwave_proxy_frame(ZWaveProxyFrame) returns (void) {}
rpc zwave_proxy_request(ZWaveProxyRequest) returns (void) {} rpc zwave_proxy_request(ZWaveProxyRequest) returns (void) {}
rpc infrared_rf_transmit_raw_timings(InfraredRFTransmitRawTimingsRequest) returns (void) {}
} }
@@ -82,14 +81,13 @@ service APIConnection {
// * VarInt denoting the type of message. // * VarInt denoting the type of message.
// * The message object encoded as a ProtoBuf message // * The message object encoded as a ProtoBuf message
// The connection is established in 4 steps: // The connection is established in 2 steps:
// * First, the client connects to the server and sends a "Hello Request" identifying itself // * First, the client connects to the server and sends a "Hello Request" identifying itself
// * The server responds with a "Hello Response" and selects the protocol version // * The server responds with a "Hello Response" and the connection is authenticated
// * After receiving this message, the client attempts to authenticate itself using
// the password and a "Connect Request"
// * The server responds with a "Connect Response" and notifies of invalid password.
// If anything in this initial process fails, the connection must immediately closed // If anything in this initial process fails, the connection must immediately closed
// by both sides and _no_ disconnection message is to be sent. // by both sides and _no_ disconnection message is to be sent.
// Note: Password authentication via AuthenticationRequest/AuthenticationResponse (message IDs 3, 4)
// was removed in ESPHome 2026.1.0. Those message IDs are reserved and should not be reused.
// Message sent at the beginning of each connection // Message sent at the beginning of each connection
// Can only be sent by the client and only at the beginning of the connection // Can only be sent by the client and only at the beginning of the connection
@@ -102,7 +100,7 @@ message HelloRequest {
// For example "Home Assistant" // For example "Home Assistant"
// Not strictly necessary to send but nice for debugging // Not strictly necessary to send but nice for debugging
// purposes. // purposes.
string client_info = 1 [(pointer_to_buffer) = true]; string client_info = 1;
uint32 api_version_major = 2; uint32 api_version_major = 2;
uint32 api_version_minor = 3; uint32 api_version_minor = 3;
} }
@@ -130,25 +128,23 @@ message HelloResponse {
string name = 4; string name = 4;
} }
// Message sent at the beginning of each connection to authenticate the client // DEPRECATED in ESPHome 2026.1.0 - Password authentication is no longer supported.
// Can only be sent by the client and only at the beginning of the connection // These messages are kept for protocol documentation but are not processed by the server.
// Use noise encryption instead: https://esphome.io/components/api/#configuration-variables
message AuthenticationRequest { message AuthenticationRequest {
option (id) = 3; option (id) = 3;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
option (no_delay) = true; option (no_delay) = true;
option (ifdef) = "USE_API_PASSWORD"; option deprecated = true;
// The password to log in with string password = 1;
string password = 1 [(pointer_to_buffer) = true];
} }
// Confirmation of successful connection. After this the connection is available for all traffic.
// Can only be sent by the server and only at the beginning of the connection
message AuthenticationResponse { message AuthenticationResponse {
option (id) = 4; option (id) = 4;
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
option (no_delay) = true; option (no_delay) = true;
option (ifdef) = "USE_API_PASSWORD"; option deprecated = true;
bool invalid_password = 1; bool invalid_password = 1;
} }
@@ -205,7 +201,9 @@ message DeviceInfoResponse {
option (id) = 10; option (id) = 10;
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
bool uses_password = 1 [(field_ifdef) = "USE_API_PASSWORD"]; // Deprecated in ESPHome 2026.1.0, but kept for backward compatibility
// with older ESPHome versions that still send this field.
bool uses_password = 1 [deprecated = true];
// The name of the node, given by "App.set_name()" // The name of the node, given by "App.set_name()"
string name = 2; string name = 2;
@@ -579,7 +577,7 @@ message LightCommandRequest {
bool has_flash_length = 16; bool has_flash_length = 16;
uint32 flash_length = 17; uint32 flash_length = 17;
bool has_effect = 18; bool has_effect = 18;
string effect = 19 [(pointer_to_buffer) = true]; string effect = 19;
uint32 device_id = 28 [(field_ifdef) = "USE_DEVICES"]; uint32 device_id = 28 [(field_ifdef) = "USE_DEVICES"];
} }
@@ -767,7 +765,7 @@ message SubscribeHomeassistantServicesRequest {
message HomeassistantServiceMap { message HomeassistantServiceMap {
string key = 1; string key = 1;
string value = 2 [(no_zero_copy) = true]; string value = 2;
} }
message HomeassistantActionRequest { message HomeassistantActionRequest {
@@ -783,7 +781,7 @@ message HomeassistantActionRequest {
bool is_event = 5; bool is_event = 5;
uint32 call_id = 6 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES"]; uint32 call_id = 6 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES"];
bool wants_response = 7 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"]; bool wants_response = 7 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"];
string response_template = 8 [(no_zero_copy) = true, (field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"]; string response_template = 8 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"];
} }
// Message sent by Home Assistant to ESPHome with service call response data // Message sent by Home Assistant to ESPHome with service call response data
@@ -796,7 +794,7 @@ message HomeassistantActionResponse {
uint32 call_id = 1; // Matches the call_id from HomeassistantActionRequest uint32 call_id = 1; // Matches the call_id from HomeassistantActionRequest
bool success = 2; // Whether the service call succeeded bool success = 2; // Whether the service call succeeded
string error_message = 3; // Error message if success = false string error_message = 3; // Error message if success = false
bytes response_data = 4 [(pointer_to_buffer) = true, (field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"]; bytes response_data = 4 [(field_ifdef) = "USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON"];
} }
// ==================== IMPORT HOME ASSISTANT STATES ==================== // ==================== IMPORT HOME ASSISTANT STATES ====================
@@ -841,7 +839,7 @@ message GetTimeResponse {
option (no_delay) = true; option (no_delay) = true;
fixed32 epoch_seconds = 1; fixed32 epoch_seconds = 1;
string timezone = 2 [(pointer_to_buffer) = true]; string timezone = 2;
} }
// ==================== USER-DEFINES SERVICES ==================== // ==================== USER-DEFINES SERVICES ====================
@@ -1101,6 +1099,85 @@ message ClimateCommandRequest {
uint32 device_id = 24 [(field_ifdef) = "USE_DEVICES"]; uint32 device_id = 24 [(field_ifdef) = "USE_DEVICES"];
} }
// ==================== WATER_HEATER ====================
enum WaterHeaterMode {
WATER_HEATER_MODE_OFF = 0;
WATER_HEATER_MODE_ECO = 1;
WATER_HEATER_MODE_ELECTRIC = 2;
WATER_HEATER_MODE_PERFORMANCE = 3;
WATER_HEATER_MODE_HIGH_DEMAND = 4;
WATER_HEATER_MODE_HEAT_PUMP = 5;
WATER_HEATER_MODE_GAS = 6;
}
message ListEntitiesWaterHeaterResponse {
option (id) = 132;
option (base_class) = "InfoResponseProtoMessage";
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_WATER_HEATER";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON"];
bool disabled_by_default = 5;
EntityCategory entity_category = 6;
uint32 device_id = 7 [(field_ifdef) = "USE_DEVICES"];
float min_temperature = 8;
float max_temperature = 9;
float target_temperature_step = 10;
repeated WaterHeaterMode supported_modes = 11 [(container_pointer_no_template) = "water_heater::WaterHeaterModeMask"];
// Bitmask of WaterHeaterFeature flags
uint32 supported_features = 12;
}
message WaterHeaterStateResponse {
option (id) = 133;
option (base_class) = "StateResponseProtoMessage";
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_WATER_HEATER";
option (no_delay) = true;
fixed32 key = 1;
float current_temperature = 2;
float target_temperature = 3;
WaterHeaterMode mode = 4;
uint32 device_id = 5 [(field_ifdef) = "USE_DEVICES"];
// Bitmask of current state flags (bit 0 = away, bit 1 = on)
uint32 state = 6;
float target_temperature_low = 7;
float target_temperature_high = 8;
}
// Bitmask for WaterHeaterCommandRequest.has_fields
enum WaterHeaterCommandHasField {
WATER_HEATER_COMMAND_HAS_NONE = 0;
WATER_HEATER_COMMAND_HAS_MODE = 1;
WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE = 2;
WATER_HEATER_COMMAND_HAS_STATE = 4;
WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW = 8;
WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH = 16;
}
message WaterHeaterCommandRequest {
option (id) = 134;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_WATER_HEATER";
option (no_delay) = true;
option (base_class) = "CommandProtoMessage";
fixed32 key = 1;
// Bitmask of which fields are set (see WaterHeaterCommandHasField)
uint32 has_fields = 2;
WaterHeaterMode mode = 3;
float target_temperature = 4;
uint32 device_id = 5 [(field_ifdef) = "USE_DEVICES"];
// State flags bitmask (bit 0 = away, bit 1 = on)
uint32 state = 6;
float target_temperature_low = 7;
float target_temperature_high = 8;
}
// ==================== NUMBER ==================== // ==================== NUMBER ====================
enum NumberMode { enum NumberMode {
NUMBER_MODE_AUTO = 0; NUMBER_MODE_AUTO = 0;
@@ -1195,7 +1272,7 @@ message SelectCommandRequest {
option (base_class) = "CommandProtoMessage"; option (base_class) = "CommandProtoMessage";
fixed32 key = 1; fixed32 key = 1;
string state = 2 [(pointer_to_buffer) = true]; string state = 2;
uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"]; uint32 device_id = 3 [(field_ifdef) = "USE_DEVICES"];
} }
@@ -1213,7 +1290,7 @@ message ListEntitiesSirenResponse {
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"]; string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
bool disabled_by_default = 6; bool disabled_by_default = 6;
repeated string tones = 7; repeated string tones = 7 [(container_pointer_no_template) = "FixedVector<const char *>"];
bool supports_duration = 8; bool supports_duration = 8;
bool supports_volume = 9; bool supports_volume = 9;
EntityCategory entity_category = 10; EntityCategory entity_category = 10;
@@ -1613,7 +1690,7 @@ message BluetoothGATTWriteRequest {
uint32 handle = 2; uint32 handle = 2;
bool response = 3; bool response = 3;
bytes data = 4 [(pointer_to_buffer) = true]; bytes data = 4;
} }
message BluetoothGATTReadDescriptorRequest { message BluetoothGATTReadDescriptorRequest {
@@ -1633,7 +1710,7 @@ message BluetoothGATTWriteDescriptorRequest {
uint64 address = 1; uint64 address = 1;
uint32 handle = 2; uint32 handle = 2;
bytes data = 3 [(pointer_to_buffer) = true]; bytes data = 3;
} }
message BluetoothGATTNotifyRequest { message BluetoothGATTNotifyRequest {
@@ -1858,7 +1935,7 @@ message VoiceAssistantAudio {
option (source) = SOURCE_BOTH; option (source) = SOURCE_BOTH;
option (ifdef) = "USE_VOICE_ASSISTANT"; option (ifdef) = "USE_VOICE_ASSISTANT";
bytes data = 1; bytes data = 1 [(pointer_to_buffer) = true];
bool end = 2; bool end = 2;
} }
@@ -2346,7 +2423,7 @@ message ZWaveProxyFrame {
option (ifdef) = "USE_ZWAVE_PROXY"; option (ifdef) = "USE_ZWAVE_PROXY";
option (no_delay) = true; option (no_delay) = true;
bytes data = 1 [(pointer_to_buffer) = true]; bytes data = 1;
} }
enum ZWaveProxyRequestType { enum ZWaveProxyRequestType {
@@ -2360,5 +2437,51 @@ message ZWaveProxyRequest {
option (ifdef) = "USE_ZWAVE_PROXY"; option (ifdef) = "USE_ZWAVE_PROXY";
ZWaveProxyRequestType type = 1; ZWaveProxyRequestType type = 1;
bytes data = 2 [(pointer_to_buffer) = true]; bytes data = 2;
}
// ==================== INFRARED ====================
// Note: Feature and capability flag enums are defined in
// esphome/components/infrared/infrared.h
// Listing of infrared instances
message ListEntitiesInfraredResponse {
option (id) = 135;
option (base_class) = "InfoResponseProtoMessage";
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_INFRARED";
string object_id = 1;
fixed32 key = 2;
string name = 3;
string icon = 4 [(field_ifdef) = "USE_ENTITY_ICON"];
bool disabled_by_default = 5;
EntityCategory entity_category = 6;
uint32 device_id = 7 [(field_ifdef) = "USE_DEVICES"];
uint32 capabilities = 8; // Bitfield of InfraredCapabilityFlags
}
// Command to transmit infrared/RF data using raw timings
message InfraredRFTransmitRawTimingsRequest {
option (id) = 136;
option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_IR_RF";
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
fixed32 key = 2; // Key identifying the transmitter instance
uint32 carrier_frequency = 3; // Carrier frequency in Hz
uint32 repeat_count = 4; // Number of times to transmit (1 = once, 2 = twice, etc.)
repeated sint32 timings = 5 [packed = true, (packed_buffer) = true]; // Raw timings in microseconds (zigzag-encoded): positive = mark (LED/TX on), negative = space (LED/TX off)
}
// Event message for received infrared/RF data
message InfraredRFReceiveEvent {
option (id) = 137;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_IR_RF";
option (no_delay) = true;
uint32 device_id = 1 [(field_ifdef) = "USE_DEVICES"];
fixed32 key = 2; // Key identifying the receiver instance
repeated sint32 timings = 3 [packed = true, (container_pointer_no_template) = "std::vector<int32_t>"]; // Raw timings in microseconds (zigzag-encoded): alternating mark/space periods
} }

File diff suppressed because it is too large Load Diff

View File

@@ -9,32 +9,24 @@
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/entity_base.h" #include "esphome/core/entity_base.h"
#include "esphome/core/string_ref.h"
#include <functional> #include <functional>
#include <limits>
#include <vector> #include <vector>
namespace esphome::api { namespace esphome::api {
// Client information structure
struct ClientInfo {
std::string name; // Client name from Hello message
std::string peername; // IP:port from socket
};
// Keepalive timeout in milliseconds // Keepalive timeout in milliseconds
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000; static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
// Maximum number of entities to process in a single batch during initial state/info sending // Maximum number of entities to process in a single batch during initial state/info sending
// This was increased from 20 to 24 after removing the unique_id field from entity info messages, // API 1.14+ clients compute object_id client-side, so messages are smaller and we can fit more per batch
// which reduced message sizes allowing more entities per batch without exceeding packet limits // TODO: Remove MAX_INITIAL_PER_BATCH_LEGACY before 2026.7.0 - all clients should support API 1.14 by then
static constexpr size_t MAX_INITIAL_PER_BATCH = 24; static constexpr size_t MAX_INITIAL_PER_BATCH_LEGACY = 24; // For clients < API 1.14 (includes object_id)
// Maximum number of packets to process in a single batch (platform-dependent) static constexpr size_t MAX_INITIAL_PER_BATCH = 34; // For clients >= API 1.14 (no object_id)
// This limit exists to prevent stack overflow from the PacketInfo array in process_batch_ // Verify MAX_MESSAGES_PER_BATCH (defined in api_frame_helper.h) can hold the initial batch
// Each PacketInfo is 8 bytes, so 64 * 8 = 512 bytes, 32 * 8 = 256 bytes static_assert(MAX_MESSAGES_PER_BATCH >= MAX_INITIAL_PER_BATCH,
#if defined(USE_ESP32) || defined(USE_HOST) "MAX_MESSAGES_PER_BATCH must be >= MAX_INITIAL_PER_BATCH");
static constexpr size_t MAX_PACKETS_PER_BATCH = 64; // ESP32 has 8KB+ stack, HOST has plenty
#else
static constexpr size_t MAX_PACKETS_PER_BATCH = 32; // ESP8266/RP2040/etc have smaller stacks
#endif
class APIConnection final : public APIServerConnection { class APIConnection final : public APIServerConnection {
public: public:
@@ -47,8 +39,8 @@ class APIConnection final : public APIServerConnection {
void loop(); void loop();
bool send_list_info_done() { bool send_list_info_done() {
return this->schedule_message_(nullptr, &APIConnection::try_send_list_info_done, return this->schedule_message_(nullptr, ListEntitiesDoneResponse::MESSAGE_TYPE,
ListEntitiesDoneResponse::MESSAGE_TYPE, ListEntitiesDoneResponse::ESTIMATED_SIZE); ListEntitiesDoneResponse::ESTIMATED_SIZE);
} }
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor); bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor);
@@ -176,8 +168,18 @@ class APIConnection final : public APIServerConnection {
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override; void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif #endif
#ifdef USE_WATER_HEATER
bool send_water_heater_state(water_heater::WaterHeater *water_heater);
void on_water_heater_command_request(const WaterHeaterCommandRequest &msg) override;
#endif
#ifdef USE_IR_RF
void infrared_rf_transmit_raw_timings(const InfraredRFTransmitRawTimingsRequest &msg) override;
void send_infrared_rf_receive_event(const InfraredRFReceiveEvent &msg);
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
void send_event(event::Event *event, const char *event_type); void send_event(event::Event *event);
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
@@ -197,16 +199,17 @@ class APIConnection final : public APIServerConnection {
void on_get_time_response(const GetTimeResponse &value) override; void on_get_time_response(const GetTimeResponse &value) override;
#endif #endif
bool send_hello_response(const HelloRequest &msg) override; bool send_hello_response(const HelloRequest &msg) override;
#ifdef USE_API_PASSWORD
bool send_authenticate_response(const AuthenticationRequest &msg) override;
#endif
bool send_disconnect_response(const DisconnectRequest &msg) override; bool send_disconnect_response(const DisconnectRequest &msg) override;
bool send_ping_response(const PingRequest &msg) override; bool send_ping_response(const PingRequest &msg) override;
bool send_device_info_response(const DeviceInfoRequest &msg) override; bool send_device_info_response(const DeviceInfoRequest &msg) override;
void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } void list_entities(const ListEntitiesRequest &msg) override { this->begin_iterator_(ActiveIterator::LIST_ENTITIES); }
void subscribe_states(const SubscribeStatesRequest &msg) override { void subscribe_states(const SubscribeStatesRequest &msg) override {
this->flags_.state_subscription = true; this->flags_.state_subscription = true;
this->initial_state_iterator_.begin(); // Start initial state iterator only if no iterator is active
// If list_entities is running, we'll start initial_state when it completes
if (this->active_iterator_ == ActiveIterator::NONE) {
this->begin_iterator_(ActiveIterator::INITIAL_STATE);
}
} }
void subscribe_logs(const SubscribeLogsRequest &msg) override { void subscribe_logs(const SubscribeLogsRequest &msg) override {
this->flags_.log_subscription = msg.level; this->flags_.log_subscription = msg.level;
@@ -224,9 +227,9 @@ class APIConnection final : public APIServerConnection {
#ifdef USE_API_USER_DEFINED_ACTIONS #ifdef USE_API_USER_DEFINED_ACTIONS
void execute_service(const ExecuteServiceRequest &msg) override; void execute_service(const ExecuteServiceRequest &msg) override;
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message); void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void send_execute_service_response(uint32_t call_id, bool success, const std::string &error_message, void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message,
const uint8_t *response_data, size_t response_data_len); const uint8_t *response_data, size_t response_data_len);
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES #endif // USE_API_USER_DEFINED_ACTION_RESPONSES
@@ -251,9 +254,6 @@ class APIConnection final : public APIServerConnection {
} }
void on_fatal_error() override; void on_fatal_error() override;
#ifdef USE_API_PASSWORD
void on_unauthenticated_access() override;
#endif
void on_no_setup_connection() override; void on_no_setup_connection() override;
ProtoWriteBuffer create_buffer(uint32_t reserve_size) override { ProtoWriteBuffer create_buffer(uint32_t reserve_size) override {
// FIXME: ensure no recursive writes can happen // FIXME: ensure no recursive writes can happen
@@ -280,13 +280,18 @@ class APIConnection final : public APIServerConnection {
bool try_to_clear_buffer(bool log_out_of_space); bool try_to_clear_buffer(bool log_out_of_space);
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override; bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
const std::string &get_name() const { return this->client_info_.name; } const char *get_name() const { return this->helper_->get_client_name(); }
const std::string &get_peername() const { return this->client_info_.peername; } /// Get peer name (IP address) - cached at connection init time
const char *get_peername() const { return this->helper_->get_client_peername(); }
protected: protected:
// Helper function to handle authentication completion // Helper function to handle authentication completion
void complete_authentication_(); void complete_authentication_();
#ifdef USE_CAMERA
void try_send_camera_image_();
#endif
#ifdef USE_API_HOMEASSISTANT_STATES #ifdef USE_API_HOMEASSISTANT_STATES
void process_state_subscriptions_(); void process_state_subscriptions_();
#endif #endif
@@ -310,25 +315,24 @@ class APIConnection final : public APIServerConnection {
APIConnection *conn, uint32_t remaining_size, bool is_single) { APIConnection *conn, uint32_t remaining_size, bool is_single) {
// Set common fields that are shared by all entity types // Set common fields that are shared by all entity types
msg.key = entity->get_object_id_hash(); msg.key = entity->get_object_id_hash();
// Try to use static reference first to avoid allocation
StringRef static_ref = entity->get_object_id_ref_for_api_(); // API 1.14+ clients compute object_id client-side from the entity name
// Store dynamic string outside the if-else to maintain lifetime // For older clients, we must send object_id for backward compatibility
std::string object_id; // See: https://github.com/esphome/backlog/issues/76
if (!static_ref.empty()) { // TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then
msg.set_object_id(static_ref); // Buffer must remain in scope until encode_message_to_buffer is called
} else { char object_id_buf[OBJECT_ID_MAX_LEN];
// Dynamic case - need to allocate if (!conn->client_supports_api_version(1, 14)) {
object_id = entity->get_object_id(); msg.object_id = entity->get_object_id_to(object_id_buf);
msg.set_object_id(StringRef(object_id));
} }
if (entity->has_own_name()) { if (entity->has_own_name()) {
msg.set_name(entity->get_name()); msg.name = entity->get_name();
} }
// Set common EntityBase properties // Set common EntityBase properties
#ifdef USE_ENTITY_ICON #ifdef USE_ENTITY_ICON
msg.set_icon(entity->get_icon_ref()); msg.icon = entity->get_icon_ref();
#endif #endif
msg.disabled_by_default = entity->is_disabled_by_default(); msg.disabled_by_default = entity->is_disabled_by_default();
msg.entity_category = static_cast<enums::EntityCategory>(entity->get_entity_category()); msg.entity_category = static_cast<enums::EntityCategory>(entity->get_entity_category());
@@ -343,16 +347,24 @@ class APIConnection final : public APIServerConnection {
inline bool check_voice_assistant_api_connection_() const; inline bool check_voice_assistant_api_connection_() const;
#endif #endif
// Get the max batch size based on client API version
// API 1.14+ clients don't receive object_id, so messages are smaller and more fit per batch
// TODO: Remove this method before 2026.7.0 and use MAX_INITIAL_PER_BATCH directly
size_t get_max_batch_size_() const {
return this->client_supports_api_version(1, 14) ? MAX_INITIAL_PER_BATCH : MAX_INITIAL_PER_BATCH_LEGACY;
}
// Helper method to process multiple entities from an iterator in a batch // Helper method to process multiple entities from an iterator in a batch
template<typename Iterator> void process_iterator_batch_(Iterator &iterator) { template<typename Iterator> void process_iterator_batch_(Iterator &iterator) {
size_t initial_size = this->deferred_batch_.size(); size_t initial_size = this->deferred_batch_.size();
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < MAX_INITIAL_PER_BATCH) { size_t max_batch = this->get_max_batch_size_();
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < max_batch) {
iterator.advance(); iterator.advance();
} }
// If the batch is full, process it immediately // If the batch is full, process it immediately
// Note: iterator.advance() already calls schedule_batch_() via schedule_message_() // Note: iterator.advance() already calls schedule_batch_() via schedule_message_()
if (this->deferred_batch_.size() >= MAX_INITIAL_PER_BATCH) { if (this->deferred_batch_.size() >= max_batch) {
this->process_batch_(); this->process_batch_();
} }
} }
@@ -456,8 +468,18 @@ class APIConnection final : public APIServerConnection {
static uint16_t try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, static uint16_t try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single); bool is_single);
#endif #endif
#ifdef USE_WATER_HEATER
static uint16_t try_send_water_heater_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
static uint16_t try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
#endif
#ifdef USE_INFRARED
static uint16_t try_send_infrared_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
static uint16_t try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn, static uint16_t try_send_event_response(event::Event *event, StringRef event_type, APIConnection *conn,
uint32_t remaining_size, bool is_single); uint32_t remaining_size, bool is_single);
static uint16_t try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single); static uint16_t try_send_event_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single);
#endif #endif
@@ -490,18 +512,27 @@ class APIConnection final : public APIServerConnection {
std::unique_ptr<APIFrameHelper> helper_; std::unique_ptr<APIFrameHelper> helper_;
APIServer *parent_; APIServer *parent_;
// Group 2: Larger objects (must be 4-byte aligned) // Group 2: Iterator union (saves ~16 bytes vs separate iterators)
// These contain vectors/pointers internally, so putting them early ensures good alignment // These iterators are never active simultaneously - list_entities runs to completion
InitialStateIterator initial_state_iterator_; // before initial_state begins, so we use a union with explicit construction/destruction.
ListEntitiesIterator list_entities_iterator_; enum class ActiveIterator : uint8_t { NONE, LIST_ENTITIES, INITIAL_STATE };
union IteratorUnion {
ListEntitiesIterator list_entities;
InitialStateIterator initial_state;
// Constructor/destructor do nothing - use placement new/explicit destructor
IteratorUnion() {}
~IteratorUnion() {}
} iterator_storage_;
// Helper methods for iterator lifecycle management
void destroy_active_iterator_();
void begin_iterator_(ActiveIterator type);
#ifdef USE_CAMERA #ifdef USE_CAMERA
std::unique_ptr<camera::CameraImageReader> image_reader_; std::unique_ptr<camera::CameraImageReader> image_reader_;
#endif #endif
// Group 3: Client info struct (24 bytes on 32-bit: 2 strings × 12 bytes each) // Group 3: 4-byte types
ClientInfo client_info_;
// Group 4: 4-byte types
uint32_t last_traffic_; uint32_t last_traffic_;
#ifdef USE_API_HOMEASSISTANT_STATES #ifdef USE_API_HOMEASSISTANT_STATES
int state_subs_at_ = -1; int state_subs_at_ = -1;
@@ -510,33 +541,17 @@ class APIConnection final : public APIServerConnection {
// Function pointer type for message encoding // Function pointer type for message encoding
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
class MessageCreator {
public:
MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; }
explicit MessageCreator(const char *str_value) { data_.const_char_ptr = str_value; }
// Call operator - uses message_type to determine union type
uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single,
uint8_t message_type) const;
private:
union Data {
MessageCreatorPtr function_ptr;
const char *const_char_ptr;
} data_; // 4 bytes on 32-bit, 8 bytes on 64-bit
};
// Generic batching mechanism for both state updates and entity info // Generic batching mechanism for both state updates and entity info
struct DeferredBatch { struct DeferredBatch {
struct BatchItem { // Sentinel value for unused aux_data_index
EntityBase *entity; // Entity pointer static constexpr uint8_t AUX_DATA_UNUSED = std::numeric_limits<uint8_t>::max();
MessageCreator creator; // Function that creates the message when needed
uint8_t message_type; // Message type for overhead calculation (max 255)
uint8_t estimated_size; // Estimated message size (max 255 bytes)
// Constructor for creating BatchItem struct BatchItem {
BatchItem(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) EntityBase *entity; // 4 bytes - Entity pointer
: entity(entity), creator(creator), message_type(message_type), estimated_size(estimated_size) {} uint8_t message_type; // 1 byte - Message type for protocol and dispatch
uint8_t estimated_size; // 1 byte - Estimated message size (max 255 bytes)
uint8_t aux_data_index{AUX_DATA_UNUSED}; // 1 byte - For events: index into entity's event_types
// 1 byte padding
}; };
std::vector<BatchItem> items; std::vector<BatchItem> items;
@@ -545,10 +560,11 @@ class APIConnection final : public APIServerConnection {
// No pre-allocation - log connections never use batching, and for // No pre-allocation - log connections never use batching, and for
// connections that do, buffers are released after initial sync anyway // connections that do, buffers are released after initial sync anyway
// Add item to the batch // Add item to the batch (with deduplication)
void add_item(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size); void add_item(EntityBase *entity, uint8_t message_type, uint8_t estimated_size,
uint8_t aux_data_index = AUX_DATA_UNUSED);
// Add item to the front of the batch (for high priority messages like ping) // Add item to the front of the batch (for high priority messages like ping)
void add_item_front(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size); void add_item_front(EntityBase *entity, uint8_t message_type, uint8_t estimated_size);
// Clear all items // Clear all items
void clear() { void clear() {
@@ -562,6 +578,7 @@ class APIConnection final : public APIServerConnection {
bool empty() const { return items.empty(); } bool empty() const { return items.empty(); }
size_t size() const { return items.size(); } size_t size() const { return items.size(); }
const BatchItem &operator[](size_t index) const { return items[index]; } const BatchItem &operator[](size_t index) const { return items[index]; }
// Release excess capacity - only releases if items already empty // Release excess capacity - only releases if items already empty
void release_buffer() { void release_buffer() {
// Safe to call: batch is processed before release_buffer is called, // Safe to call: batch is processed before release_buffer is called,
@@ -608,7 +625,9 @@ class APIConnection final : public APIServerConnection {
// 2-byte types immediately after flags_ (no padding between them) // 2-byte types immediately after flags_ (no padding between them)
uint16_t client_api_version_major_{0}; uint16_t client_api_version_major_{0};
uint16_t client_api_version_minor_{0}; uint16_t client_api_version_minor_{0};
// Total: 2 (flags) + 2 + 2 = 6 bytes, then 2 bytes padding to next 4-byte boundary // 1-byte type to fill padding
ActiveIterator active_iterator_{ActiveIterator::NONE};
// Total: 2 (flags) + 2 + 2 + 1 = 7 bytes, then 1 byte padding to next 4-byte boundary
uint32_t get_batch_delay_ms_() const; uint32_t get_batch_delay_ms_() const;
// Message will use 8 more bytes than the minimum size, and typical // Message will use 8 more bytes than the minimum size, and typical
@@ -631,17 +650,15 @@ class APIConnection final : public APIServerConnection {
this->flags_.batch_scheduled = false; this->flags_.batch_scheduled = false;
} }
#ifdef HAS_PROTO_MESSAGE_DUMP // Dispatch message encoding based on message_type - replaces function pointer storage
// Helper to log a proto message from a MessageCreator object // Switch assigns pointer, single call site for smaller code size
void log_proto_message_(EntityBase *entity, const MessageCreator &creator, uint8_t message_type) { uint16_t dispatch_message_(const DeferredBatch::BatchItem &item, uint32_t remaining_size, bool is_single);
this->flags_.log_only_mode = true;
creator(entity, this, MAX_BATCH_PACKET_SIZE, true, message_type);
this->flags_.log_only_mode = false;
}
#ifdef HAS_PROTO_MESSAGE_DUMP
void log_batch_item_(const DeferredBatch::BatchItem &item) { void log_batch_item_(const DeferredBatch::BatchItem &item) {
// Use the helper to log the message this->flags_.log_only_mode = true;
this->log_proto_message_(item.entity, item.creator, item.message_type); this->dispatch_message_(item, MAX_BATCH_PACKET_SIZE, true);
this->flags_.log_only_mode = false;
} }
#endif #endif
@@ -666,66 +683,36 @@ class APIConnection final : public APIServerConnection {
// Helper method to send a message either immediately or via batching // Helper method to send a message either immediately or via batching
// Tries immediate send if should_send_immediately_() returns true and buffer has space // Tries immediate send if should_send_immediately_() returns true and buffer has space
// Falls back to batching if immediate send fails or isn't applicable // Falls back to batching if immediate send fails or isn't applicable
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type, bool send_message_smart_(EntityBase *entity, uint8_t message_type, uint8_t estimated_size,
uint8_t estimated_size) { uint8_t aux_data_index = DeferredBatch::AUX_DATA_UNUSED) {
if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) { if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) {
// Now actually encode and send DeferredBatch::BatchItem item{entity, message_type, estimated_size, aux_data_index};
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true) && if (this->dispatch_message_(item, MAX_BATCH_PACKET_SIZE, true) &&
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) { this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
// Log the message in verbose mode this->log_batch_item_(item);
this->log_proto_message_(entity, MessageCreator(creator), message_type);
#endif #endif
return true; return true;
} }
// If immediate send failed, fall through to batching
} }
return this->schedule_message_(entity, message_type, estimated_size, aux_data_index);
// Fall back to scheduled batching
return this->schedule_message_(entity, creator, message_type, estimated_size);
}
// Overload for MessageCreator (used by events which need to capture event_type)
bool send_message_smart_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
// Try to send immediately if message type should bypass batching and buffer has space
if (this->should_send_immediately_(message_type) && this->helper_->can_write_without_blocking()) {
// Now actually encode and send
if (creator(entity, this, MAX_BATCH_PACKET_SIZE, true, message_type) &&
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
#ifdef HAS_PROTO_MESSAGE_DUMP
// Log the message in verbose mode
this->log_proto_message_(entity, creator, message_type);
#endif
return true;
}
// If immediate send failed, fall through to batching
}
// Fall back to scheduled batching
return this->schedule_message_(entity, creator, message_type, estimated_size);
} }
// Helper function to schedule a deferred message with known message type // Helper function to schedule a deferred message with known message type
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) { bool schedule_message_(EntityBase *entity, uint8_t message_type, uint8_t estimated_size,
this->deferred_batch_.add_item(entity, creator, message_type, estimated_size); uint8_t aux_data_index = DeferredBatch::AUX_DATA_UNUSED) {
this->deferred_batch_.add_item(entity, message_type, estimated_size, aux_data_index);
return this->schedule_batch_(); return this->schedule_batch_();
} }
// Overload for function pointers (for info messages and current state reads)
bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint8_t message_type,
uint8_t estimated_size) {
return schedule_message_(entity, MessageCreator(function_ptr), message_type, estimated_size);
}
// Helper function to schedule a high priority message at the front of the batch // Helper function to schedule a high priority message at the front of the batch
bool schedule_message_front_(EntityBase *entity, MessageCreatorPtr function_ptr, uint8_t message_type, bool schedule_message_front_(EntityBase *entity, uint8_t message_type, uint8_t estimated_size) {
uint8_t estimated_size) { this->deferred_batch_.add_item_front(entity, message_type, estimated_size);
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type, estimated_size);
return this->schedule_batch_(); return this->schedule_batch_();
} }
// Helper function to log client messages with name and peername
void log_client_(int level, const LogString *message);
// Helper function to log API errors with errno // Helper function to log API errors with errno
void log_warning_(const LogString *message, APIError err); void log_warning_(const LogString *message, APIError err);
// Helper to handle fatal errors with logging // Helper to handle fatal errors with logging

View File

@@ -1,6 +1,5 @@
#include "api_frame_helper.h" #include "api_frame_helper.h"
#ifdef USE_API #ifdef USE_API
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
@@ -13,12 +12,29 @@ namespace esphome::api {
static const char *const TAG = "api.frame_helper"; static const char *const TAG = "api.frame_helper";
#define HELPER_LOG(msg, ...) \ // Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) \
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Received frame: %s", \
format_hex_pretty_to(hex_buf_, (buffer).data(), \
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
} while (0)
#define LOG_PACKET_SENDING(data, len) \
do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Sending raw: %s", \
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
} while (0)
#else #else
#define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0)
@@ -229,6 +245,8 @@ APIError APIFrameHelper::init_common_() {
HELPER_LOG("Bad state for init %d", (int) state_); HELPER_LOG("Bad state for init %d", (int) state_);
return APIError::BAD_STATE; return APIError::BAD_STATE;
} }
// Cache peername now while socket is valid - needed for error logging after socket failure
this->socket_->getpeername_to(this->client_peername_);
int err = this->socket_->setblocking(false); int err = this->socket_->setblocking(false);
if (err != 0) { if (err != 0) {
state_ = State::FAILED; state_ = State::FAILED;

View File

@@ -29,24 +29,28 @@ static constexpr uint16_t MAX_MESSAGE_SIZE = 8192; // 8 KiB for ESP8266
static constexpr uint16_t MAX_MESSAGE_SIZE = 32768; // 32 KiB for ESP32 and other platforms static constexpr uint16_t MAX_MESSAGE_SIZE = 32768; // 32 KiB for ESP32 and other platforms
#endif #endif
// Forward declaration // Maximum number of messages to batch in a single write operation
struct ClientInfo; // Must be >= MAX_INITIAL_PER_BATCH in api_connection.h (enforced by static_assert there)
static constexpr size_t MAX_MESSAGES_PER_BATCH = 34;
class ProtoWriteBuffer; class ProtoWriteBuffer;
// Max client name length (e.g., "Home Assistant 2026.1.0.dev0" = 28 chars)
static constexpr size_t CLIENT_INFO_NAME_MAX_LEN = 32;
struct ReadPacketBuffer { struct ReadPacketBuffer {
const uint8_t *data; // Points directly into frame helper's rx_buf_ (valid until next read_packet call) const uint8_t *data; // Points directly into frame helper's rx_buf_ (valid until next read_packet call)
uint16_t data_len; uint16_t data_len;
uint16_t type; uint16_t type;
}; };
// Packed packet info structure to minimize memory usage // Packed message info structure to minimize memory usage
struct PacketInfo { struct MessageInfo {
uint16_t offset; // Offset in buffer where message starts uint16_t offset; // Offset in buffer where message starts
uint16_t payload_size; // Size of the message payload uint16_t payload_size; // Size of the message payload
uint8_t message_type; // Message type (0-255) uint8_t message_type; // Message type (0-255)
PacketInfo(uint8_t type, uint16_t off, uint16_t size) : offset(off), payload_size(size), message_type(type) {} MessageInfo(uint8_t type, uint16_t off, uint16_t size) : offset(off), payload_size(size), message_type(type) {}
}; };
enum class APIError : uint16_t { enum class APIError : uint16_t {
@@ -82,14 +86,23 @@ const LogString *api_error_to_logstr(APIError err);
class APIFrameHelper { class APIFrameHelper {
public: public:
APIFrameHelper() = default; APIFrameHelper() = default;
explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info) explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket) : socket_(std::move(socket)) {}
: socket_(std::move(socket)), client_info_(client_info) {}
// Get client name (null-terminated)
const char *get_client_name() const { return this->client_name_; }
// Get client peername/IP (null-terminated, cached at init time for availability after socket failure)
const char *get_client_peername() const { return this->client_peername_; }
// Set client name from buffer with length (truncates if needed)
void set_client_name(const char *name, size_t len) {
size_t copy_len = std::min(len, sizeof(this->client_name_) - 1);
memcpy(this->client_name_, name, copy_len);
this->client_name_[copy_len] = '\0';
}
virtual ~APIFrameHelper() = default; virtual ~APIFrameHelper() = default;
virtual APIError init() = 0; virtual APIError init() = 0;
virtual APIError loop(); virtual APIError loop();
virtual APIError read_packet(ReadPacketBuffer *buffer) = 0; virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; } bool can_write_without_blocking() { return this->state_ == State::DATA && this->tx_buf_count_ == 0; }
std::string getpeername() { return socket_->getpeername(); }
int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); } int getpeername(struct sockaddr *addr, socklen_t *addrlen) { return socket_->getpeername(addr, addrlen); }
APIError close() { APIError close() {
state_ = State::CLOSED; state_ = State::CLOSED;
@@ -107,11 +120,32 @@ class APIFrameHelper {
} }
return APIError::OK; return APIError::OK;
} }
/// Toggle TCP_NODELAY socket option to control Nagle's algorithm.
///
/// This is used to allow log messages to coalesce (Nagle enabled) while keeping
/// state updates low-latency (NODELAY enabled). Without this, many small log
/// packets fill the TCP send buffer, crowding out important state updates.
///
/// State is tracked to minimize setsockopt() overhead - on lwip_raw (ESP8266/RP2040)
/// this is just a boolean assignment; on other platforms it's a lightweight syscall.
///
/// @param enable true to enable NODELAY (disable Nagle), false to enable Nagle
/// @return true if successful or already in desired state
bool set_nodelay(bool enable) {
if (this->nodelay_enabled_ == enable)
return true;
int val = enable ? 1 : 0;
int err = this->socket_->setsockopt(IPPROTO_TCP, TCP_NODELAY, &val, sizeof(int));
if (err == 0) {
this->nodelay_enabled_ = enable;
}
return err == 0;
}
virtual APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) = 0; virtual APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) = 0;
// Write multiple protobuf packets in a single operation // Write multiple protobuf messages in a single operation
// packets contains (message_type, offset, length) for each message in the buffer // messages contains (message_type, offset, length) for each message in the buffer
// The buffer contains all messages with appropriate padding before each // The buffer contains all messages with appropriate padding before each
virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) = 0; virtual APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) = 0;
// Get the frame header padding required by this protocol // Get the frame header padding required by this protocol
uint8_t frame_header_padding() const { return frame_header_padding_; } uint8_t frame_header_padding() const { return frame_header_padding_; }
// Get the frame footer size required by this protocol // Get the frame footer size required by this protocol
@@ -127,12 +161,6 @@ class APIFrameHelper {
// Use swap trick since shrink_to_fit() is non-binding and may be ignored // Use swap trick since shrink_to_fit() is non-binding and may be ignored
std::vector<uint8_t>().swap(this->rx_buf_); std::vector<uint8_t>().swap(this->rx_buf_);
} }
// reusable_iovs_: Safe to release unconditionally.
// Only used within write_protobuf_packets() calls - cleared at start,
// populated with pointers, used for writev(), then function returns.
// The iovecs contain stale pointers after the call (data was either sent
// or copied to tx_buf_), and are cleared on next write_protobuf_packets().
std::vector<struct iovec>().swap(this->reusable_iovs_);
} }
protected: protected:
@@ -186,12 +214,12 @@ class APIFrameHelper {
// Containers (size varies, but typically 12+ bytes on 32-bit) // Containers (size varies, but typically 12+ bytes on 32-bit)
std::array<std::unique_ptr<SendBuffer>, API_MAX_SEND_QUEUE> tx_buf_; std::array<std::unique_ptr<SendBuffer>, API_MAX_SEND_QUEUE> tx_buf_;
std::vector<struct iovec> reusable_iovs_;
std::vector<uint8_t> rx_buf_; std::vector<uint8_t> rx_buf_;
// Pointer to client info (4 bytes on 32-bit) // Client name buffer - stores name from Hello message or initial peername
// Note: The pointed-to ClientInfo object must outlive this APIFrameHelper instance. char client_name_[CLIENT_INFO_NAME_MAX_LEN]{};
const ClientInfo *client_info_{nullptr}; // Cached peername/IP address - captured at init time for availability after socket failure
char client_peername_[socket::SOCKADDR_STR_LEN]{};
// Group smaller types together // Group smaller types together
uint16_t rx_buf_len_ = 0; uint16_t rx_buf_len_ = 0;
@@ -201,7 +229,10 @@ class APIFrameHelper {
uint8_t tx_buf_head_{0}; uint8_t tx_buf_head_{0};
uint8_t tx_buf_tail_{0}; uint8_t tx_buf_tail_{0};
uint8_t tx_buf_count_{0}; uint8_t tx_buf_count_{0};
// 8 bytes total, 0 bytes padding // Tracks TCP_NODELAY state to minimize setsockopt() calls. Initialized to true
// since init_common_() enables NODELAY. Used by set_nodelay() to allow log
// messages to coalesce while keeping state updates low-latency.
bool nodelay_enabled_{true};
// Common initialization for both plaintext and noise protocols // Common initialization for both plaintext and noise protocols
APIError init_common_(); APIError init_common_();

View File

@@ -24,12 +24,29 @@ static const char *const PROLOGUE_INIT = "NoiseAPIInit";
#endif #endif
static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit") static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
#define HELPER_LOG(msg, ...) \ // Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) \
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Received frame: %s", \
format_hex_pretty_to(hex_buf_, (buffer).data(), \
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
} while (0)
#define LOG_PACKET_SENDING(data, len) \
do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Sending raw: %s", \
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
} while (0)
#else #else
#define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0)
@@ -415,12 +432,12 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) { APIError APINoiseFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) {
// Resize to include MAC space (required for Noise encryption) // Resize to include MAC space (required for Noise encryption)
buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_); buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
PacketInfo packet{type, 0, MessageInfo msg{type, 0,
static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)}; static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1)); return write_protobuf_messages(buffer, std::span<const MessageInfo>(&msg, 1));
} }
APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) { APIError APINoiseFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) {
APIError aerr = state_action_(); APIError aerr = state_action_();
if (aerr != APIError::OK) { if (aerr != APIError::OK) {
return aerr; return aerr;
@@ -430,20 +447,20 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, st
return APIError::WOULD_BLOCK; return APIError::WOULD_BLOCK;
} }
if (packets.empty()) { if (messages.empty()) {
return APIError::OK; return APIError::OK;
} }
uint8_t *buffer_data = buffer.get_buffer()->data(); uint8_t *buffer_data = buffer.get_buffer()->data();
this->reusable_iovs_.clear(); // Stack-allocated iovec array - no heap allocation
this->reusable_iovs_.reserve(packets.size()); StaticVector<struct iovec, MAX_MESSAGES_PER_BATCH> iovs;
uint16_t total_write_len = 0; uint16_t total_write_len = 0;
// We need to encrypt each packet in place // We need to encrypt each message in place
for (const auto &packet : packets) { for (const auto &msg : messages) {
// The buffer already has padding at offset // The buffer already has padding at offset
uint8_t *buf_start = buffer_data + packet.offset; uint8_t *buf_start = buffer_data + msg.offset;
// Write noise header // Write noise header
buf_start[0] = 0x01; // indicator buf_start[0] = 0x01; // indicator
@@ -451,10 +468,10 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, st
// Write message header (to be encrypted) // Write message header (to be encrypted)
const uint8_t msg_offset = 3; const uint8_t msg_offset = 3;
buf_start[msg_offset] = static_cast<uint8_t>(packet.message_type >> 8); // type high byte buf_start[msg_offset] = static_cast<uint8_t>(msg.message_type >> 8); // type high byte
buf_start[msg_offset + 1] = static_cast<uint8_t>(packet.message_type); // type low byte buf_start[msg_offset + 1] = static_cast<uint8_t>(msg.message_type); // type low byte
buf_start[msg_offset + 2] = static_cast<uint8_t>(packet.payload_size >> 8); // data_len high byte buf_start[msg_offset + 2] = static_cast<uint8_t>(msg.payload_size >> 8); // data_len high byte
buf_start[msg_offset + 3] = static_cast<uint8_t>(packet.payload_size); // data_len low byte buf_start[msg_offset + 3] = static_cast<uint8_t>(msg.payload_size); // data_len low byte
// payload data is already in the buffer starting at offset + 7 // payload data is already in the buffer starting at offset + 7
// Make sure we have space for MAC // Make sure we have space for MAC
@@ -463,8 +480,8 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, st
// Encrypt the message in place // Encrypt the message in place
NoiseBuffer mbuf; NoiseBuffer mbuf;
noise_buffer_init(mbuf); noise_buffer_init(mbuf);
noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + packet.payload_size, noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + msg.payload_size,
4 + packet.payload_size + frame_footer_size_); 4 + msg.payload_size + frame_footer_size_);
int err = noise_cipherstate_encrypt(send_cipher_, &mbuf); int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
APIError aerr = APIError aerr =
@@ -476,14 +493,14 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, st
buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8); buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
buf_start[2] = static_cast<uint8_t>(mbuf.size); buf_start[2] = static_cast<uint8_t>(mbuf.size);
// Add iovec for this encrypted packet // Add iovec for this encrypted message
size_t packet_len = static_cast<size_t>(3 + mbuf.size); // indicator + size + encrypted data size_t msg_len = static_cast<size_t>(3 + mbuf.size); // indicator + size + encrypted data
this->reusable_iovs_.push_back({buf_start, packet_len}); iovs.push_back({buf_start, msg_len});
total_write_len += packet_len; total_write_len += msg_len;
} }
// Send all encrypted packets in one writev call // Send all encrypted messages in one writev call
return this->write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size(), total_write_len); return this->write_raw_(iovs.data(), iovs.size(), total_write_len);
} }
APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) { APIError APINoiseFrameHelper::write_frame_(const uint8_t *data, uint16_t len) {

View File

@@ -9,8 +9,8 @@ namespace esphome::api {
class APINoiseFrameHelper final : public APIFrameHelper { class APINoiseFrameHelper final : public APIFrameHelper {
public: public:
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, APINoiseContext &ctx, const ClientInfo *client_info) APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, APINoiseContext &ctx)
: APIFrameHelper(std::move(socket), client_info), ctx_(ctx) { : APIFrameHelper(std::move(socket)), ctx_(ctx) {
// Noise header structure: // Noise header structure:
// Pos 0: indicator (0x01) // Pos 0: indicator (0x01)
// Pos 1-2: encrypted payload size (16-bit big-endian) // Pos 1-2: encrypted payload size (16-bit big-endian)
@@ -23,7 +23,7 @@ class APINoiseFrameHelper final : public APIFrameHelper {
APIError loop() override; APIError loop() override;
APIError read_packet(ReadPacketBuffer *buffer) override; APIError read_packet(ReadPacketBuffer *buffer) override;
APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override; APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override;
APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override; APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) override;
protected: protected:
APIError state_action_(); APIError state_action_();

View File

@@ -1,7 +1,6 @@
#include "api_frame_helper_plaintext.h" #include "api_frame_helper_plaintext.h"
#ifdef USE_API #ifdef USE_API
#ifdef USE_API_PLAINTEXT #ifdef USE_API_PLAINTEXT
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
@@ -18,12 +17,29 @@ namespace esphome::api {
static const char *const TAG = "api.plaintext"; static const char *const TAG = "api.plaintext";
#define HELPER_LOG(msg, ...) \ // Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__) static constexpr size_t API_MAX_LOG_BYTES = 168;
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, this->client_peername_, ##__VA_ARGS__)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS #ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str()) #define LOG_PACKET_RECEIVED(buffer) \
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str()) do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Received frame: %s", \
format_hex_pretty_to(hex_buf_, (buffer).data(), \
(buffer).size() < API_MAX_LOG_BYTES ? (buffer).size() : API_MAX_LOG_BYTES)); \
} while (0)
#define LOG_PACKET_SENDING(data, len) \
do { \
char hex_buf_[format_hex_pretty_size(API_MAX_LOG_BYTES)]; \
ESP_LOGVV(TAG, "Sending raw: %s", \
format_hex_pretty_to(hex_buf_, data, (len) < API_MAX_LOG_BYTES ? (len) : API_MAX_LOG_BYTES)); \
} while (0)
#else #else
#define LOG_PACKET_RECEIVED(buffer) ((void) 0) #define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0) #define LOG_PACKET_SENDING(data, len) ((void) 0)
@@ -216,29 +232,30 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return APIError::OK; return APIError::OK;
} }
APIError APIPlaintextFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) { APIError APIPlaintextFrameHelper::write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) {
PacketInfo packet{type, 0, static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_)}; MessageInfo msg{type, 0, static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_)};
return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1)); return write_protobuf_messages(buffer, std::span<const MessageInfo>(&msg, 1));
} }
APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) { APIError APIPlaintextFrameHelper::write_protobuf_messages(ProtoWriteBuffer buffer,
std::span<const MessageInfo> messages) {
if (state_ != State::DATA) { if (state_ != State::DATA) {
return APIError::BAD_STATE; return APIError::BAD_STATE;
} }
if (packets.empty()) { if (messages.empty()) {
return APIError::OK; return APIError::OK;
} }
uint8_t *buffer_data = buffer.get_buffer()->data(); uint8_t *buffer_data = buffer.get_buffer()->data();
this->reusable_iovs_.clear(); // Stack-allocated iovec array - no heap allocation
this->reusable_iovs_.reserve(packets.size()); StaticVector<struct iovec, MAX_MESSAGES_PER_BATCH> iovs;
uint16_t total_write_len = 0; uint16_t total_write_len = 0;
for (const auto &packet : packets) { for (const auto &msg : messages) {
// Calculate varint sizes for header layout // Calculate varint sizes for header layout
uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.payload_size)); uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(msg.payload_size));
uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.message_type)); uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(msg.message_type));
uint8_t total_header_len = 1 + size_varint_len + type_varint_len; uint8_t total_header_len = 1 + size_varint_len + type_varint_len;
// Calculate where to start writing the header // Calculate where to start writing the header
@@ -266,25 +283,25 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
// //
// The message starts at offset + frame_header_padding_ // The message starts at offset + frame_header_padding_
// So we write the header starting at offset + frame_header_padding_ - total_header_len // So we write the header starting at offset + frame_header_padding_ - total_header_len
uint8_t *buf_start = buffer_data + packet.offset; uint8_t *buf_start = buffer_data + msg.offset;
uint32_t header_offset = frame_header_padding_ - total_header_len; uint32_t header_offset = frame_header_padding_ - total_header_len;
// Write the plaintext header // Write the plaintext header
buf_start[header_offset] = 0x00; // indicator buf_start[header_offset] = 0x00; // indicator
// Encode varints directly into buffer // Encode varints directly into buffer
ProtoVarInt(packet.payload_size).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len); ProtoVarInt(msg.payload_size).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len);
ProtoVarInt(packet.message_type) ProtoVarInt(msg.message_type)
.encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len); .encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
// Add iovec for this packet (header + payload) // Add iovec for this message (header + payload)
size_t packet_len = static_cast<size_t>(total_header_len + packet.payload_size); size_t msg_len = static_cast<size_t>(total_header_len + msg.payload_size);
this->reusable_iovs_.push_back({buf_start + header_offset, packet_len}); iovs.push_back({buf_start + header_offset, msg_len});
total_write_len += packet_len; total_write_len += msg_len;
} }
// Send all packets in one writev call // Send all messages in one writev call
return write_raw_(this->reusable_iovs_.data(), this->reusable_iovs_.size(), total_write_len); return write_raw_(iovs.data(), iovs.size(), total_write_len);
} }
} // namespace esphome::api } // namespace esphome::api

View File

@@ -7,8 +7,7 @@ namespace esphome::api {
class APIPlaintextFrameHelper final : public APIFrameHelper { class APIPlaintextFrameHelper final : public APIFrameHelper {
public: public:
APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info) explicit APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket) : APIFrameHelper(std::move(socket)) {
: APIFrameHelper(std::move(socket), client_info) {
// Plaintext header structure (worst case): // Plaintext header structure (worst case):
// Pos 0: indicator (0x00) // Pos 0: indicator (0x00)
// Pos 1-3: payload size varint (up to 3 bytes) // Pos 1-3: payload size varint (up to 3 bytes)
@@ -21,7 +20,7 @@ class APIPlaintextFrameHelper final : public APIFrameHelper {
APIError loop() override; APIError loop() override;
APIError read_packet(ReadPacketBuffer *buffer) override; APIError read_packet(ReadPacketBuffer *buffer) override;
APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override; APIError write_protobuf_packet(uint8_t type, ProtoWriteBuffer buffer) override;
APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override; APIError write_protobuf_messages(ProtoWriteBuffer buffer, std::span<const MessageInfo> messages) override;
protected: protected:
APIError try_read_frame_(); APIError try_read_frame_();

View File

@@ -27,7 +27,6 @@ extend google.protobuf.MessageOptions {
extend google.protobuf.FieldOptions { extend google.protobuf.FieldOptions {
optional string field_ifdef = 1042; optional string field_ifdef = 1042;
optional uint32 fixed_array_size = 50007; optional uint32 fixed_array_size = 50007;
optional bool no_zero_copy = 50008 [default=false];
optional bool fixed_array_skip_zero = 50009 [default=false]; optional bool fixed_array_skip_zero = 50009 [default=false];
optional string fixed_array_size_define = 50010; optional string fixed_array_size_define = 50010;
optional string fixed_array_with_length_define = 50011; optional string fixed_array_with_length_define = 50011;
@@ -80,4 +79,15 @@ extend google.protobuf.FieldOptions {
// Example: [(container_pointer_no_template) = "light::ColorModeMask"] // Example: [(container_pointer_no_template) = "light::ColorModeMask"]
// generates: const light::ColorModeMask *supported_color_modes{}; // generates: const light::ColorModeMask *supported_color_modes{};
optional string container_pointer_no_template = 50014; optional string container_pointer_no_template = 50014;
// packed_buffer: Expose raw packed buffer instead of decoding into container
// When set on a packed repeated field, the generated code stores a pointer
// to the raw protobuf buffer instead of decoding values. This enables
// zero-copy passthrough when the consumer can decode on-demand.
// The field must be a packed repeated field (packed=true).
// Generates three fields:
// - const uint8_t *<field>_data_{nullptr};
// - uint16_t <field>_length_{0};
// - uint16_t <field>_count_{0};
optional bool packed_buffer = 50015 [default=false];
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,10 @@
#include "esphome/components/climate/climate_traits.h" #include "esphome/components/climate/climate_traits.h"
#endif #endif
#ifdef USE_WATER_HEATER
#include "esphome/components/water_heater/water_heater.h"
#endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
#include "esphome/components/light/light_traits.h" #include "esphome/components/light/light_traits.h"
#endif #endif

View File

@@ -8,8 +8,12 @@ namespace esphome::api {
static const char *const TAG = "api.service"; static const char *const TAG = "api.service";
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
void APIServerConnectionBase::log_send_message_(const char *name, const std::string &dump) { void APIServerConnectionBase::log_send_message_(const char *name, const char *dump) {
ESP_LOGVV(TAG, "send_message %s: %s", name, dump.c_str()); ESP_LOGVV(TAG, "send_message %s: %s", name, dump);
}
void APIServerConnectionBase::log_receive_message_(const LogString *name, const ProtoMessage &msg) {
DumpBuffer dump_buf;
ESP_LOGVV(TAG, "%s: %s", LOG_STR_ARG(name), msg.dump_to(dump_buf));
} }
#endif #endif
@@ -19,27 +23,16 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
HelloRequest msg; HelloRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_hello_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_hello_request"), msg);
#endif #endif
this->on_hello_request(msg); this->on_hello_request(msg);
break; break;
} }
#ifdef USE_API_PASSWORD
case AuthenticationRequest::MESSAGE_TYPE: {
AuthenticationRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_authentication_request: %s", msg.dump().c_str());
#endif
this->on_authentication_request(msg);
break;
}
#endif
case DisconnectRequest::MESSAGE_TYPE: { case DisconnectRequest::MESSAGE_TYPE: {
DisconnectRequest msg; DisconnectRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_disconnect_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_disconnect_request"), msg);
#endif #endif
this->on_disconnect_request(msg); this->on_disconnect_request(msg);
break; break;
@@ -48,7 +41,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
DisconnectResponse msg; DisconnectResponse msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_disconnect_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_disconnect_response"), msg);
#endif #endif
this->on_disconnect_response(msg); this->on_disconnect_response(msg);
break; break;
@@ -57,7 +50,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
PingRequest msg; PingRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_ping_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_ping_request"), msg);
#endif #endif
this->on_ping_request(msg); this->on_ping_request(msg);
break; break;
@@ -66,7 +59,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
PingResponse msg; PingResponse msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_ping_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_ping_response"), msg);
#endif #endif
this->on_ping_response(msg); this->on_ping_response(msg);
break; break;
@@ -75,7 +68,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
DeviceInfoRequest msg; DeviceInfoRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_device_info_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_device_info_request"), msg);
#endif #endif
this->on_device_info_request(msg); this->on_device_info_request(msg);
break; break;
@@ -84,7 +77,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ListEntitiesRequest msg; ListEntitiesRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_list_entities_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_list_entities_request"), msg);
#endif #endif
this->on_list_entities_request(msg); this->on_list_entities_request(msg);
break; break;
@@ -93,7 +86,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeStatesRequest msg; SubscribeStatesRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_states_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_states_request"), msg);
#endif #endif
this->on_subscribe_states_request(msg); this->on_subscribe_states_request(msg);
break; break;
@@ -102,7 +95,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeLogsRequest msg; SubscribeLogsRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_logs_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_logs_request"), msg);
#endif #endif
this->on_subscribe_logs_request(msg); this->on_subscribe_logs_request(msg);
break; break;
@@ -112,7 +105,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
CoverCommandRequest msg; CoverCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_cover_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_cover_command_request"), msg);
#endif #endif
this->on_cover_command_request(msg); this->on_cover_command_request(msg);
break; break;
@@ -123,7 +116,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
FanCommandRequest msg; FanCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_fan_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_fan_command_request"), msg);
#endif #endif
this->on_fan_command_request(msg); this->on_fan_command_request(msg);
break; break;
@@ -134,7 +127,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
LightCommandRequest msg; LightCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_light_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_light_command_request"), msg);
#endif #endif
this->on_light_command_request(msg); this->on_light_command_request(msg);
break; break;
@@ -145,7 +138,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SwitchCommandRequest msg; SwitchCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_switch_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_switch_command_request"), msg);
#endif #endif
this->on_switch_command_request(msg); this->on_switch_command_request(msg);
break; break;
@@ -156,7 +149,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeHomeassistantServicesRequest msg; SubscribeHomeassistantServicesRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_homeassistant_services_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_homeassistant_services_request"), msg);
#endif #endif
this->on_subscribe_homeassistant_services_request(msg); this->on_subscribe_homeassistant_services_request(msg);
break; break;
@@ -166,7 +159,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
GetTimeResponse msg; GetTimeResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_get_time_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_get_time_response"), msg);
#endif #endif
this->on_get_time_response(msg); this->on_get_time_response(msg);
break; break;
@@ -176,7 +169,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeHomeAssistantStatesRequest msg; SubscribeHomeAssistantStatesRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_home_assistant_states_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_home_assistant_states_request"), msg);
#endif #endif
this->on_subscribe_home_assistant_states_request(msg); this->on_subscribe_home_assistant_states_request(msg);
break; break;
@@ -187,7 +180,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
HomeAssistantStateResponse msg; HomeAssistantStateResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_home_assistant_state_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_home_assistant_state_response"), msg);
#endif #endif
this->on_home_assistant_state_response(msg); this->on_home_assistant_state_response(msg);
break; break;
@@ -198,7 +191,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ExecuteServiceRequest msg; ExecuteServiceRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_execute_service_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_execute_service_request"), msg);
#endif #endif
this->on_execute_service_request(msg); this->on_execute_service_request(msg);
break; break;
@@ -209,7 +202,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
CameraImageRequest msg; CameraImageRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_camera_image_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_camera_image_request"), msg);
#endif #endif
this->on_camera_image_request(msg); this->on_camera_image_request(msg);
break; break;
@@ -220,7 +213,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ClimateCommandRequest msg; ClimateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_climate_command_request"), msg);
#endif #endif
this->on_climate_command_request(msg); this->on_climate_command_request(msg);
break; break;
@@ -231,7 +224,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
NumberCommandRequest msg; NumberCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_number_command_request"), msg);
#endif #endif
this->on_number_command_request(msg); this->on_number_command_request(msg);
break; break;
@@ -242,7 +235,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SelectCommandRequest msg; SelectCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_select_command_request"), msg);
#endif #endif
this->on_select_command_request(msg); this->on_select_command_request(msg);
break; break;
@@ -253,7 +246,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SirenCommandRequest msg; SirenCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_siren_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_siren_command_request"), msg);
#endif #endif
this->on_siren_command_request(msg); this->on_siren_command_request(msg);
break; break;
@@ -264,7 +257,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
LockCommandRequest msg; LockCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_lock_command_request"), msg);
#endif #endif
this->on_lock_command_request(msg); this->on_lock_command_request(msg);
break; break;
@@ -275,7 +268,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ButtonCommandRequest msg; ButtonCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_button_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_button_command_request"), msg);
#endif #endif
this->on_button_command_request(msg); this->on_button_command_request(msg);
break; break;
@@ -286,7 +279,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
MediaPlayerCommandRequest msg; MediaPlayerCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_media_player_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_media_player_command_request"), msg);
#endif #endif
this->on_media_player_command_request(msg); this->on_media_player_command_request(msg);
break; break;
@@ -297,7 +290,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeBluetoothLEAdvertisementsRequest msg; SubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_bluetooth_le_advertisements_request"), msg);
#endif #endif
this->on_subscribe_bluetooth_le_advertisements_request(msg); this->on_subscribe_bluetooth_le_advertisements_request(msg);
break; break;
@@ -308,7 +301,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothDeviceRequest msg; BluetoothDeviceRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_device_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_device_request"), msg);
#endif #endif
this->on_bluetooth_device_request(msg); this->on_bluetooth_device_request(msg);
break; break;
@@ -319,7 +312,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTGetServicesRequest msg; BluetoothGATTGetServicesRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_get_services_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_get_services_request"), msg);
#endif #endif
this->on_bluetooth_gatt_get_services_request(msg); this->on_bluetooth_gatt_get_services_request(msg);
break; break;
@@ -330,7 +323,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTReadRequest msg; BluetoothGATTReadRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_read_request"), msg);
#endif #endif
this->on_bluetooth_gatt_read_request(msg); this->on_bluetooth_gatt_read_request(msg);
break; break;
@@ -341,7 +334,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTWriteRequest msg; BluetoothGATTWriteRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_write_request"), msg);
#endif #endif
this->on_bluetooth_gatt_write_request(msg); this->on_bluetooth_gatt_write_request(msg);
break; break;
@@ -352,7 +345,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTReadDescriptorRequest msg; BluetoothGATTReadDescriptorRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_descriptor_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_read_descriptor_request"), msg);
#endif #endif
this->on_bluetooth_gatt_read_descriptor_request(msg); this->on_bluetooth_gatt_read_descriptor_request(msg);
break; break;
@@ -363,7 +356,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTWriteDescriptorRequest msg; BluetoothGATTWriteDescriptorRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_descriptor_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_write_descriptor_request"), msg);
#endif #endif
this->on_bluetooth_gatt_write_descriptor_request(msg); this->on_bluetooth_gatt_write_descriptor_request(msg);
break; break;
@@ -374,7 +367,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothGATTNotifyRequest msg; BluetoothGATTNotifyRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_notify_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_gatt_notify_request"), msg);
#endif #endif
this->on_bluetooth_gatt_notify_request(msg); this->on_bluetooth_gatt_notify_request(msg);
break; break;
@@ -385,7 +378,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeBluetoothConnectionsFreeRequest msg; SubscribeBluetoothConnectionsFreeRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_bluetooth_connections_free_request"), msg);
#endif #endif
this->on_subscribe_bluetooth_connections_free_request(msg); this->on_subscribe_bluetooth_connections_free_request(msg);
break; break;
@@ -396,7 +389,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
UnsubscribeBluetoothLEAdvertisementsRequest msg; UnsubscribeBluetoothLEAdvertisementsRequest msg;
// Empty message: no decode needed // Empty message: no decode needed
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_unsubscribe_bluetooth_le_advertisements_request"), msg);
#endif #endif
this->on_unsubscribe_bluetooth_le_advertisements_request(msg); this->on_unsubscribe_bluetooth_le_advertisements_request(msg);
break; break;
@@ -407,7 +400,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
SubscribeVoiceAssistantRequest msg; SubscribeVoiceAssistantRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_subscribe_voice_assistant_request"), msg);
#endif #endif
this->on_subscribe_voice_assistant_request(msg); this->on_subscribe_voice_assistant_request(msg);
break; break;
@@ -418,7 +411,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantResponse msg; VoiceAssistantResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_response"), msg);
#endif #endif
this->on_voice_assistant_response(msg); this->on_voice_assistant_response(msg);
break; break;
@@ -429,7 +422,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantEventResponse msg; VoiceAssistantEventResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_event_response"), msg);
#endif #endif
this->on_voice_assistant_event_response(msg); this->on_voice_assistant_event_response(msg);
break; break;
@@ -440,7 +433,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
AlarmControlPanelCommandRequest msg; AlarmControlPanelCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_alarm_control_panel_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_alarm_control_panel_command_request"), msg);
#endif #endif
this->on_alarm_control_panel_command_request(msg); this->on_alarm_control_panel_command_request(msg);
break; break;
@@ -451,7 +444,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
TextCommandRequest msg; TextCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_text_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_text_command_request"), msg);
#endif #endif
this->on_text_command_request(msg); this->on_text_command_request(msg);
break; break;
@@ -462,7 +455,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
DateCommandRequest msg; DateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_date_command_request"), msg);
#endif #endif
this->on_date_command_request(msg); this->on_date_command_request(msg);
break; break;
@@ -473,7 +466,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
TimeCommandRequest msg; TimeCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_time_command_request"), msg);
#endif #endif
this->on_time_command_request(msg); this->on_time_command_request(msg);
break; break;
@@ -484,7 +477,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantAudio msg; VoiceAssistantAudio msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_audio"), msg);
#endif #endif
this->on_voice_assistant_audio(msg); this->on_voice_assistant_audio(msg);
break; break;
@@ -495,7 +488,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ValveCommandRequest msg; ValveCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_valve_command_request"), msg);
#endif #endif
this->on_valve_command_request(msg); this->on_valve_command_request(msg);
break; break;
@@ -506,7 +499,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
DateTimeCommandRequest msg; DateTimeCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_date_time_command_request"), msg);
#endif #endif
this->on_date_time_command_request(msg); this->on_date_time_command_request(msg);
break; break;
@@ -517,7 +510,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantTimerEventResponse msg; VoiceAssistantTimerEventResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_timer_event_response"), msg);
#endif #endif
this->on_voice_assistant_timer_event_response(msg); this->on_voice_assistant_timer_event_response(msg);
break; break;
@@ -528,7 +521,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
UpdateCommandRequest msg; UpdateCommandRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_update_command_request"), msg);
#endif #endif
this->on_update_command_request(msg); this->on_update_command_request(msg);
break; break;
@@ -539,7 +532,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantAnnounceRequest msg; VoiceAssistantAnnounceRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_announce_request"), msg);
#endif #endif
this->on_voice_assistant_announce_request(msg); this->on_voice_assistant_announce_request(msg);
break; break;
@@ -550,7 +543,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantConfigurationRequest msg; VoiceAssistantConfigurationRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_configuration_request"), msg);
#endif #endif
this->on_voice_assistant_configuration_request(msg); this->on_voice_assistant_configuration_request(msg);
break; break;
@@ -561,7 +554,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
VoiceAssistantSetConfiguration msg; VoiceAssistantSetConfiguration msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_voice_assistant_set_configuration"), msg);
#endif #endif
this->on_voice_assistant_set_configuration(msg); this->on_voice_assistant_set_configuration(msg);
break; break;
@@ -572,7 +565,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
NoiseEncryptionSetKeyRequest msg; NoiseEncryptionSetKeyRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_noise_encryption_set_key_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_noise_encryption_set_key_request"), msg);
#endif #endif
this->on_noise_encryption_set_key_request(msg); this->on_noise_encryption_set_key_request(msg);
break; break;
@@ -583,7 +576,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
BluetoothScannerSetModeRequest msg; BluetoothScannerSetModeRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_scanner_set_mode_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_bluetooth_scanner_set_mode_request"), msg);
#endif #endif
this->on_bluetooth_scanner_set_mode_request(msg); this->on_bluetooth_scanner_set_mode_request(msg);
break; break;
@@ -594,7 +587,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ZWaveProxyFrame msg; ZWaveProxyFrame msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_z_wave_proxy_frame: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_z_wave_proxy_frame"), msg);
#endif #endif
this->on_z_wave_proxy_frame(msg); this->on_z_wave_proxy_frame(msg);
break; break;
@@ -605,7 +598,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
ZWaveProxyRequest msg; ZWaveProxyRequest msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_z_wave_proxy_request: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_z_wave_proxy_request"), msg);
#endif #endif
this->on_z_wave_proxy_request(msg); this->on_z_wave_proxy_request(msg);
break; break;
@@ -616,11 +609,33 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
HomeassistantActionResponse msg; HomeassistantActionResponse msg;
msg.decode(msg_data, msg_size); msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_homeassistant_action_response: %s", msg.dump().c_str()); this->log_receive_message_(LOG_STR("on_homeassistant_action_response"), msg);
#endif #endif
this->on_homeassistant_action_response(msg); this->on_homeassistant_action_response(msg);
break; break;
} }
#endif
#ifdef USE_WATER_HEATER
case WaterHeaterCommandRequest::MESSAGE_TYPE: {
WaterHeaterCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
this->log_receive_message_(LOG_STR("on_water_heater_command_request"), msg);
#endif
this->on_water_heater_command_request(msg);
break;
}
#endif
#ifdef USE_IR_RF
case InfraredRFTransmitRawTimingsRequest::MESSAGE_TYPE: {
InfraredRFTransmitRawTimingsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
this->log_receive_message_(LOG_STR("on_infrared_rf_transmit_raw_timings_request"), msg);
#endif
this->on_infrared_rf_transmit_raw_timings_request(msg);
break;
}
#endif #endif
default: default:
break; break;
@@ -632,13 +647,6 @@ void APIServerConnection::on_hello_request(const HelloRequest &msg) {
this->on_fatal_error(); this->on_fatal_error();
} }
} }
#ifdef USE_API_PASSWORD
void APIServerConnection::on_authentication_request(const AuthenticationRequest &msg) {
if (!this->send_authenticate_response(msg)) {
this->on_fatal_error();
}
}
#endif
void APIServerConnection::on_disconnect_request(const DisconnectRequest &msg) { void APIServerConnection::on_disconnect_request(const DisconnectRequest &msg) {
if (!this->send_disconnect_response(msg)) { if (!this->send_disconnect_response(msg)) {
this->on_fatal_error(); this->on_fatal_error();
@@ -826,14 +834,16 @@ void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) { th
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); } void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); }
#endif #endif
#ifdef USE_IR_RF
void APIServerConnection::on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) {
this->infrared_rf_transmit_raw_timings(msg);
}
#endif
void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) { void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
// Check authentication/connection requirements for messages // Check authentication/connection requirements for messages
switch (msg_type) { switch (msg_type) {
case HelloRequest::MESSAGE_TYPE: // No setup required case HelloRequest::MESSAGE_TYPE: // No setup required
#ifdef USE_API_PASSWORD
case AuthenticationRequest::MESSAGE_TYPE: // No setup required
#endif
case DisconnectRequest::MESSAGE_TYPE: // No setup required case DisconnectRequest::MESSAGE_TYPE: // No setup required
case PingRequest::MESSAGE_TYPE: // No setup required case PingRequest::MESSAGE_TYPE: // No setup required
break; // Skip all checks for these messages break; // Skip all checks for these messages

View File

@@ -12,24 +12,22 @@ class APIServerConnectionBase : public ProtoService {
public: public:
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
protected: protected:
void log_send_message_(const char *name, const std::string &dump); void log_send_message_(const char *name, const char *dump);
void log_receive_message_(const LogString *name, const ProtoMessage &msg);
public: public:
#endif #endif
bool send_message(const ProtoMessage &msg, uint8_t message_type) { bool send_message(const ProtoMessage &msg, uint8_t message_type) {
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
this->log_send_message_(msg.message_name(), msg.dump()); DumpBuffer dump_buf;
this->log_send_message_(msg.message_name(), msg.dump_to(dump_buf));
#endif #endif
return this->send_message_(msg, message_type); return this->send_message_(msg, message_type);
} }
virtual void on_hello_request(const HelloRequest &value){}; virtual void on_hello_request(const HelloRequest &value){};
#ifdef USE_API_PASSWORD
virtual void on_authentication_request(const AuthenticationRequest &value){};
#endif
virtual void on_disconnect_request(const DisconnectRequest &value){}; virtual void on_disconnect_request(const DisconnectRequest &value){};
virtual void on_disconnect_response(const DisconnectResponse &value){}; virtual void on_disconnect_response(const DisconnectResponse &value){};
virtual void on_ping_request(const PingRequest &value){}; virtual void on_ping_request(const PingRequest &value){};
@@ -91,6 +89,10 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_climate_command_request(const ClimateCommandRequest &value){}; virtual void on_climate_command_request(const ClimateCommandRequest &value){};
#endif #endif
#ifdef USE_WATER_HEATER
virtual void on_water_heater_command_request(const WaterHeaterCommandRequest &value){};
#endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
virtual void on_number_command_request(const NumberCommandRequest &value){}; virtual void on_number_command_request(const NumberCommandRequest &value){};
#endif #endif
@@ -217,6 +219,11 @@ class APIServerConnectionBase : public ProtoService {
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){}; virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
#endif #endif
#ifdef USE_IR_RF
virtual void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &value){};
#endif
protected: protected:
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override; void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
}; };
@@ -224,9 +231,6 @@ class APIServerConnectionBase : public ProtoService {
class APIServerConnection : public APIServerConnectionBase { class APIServerConnection : public APIServerConnectionBase {
public: public:
virtual bool send_hello_response(const HelloRequest &msg) = 0; virtual bool send_hello_response(const HelloRequest &msg) = 0;
#ifdef USE_API_PASSWORD
virtual bool send_authenticate_response(const AuthenticationRequest &msg) = 0;
#endif
virtual bool send_disconnect_response(const DisconnectRequest &msg) = 0; virtual bool send_disconnect_response(const DisconnectRequest &msg) = 0;
virtual bool send_ping_response(const PingRequest &msg) = 0; virtual bool send_ping_response(const PingRequest &msg) = 0;
virtual bool send_device_info_response(const DeviceInfoRequest &msg) = 0; virtual bool send_device_info_response(const DeviceInfoRequest &msg) = 0;
@@ -350,12 +354,12 @@ class APIServerConnection : public APIServerConnectionBase {
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
virtual void zwave_proxy_request(const ZWaveProxyRequest &msg) = 0; virtual void zwave_proxy_request(const ZWaveProxyRequest &msg) = 0;
#endif
#ifdef USE_IR_RF
virtual void infrared_rf_transmit_raw_timings(const InfraredRFTransmitRawTimingsRequest &msg) = 0;
#endif #endif
protected: protected:
void on_hello_request(const HelloRequest &msg) override; void on_hello_request(const HelloRequest &msg) override;
#ifdef USE_API_PASSWORD
void on_authentication_request(const AuthenticationRequest &msg) override;
#endif
void on_disconnect_request(const DisconnectRequest &msg) override; void on_disconnect_request(const DisconnectRequest &msg) override;
void on_ping_request(const PingRequest &msg) override; void on_ping_request(const PingRequest &msg) override;
void on_device_info_request(const DeviceInfoRequest &msg) override; void on_device_info_request(const DeviceInfoRequest &msg) override;
@@ -479,6 +483,9 @@ class APIServerConnection : public APIServerConnectionBase {
#endif #endif
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override; void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
#endif
#ifdef USE_IR_RF
void on_infrared_rf_transmit_raw_timings_request(const InfraredRFTransmitRawTimingsRequest &msg) override;
#endif #endif
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override; void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
}; };

View File

@@ -125,15 +125,18 @@ void APIServer::loop() {
if (!sock) if (!sock)
break; break;
char peername[socket::SOCKADDR_STR_LEN];
sock->getpeername_to(peername);
// Check if we're at the connection limit // Check if we're at the connection limit
if (this->clients_.size() >= this->max_connections_) { if (this->clients_.size() >= this->max_connections_) {
ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, sock->getpeername().c_str()); ESP_LOGW(TAG, "Max connections (%d), rejecting %s", this->max_connections_, peername);
// Immediately close - socket destructor will handle cleanup // Immediately close - socket destructor will handle cleanup
sock.reset(); sock.reset();
continue; continue;
} }
ESP_LOGD(TAG, "Accept %s", sock->getpeername().c_str()); ESP_LOGD(TAG, "Accept %s", peername);
auto *conn = new APIConnection(std::move(sock), this); auto *conn = new APIConnection(std::move(sock), this);
this->clients_.emplace_back(conn); this->clients_.emplace_back(conn);
@@ -166,8 +169,7 @@ void APIServer::loop() {
// Network is down - disconnect all clients // Network is down - disconnect all clients
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
client->on_fatal_error(); client->on_fatal_error();
ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(), client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("Network down; disconnect"));
client->client_info_.peername.c_str());
} }
// Continue to process and clean up the clients below // Continue to process and clean up the clients below
} }
@@ -184,13 +186,16 @@ void APIServer::loop() {
} }
// Rare case: handle disconnection // Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_.name, client->client_info_.peername);
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->unregister_active_action_calls_for_connection(client.get()); this->unregister_active_action_calls_for_connection(client.get());
#endif #endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.name.c_str()); ESP_LOGV(TAG, "Remove connection %s", client->get_name());
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
// Save client info before removal for the trigger
std::string client_name(client->get_name());
std::string client_peername(client->get_peername());
#endif
// Swap with the last element and pop (avoids expensive vector shifts) // Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) { if (client_index < this->clients_.size() - 1) {
@@ -203,6 +208,11 @@ void APIServer::loop() {
this->status_set_warning(); this->status_set_warning();
this->last_connected_ = App.get_loop_component_start_time(); this->last_connected_ = App.get_loop_component_start_time();
} }
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
// Fire trigger after client is removed so api.connected reflects the true state
this->client_disconnected_trigger_->trigger(client_name, client_peername);
#endif
// Don't increment client_index since we need to process the swapped element // Don't increment client_index since we need to process the swapped element
} }
} }
@@ -224,38 +234,6 @@ void APIServer::dump_config() {
#endif #endif
} }
#ifdef USE_API_PASSWORD
bool APIServer::check_password(const uint8_t *password_data, size_t password_len) const {
// depend only on input password length
const char *a = this->password_.c_str();
uint32_t len_a = this->password_.length();
const char *b = reinterpret_cast<const char *>(password_data);
uint32_t len_b = password_len;
// disable optimization with volatile
volatile uint32_t length = len_b;
volatile const char *left = nullptr;
volatile const char *right = b;
uint8_t result = 0;
if (len_a == length) {
left = *((volatile const char **) &a);
result = 0;
}
if (len_a != length) {
left = b;
result = 1;
}
for (size_t i = 0; i < length; i++) {
result |= *left++ ^ *right++; // NOLINT
}
return result == 0;
}
#endif
void APIServer::handle_disconnect(APIConnection *conn) {} void APIServer::handle_disconnect(APIConnection *conn) {}
// Macro for controller update dispatch // Macro for controller update dispatch
@@ -263,8 +241,10 @@ void APIServer::handle_disconnect(APIConnection *conn) {}
void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \ void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
if (obj->is_internal()) \ if (obj->is_internal()) \
return; \ return; \
for (auto &c : this->clients_) \ for (auto &c : this->clients_) { \
c->send_##entity_name##_state(obj); \ if (c->flags_.state_subscription) \
c->send_##entity_name##_state(obj); \
} \
} }
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
@@ -335,14 +315,18 @@ API_DISPATCH_UPDATE(valve::Valve, valve)
API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player) API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player)
#endif #endif
#ifdef USE_WATER_HEATER
API_DISPATCH_UPDATE(water_heater::WaterHeater, water_heater)
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
// Event is a special case - unlike other entities with simple state fields,
// events store their state in a member accessed via obj->get_last_event_type()
void APIServer::on_event(event::Event *obj) { void APIServer::on_event(event::Event *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
for (auto &c : this->clients_) for (auto &c : this->clients_) {
c->send_event(obj, obj->get_last_event_type()); if (c->flags_.state_subscription)
c->send_event(obj);
}
} }
#endif #endif
@@ -351,8 +335,10 @@ void APIServer::on_event(event::Event *obj) {
void APIServer::on_update(update::UpdateEntity *obj) { void APIServer::on_update(update::UpdateEntity *obj) {
if (obj->is_internal()) if (obj->is_internal())
return; return;
for (auto &c : this->clients_) for (auto &c : this->clients_) {
c->send_update_state(obj); if (c->flags_.state_subscription)
c->send_update_state(obj);
}
} }
#endif #endif
@@ -365,6 +351,21 @@ void APIServer::on_zwave_proxy_request(const esphome::api::ProtoMessage &msg) {
} }
#endif #endif
#ifdef USE_IR_RF
void APIServer::send_infrared_rf_receive_event([[maybe_unused]] uint32_t device_id, uint32_t key,
const std::vector<int32_t> *timings) {
InfraredRFReceiveEvent resp{};
#ifdef USE_DEVICES
resp.device_id = device_id;
#endif
resp.key = key;
resp.timings = timings;
for (auto &c : this->clients_)
c->send_infrared_rf_receive_event(resp);
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel) API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
#endif #endif
@@ -373,10 +374,6 @@ float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI;
void APIServer::set_port(uint16_t port) { this->port_ = port; } void APIServer::set_port(uint16_t port) { this->port_ = port; }
#ifdef USE_API_PASSWORD
void APIServer::set_password(const std::string &password) { this->password_ = password; }
#endif
void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; } void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
#ifdef USE_API_HOMEASSISTANT_SERVICES #ifdef USE_API_HOMEASSISTANT_SERVICES
@@ -390,7 +387,7 @@ void APIServer::register_action_response_callback(uint32_t call_id, ActionRespon
this->action_response_callbacks_.push_back({call_id, std::move(callback)}); this->action_response_callbacks_.push_back({call_id, std::move(callback)});
} }
void APIServer::handle_action_response(uint32_t call_id, bool success, const std::string &error_message) { void APIServer::handle_action_response(uint32_t call_id, bool success, StringRef error_message) {
for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) { for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) {
if (it->call_id == call_id) { if (it->call_id == call_id) {
auto callback = std::move(it->callback); auto callback = std::move(it->callback);
@@ -402,7 +399,7 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
} }
} }
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
void APIServer::handle_action_response(uint32_t call_id, bool success, const std::string &error_message, void APIServer::handle_action_response(uint32_t call_id, bool success, StringRef error_message,
const uint8_t *response_data, size_t response_data_len) { const uint8_t *response_data, size_t response_data_len) {
for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) { for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) {
if (it->call_id == call_id) { if (it->call_id == call_id) {
@@ -420,8 +417,8 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
#ifdef USE_API_HOMEASSISTANT_STATES #ifdef USE_API_HOMEASSISTANT_STATES
// Helper to add subscription (reduces duplication) // Helper to add subscription (reduces duplication)
void APIServer::add_state_subscription_(const char *entity_id, const char *attribute, void APIServer::add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
std::function<void(std::string)> f, bool once) { bool once) {
this->state_subs_.push_back(HomeAssistantStateSubscription{ this->state_subs_.push_back(HomeAssistantStateSubscription{
.entity_id = entity_id, .attribute = attribute, .callback = std::move(f), .once = once, .entity_id = entity_id, .attribute = attribute, .callback = std::move(f), .once = once,
// entity_id_dynamic_storage and attribute_dynamic_storage remain nullptr (no heap allocation) // entity_id_dynamic_storage and attribute_dynamic_storage remain nullptr (no heap allocation)
@@ -430,7 +427,7 @@ void APIServer::add_state_subscription_(const char *entity_id, const char *attri
// Helper to add subscription with heap-allocated strings (reduces duplication) // Helper to add subscription with heap-allocated strings (reduces duplication)
void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute, void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f, bool once) { std::function<void(StringRef)> f, bool once) {
HomeAssistantStateSubscription sub; HomeAssistantStateSubscription sub;
// Allocate heap storage for the strings // Allocate heap storage for the strings
sub.entity_id_dynamic_storage = std::make_unique<std::string>(std::move(entity_id)); sub.entity_id_dynamic_storage = std::make_unique<std::string>(std::move(entity_id));
@@ -450,23 +447,43 @@ void APIServer::add_state_subscription_(std::string entity_id, optional<std::str
// New const char* overload (for internal components - zero allocation) // New const char* overload (for internal components - zero allocation)
void APIServer::subscribe_home_assistant_state(const char *entity_id, const char *attribute, void APIServer::subscribe_home_assistant_state(const char *entity_id, const char *attribute,
std::function<void(std::string)> f) { std::function<void(StringRef)> f) {
this->add_state_subscription_(entity_id, attribute, std::move(f), false); this->add_state_subscription_(entity_id, attribute, std::move(f), false);
} }
void APIServer::get_home_assistant_state(const char *entity_id, const char *attribute, void APIServer::get_home_assistant_state(const char *entity_id, const char *attribute,
std::function<void(std::string)> f) { std::function<void(StringRef)> f) {
this->add_state_subscription_(entity_id, attribute, std::move(f), true); this->add_state_subscription_(entity_id, attribute, std::move(f), true);
} }
// Existing std::string overload (for custom_api_device.h - heap allocation) // std::string overload with StringRef callback (zero-allocation callback)
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute, void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) { std::function<void(StringRef)> f) {
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false); this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
} }
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute, void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) { std::function<void(StringRef)> f) {
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
}
// Legacy helper: wraps std::string callback and delegates to StringRef version
void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
std::function<void(const std::string &)> f, bool once) {
// Wrap callback to convert StringRef -> std::string, then delegate
this->add_state_subscription_(std::move(entity_id), std::move(attribute),
std::function<void(StringRef)>([f = std::move(f)](StringRef state) { f(state.str()); }),
once);
}
// Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string)
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(const std::string &)> f) {
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), false);
}
void APIServer::get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(const std::string &)> f) {
this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true); this->add_state_subscription_(std::move(entity_id), std::move(attribute), std::move(f), true);
} }
@@ -541,8 +558,10 @@ bool APIServer::clear_noise_psk(bool make_active) {
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
void APIServer::request_time() { void APIServer::request_time() {
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
if (!client->flags_.remove && client->is_authenticated()) if (!client->flags_.remove && client->is_authenticated()) {
client->send_time_request(); client->send_time_request();
return; // Only request from one client to avoid clock conflicts
}
} }
} }
#endif #endif
@@ -602,8 +621,7 @@ void APIServer::on_shutdown() {
if (!c->send_message(req, DisconnectRequest::MESSAGE_TYPE)) { if (!c->send_message(req, DisconnectRequest::MESSAGE_TYPE)) {
// If we can't send the disconnect request directly (tx_buffer full), // If we can't send the disconnect request directly (tx_buffer full),
// schedule it at the front of the batch so it will be sent with priority // schedule it at the front of the batch so it will be sent with priority
c->schedule_message_front_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE, c->schedule_message_front_(nullptr, DisconnectRequest::MESSAGE_TYPE, DisconnectRequest::ESTIMATED_SIZE);
DisconnectRequest::ESTIMATED_SIZE);
} }
} }
} }
@@ -635,18 +653,18 @@ uint32_t APIServer::register_active_action_call(uint32_t client_call_id, APIConn
this->active_action_calls_.push_back({action_call_id, client_call_id, conn}); this->active_action_calls_.push_back({action_call_id, client_call_id, conn});
// Schedule automatic cleanup after timeout (client will have given up by then) // Schedule automatic cleanup after timeout (client will have given up by then)
this->set_timeout(str_sprintf("action_call_%u", action_call_id), USE_API_ACTION_CALL_TIMEOUT_MS, // Uses numeric ID overload to avoid heap allocation from str_sprintf
[this, action_call_id]() { this->set_timeout(action_call_id, USE_API_ACTION_CALL_TIMEOUT_MS, [this, action_call_id]() {
ESP_LOGD(TAG, "Action call %u timed out", action_call_id); ESP_LOGD(TAG, "Action call %u timed out", action_call_id);
this->unregister_active_action_call(action_call_id); this->unregister_active_action_call(action_call_id);
}); });
return action_call_id; return action_call_id;
} }
void APIServer::unregister_active_action_call(uint32_t action_call_id) { void APIServer::unregister_active_action_call(uint32_t action_call_id) {
// Cancel the timeout for this action call // Cancel the timeout for this action call (uses numeric ID overload)
this->cancel_timeout(str_sprintf("action_call_%u", action_call_id)); this->cancel_timeout(action_call_id);
// Swap-and-pop is more efficient than remove_if for unordered vectors // Swap-and-pop is more efficient than remove_if for unordered vectors
for (size_t i = 0; i < this->active_action_calls_.size(); i++) { for (size_t i = 0; i < this->active_action_calls_.size(); i++) {
@@ -662,8 +680,8 @@ void APIServer::unregister_active_action_calls_for_connection(APIConnection *con
// Remove all active action calls for disconnected connection using swap-and-pop // Remove all active action calls for disconnected connection using swap-and-pop
for (size_t i = 0; i < this->active_action_calls_.size();) { for (size_t i = 0; i < this->active_action_calls_.size();) {
if (this->active_action_calls_[i].connection == conn) { if (this->active_action_calls_[i].connection == conn) {
// Cancel the timeout for this action call // Cancel the timeout for this action call (uses numeric ID overload)
this->cancel_timeout(str_sprintf("action_call_%u", this->active_action_calls_[i].action_call_id)); this->cancel_timeout(this->active_action_calls_[i].action_call_id);
std::swap(this->active_action_calls_[i], this->active_action_calls_.back()); std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
this->active_action_calls_.pop_back(); this->active_action_calls_.pop_back();
@@ -674,7 +692,7 @@ void APIServer::unregister_active_action_calls_for_connection(APIConnection *con
} }
} }
void APIServer::send_action_response(uint32_t action_call_id, bool success, const std::string &error_message) { void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message) {
for (auto &call : this->active_action_calls_) { for (auto &call : this->active_action_calls_) {
if (call.action_call_id == action_call_id) { if (call.action_call_id == action_call_id) {
call.connection->send_execute_service_response(call.client_call_id, success, error_message); call.connection->send_execute_service_response(call.client_call_id, success, error_message);
@@ -684,7 +702,7 @@ void APIServer::send_action_response(uint32_t action_call_id, bool success, cons
ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id); ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id);
} }
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void APIServer::send_action_response(uint32_t action_call_id, bool success, const std::string &error_message, void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
const uint8_t *response_data, size_t response_data_len) { const uint8_t *response_data, size_t response_data_len) {
for (auto &call : this->active_action_calls_) { for (auto &call : this->active_action_calls_) {
if (call.action_call_id == action_call_id) { if (call.action_call_id == action_call_id) {

View File

@@ -10,6 +10,7 @@
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/controller.h" #include "esphome/core/controller.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/string_ref.h"
#include "list_entities.h" #include "list_entities.h"
#include "subscribe_state.h" #include "subscribe_state.h"
#ifdef USE_LOGGER #ifdef USE_LOGGER
@@ -59,10 +60,6 @@ class APIServer : public Component,
#endif #endif
#ifdef USE_CAMERA #ifdef USE_CAMERA
void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override; void on_camera_image(const std::shared_ptr<camera::CameraImage> &image) override;
#endif
#ifdef USE_API_PASSWORD
bool check_password(const uint8_t *password_data, size_t password_len) const;
void set_password(const std::string &password);
#endif #endif
void set_port(uint16_t port); void set_port(uint16_t port);
void set_reboot_timeout(uint32_t reboot_timeout); void set_reboot_timeout(uint32_t reboot_timeout);
@@ -133,6 +130,9 @@ class APIServer : public Component,
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
void on_media_player_update(media_player::MediaPlayer *obj) override; void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif #endif
#ifdef USE_WATER_HEATER
void on_water_heater_update(water_heater::WaterHeater *obj) override;
#endif
#ifdef USE_API_HOMEASSISTANT_SERVICES #ifdef USE_API_HOMEASSISTANT_SERVICES
void send_homeassistant_action(const HomeassistantActionRequest &call); void send_homeassistant_action(const HomeassistantActionRequest &call);
@@ -140,10 +140,10 @@ class APIServer : public Component,
// Action response handling // Action response handling
using ActionResponseCallback = std::function<void(const class ActionResponse &)>; using ActionResponseCallback = std::function<void(const class ActionResponse &)>;
void register_action_response_callback(uint32_t call_id, ActionResponseCallback callback); void register_action_response_callback(uint32_t call_id, ActionResponseCallback callback);
void handle_action_response(uint32_t call_id, bool success, const std::string &error_message); void handle_action_response(uint32_t call_id, bool success, StringRef error_message);
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
void handle_action_response(uint32_t call_id, bool success, const std::string &error_message, void handle_action_response(uint32_t call_id, bool success, StringRef error_message, const uint8_t *response_data,
const uint8_t *response_data, size_t response_data_len); size_t response_data_len);
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON #endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES #endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
#endif // USE_API_HOMEASSISTANT_SERVICES #endif // USE_API_HOMEASSISTANT_SERVICES
@@ -162,9 +162,9 @@ class APIServer : public Component,
void unregister_active_action_call(uint32_t action_call_id); void unregister_active_action_call(uint32_t action_call_id);
void unregister_active_action_calls_for_connection(APIConnection *conn); void unregister_active_action_calls_for_connection(APIConnection *conn);
// Send response for a specific action call (uses action_call_id, sends client_call_id in response) // Send response for a specific action call (uses action_call_id, sends client_call_id in response)
void send_action_response(uint32_t action_call_id, bool success, const std::string &error_message); void send_action_response(uint32_t action_call_id, bool success, StringRef error_message);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void send_action_response(uint32_t action_call_id, bool success, const std::string &error_message, void send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
const uint8_t *response_data, size_t response_data_len); const uint8_t *response_data, size_t response_data_len);
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON #endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES #endif // USE_API_USER_DEFINED_ACTION_RESPONSES
@@ -185,6 +185,9 @@ class APIServer : public Component,
#ifdef USE_ZWAVE_PROXY #ifdef USE_ZWAVE_PROXY
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg); void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg);
#endif #endif
#ifdef USE_IR_RF
void send_infrared_rf_receive_event(uint32_t device_id, uint32_t key, const std::vector<int32_t> *timings);
#endif
bool is_connected(bool state_subscription_only = false) const; bool is_connected(bool state_subscription_only = false) const;
@@ -192,7 +195,7 @@ class APIServer : public Component,
struct HomeAssistantStateSubscription { struct HomeAssistantStateSubscription {
const char *entity_id; // Pointer to flash (internal) or heap (external) const char *entity_id; // Pointer to flash (internal) or heap (external)
const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute) const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute)
std::function<void(std::string)> callback; std::function<void(StringRef)> callback;
bool once; bool once;
// Dynamic storage for external components using std::string API (custom_api_device.h) // Dynamic storage for external components using std::string API (custom_api_device.h)
@@ -202,14 +205,20 @@ class APIServer : public Component,
}; };
// New const char* overload (for internal components - zero allocation) // New const char* overload (for internal components - zero allocation)
void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(std::string)> f); void subscribe_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> f);
void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(std::string)> f); void get_home_assistant_state(const char *entity_id, const char *attribute, std::function<void(StringRef)> f);
// Existing std::string overload (for custom_api_device.h - heap allocation) // std::string overload with StringRef callback (for custom_api_device.h with zero-allocation callback)
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute, void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f); std::function<void(StringRef)> f);
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute, void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f); std::function<void(StringRef)> f);
// Legacy std::string overload (for custom_api_device.h - converts StringRef to std::string for callback)
void subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(const std::string &)> f);
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(const std::string &)> f);
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const; const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
#endif #endif
@@ -233,10 +242,13 @@ class APIServer : public Component,
#endif // USE_API_NOISE #endif // USE_API_NOISE
#ifdef USE_API_HOMEASSISTANT_STATES #ifdef USE_API_HOMEASSISTANT_STATES
// Helper methods to reduce code duplication // Helper methods to reduce code duplication
void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(std::string)> f, void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
bool once); bool once);
void add_state_subscription_(std::string entity_id, optional<std::string> attribute, std::function<void(StringRef)> f,
bool once);
// Legacy helper: wraps std::string callback and delegates to StringRef version
void add_state_subscription_(std::string entity_id, optional<std::string> attribute, void add_state_subscription_(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f, bool once); std::function<void(const std::string &)> f, bool once);
#endif // USE_API_HOMEASSISTANT_STATES #endif // USE_API_HOMEASSISTANT_STATES
// Pointers and pointer-like types first (4 bytes each) // Pointers and pointer-like types first (4 bytes each)
std::unique_ptr<socket::Socket> socket_ = nullptr; std::unique_ptr<socket::Socket> socket_ = nullptr;
@@ -253,9 +265,6 @@ class APIServer : public Component,
// Vectors and strings (12 bytes each on 32-bit) // Vectors and strings (12 bytes each on 32-bit)
std::vector<std::unique_ptr<APIConnection>> clients_; std::vector<std::unique_ptr<APIConnection>> clients_;
#ifdef USE_API_PASSWORD
std::string password_;
#endif
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
#ifdef USE_API_HOMEASSISTANT_STATES #ifdef USE_API_HOMEASSISTANT_STATES
std::vector<HomeAssistantStateSubscription> state_subs_; std::vector<HomeAssistantStateSubscription> state_subs_;

View File

@@ -16,7 +16,7 @@ with warnings.catch_warnings():
import contextlib import contextlib
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__ from esphome.const import CONF_KEY, CONF_PORT, __version__
from esphome.core import CORE from esphome.core import CORE
from . import CONF_ENCRYPTION from . import CONF_ENCRYPTION
@@ -35,7 +35,6 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
conf = config["api"] conf = config["api"]
name = config["esphome"]["name"] name = config["esphome"]["name"]
port: int = int(conf[CONF_PORT]) port: int = int(conf[CONF_PORT])
password: str = conf[CONF_PASSWORD]
noise_psk: str | None = None noise_psk: str | None = None
if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)): if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
noise_psk = key noise_psk = key
@@ -50,7 +49,7 @@ async def async_run_logs(config: dict[str, Any], addresses: list[str]) -> None:
cli = APIClient( cli = APIClient(
addresses[0], # Primary address for compatibility addresses[0], # Primary address for compatibility
port, port,
password, "", # Password auth removed in 2026.1.0
client_info=f"ESPHome Logs {__version__}", client_info=f"ESPHome Logs {__version__}",
noise_psk=noise_psk, noise_psk=noise_psk,
addresses=addresses, # Pass all addresses for automatic retry addresses=addresses, # Pass all addresses for automatic retry

View File

@@ -122,21 +122,36 @@ class CustomAPIDevice {
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature"); * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature");
* } * }
* *
* void on_state_changed(std::string state) { * void on_state_changed(StringRef state) {
* // State of sensor.weather_forecast is `state` * // State of climate.kitchen current_temperature is `state`
* // Use state.c_str() for C string, state.str() for std::string
* } * }
* ``` * ```
* *
* @tparam T The class type creating the service, automatically deduced from the function pointer. * @tparam T The class type creating the service, automatically deduced from the function pointer.
* @param callback The member function to call when the entity state changes. * @param callback The member function to call when the entity state changes (zero-allocation).
* @param entity_id The entity_id to track. * @param entity_id The entity_id to track.
* @param attribute The entity state attribute to track. * @param attribute The entity state attribute to track.
*/ */
template<typename T> template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(StringRef), const std::string &entity_id,
const std::string &attribute = "") {
auto f = std::bind(callback, (T *) this, std::placeholders::_1);
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), std::move(f));
}
/** Subscribe to the state (or attribute state) of an entity from Home Assistant (legacy std::string version).
*
* @deprecated Use the StringRef overload for zero-allocation callbacks. Will be removed in 2027.1.0.
*/
template<typename T>
ESPDEPRECATED("Use void callback(StringRef) instead. Will be removed in 2027.1.0.", "2026.1.0")
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id, void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
const std::string &attribute = "") { const std::string &attribute = "") {
auto f = std::bind(callback, (T *) this, std::placeholders::_1); auto f = std::bind(callback, (T *) this, std::placeholders::_1);
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f); // Explicit type to disambiguate overload resolution
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute),
std::function<void(const std::string &)>(f));
} }
/** Subscribe to the state (or attribute state) of an entity from Home Assistant. /** Subscribe to the state (or attribute state) of an entity from Home Assistant.
@@ -148,23 +163,45 @@ class CustomAPIDevice {
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast"); * subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "sensor.weather_forecast");
* } * }
* *
* void on_state_changed(std::string entity_id, std::string state) { * void on_state_changed(const std::string &entity_id, StringRef state) {
* // State of `entity_id` is `state` * // State of `entity_id` is `state`
* } * }
* ``` * ```
* *
* @tparam T The class type creating the service, automatically deduced from the function pointer. * @tparam T The class type creating the service, automatically deduced from the function pointer.
* @param callback The member function to call when the entity state changes. * @param callback The member function to call when the entity state changes (zero-allocation for state).
* @param entity_id The entity_id to track. * @param entity_id The entity_id to track.
* @param attribute The entity state attribute to track. * @param attribute The entity state attribute to track.
*/ */
template<typename T> template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(const std::string &, StringRef), const std::string &entity_id,
const std::string &attribute = "") {
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), std::move(f));
}
/** Subscribe to the state (or attribute state) of an entity from Home Assistant (legacy std::string version).
*
* @deprecated Use the StringRef overload for zero-allocation callbacks. Will be removed in 2027.1.0.
*/
template<typename T>
ESPDEPRECATED("Use void callback(const std::string &, StringRef) instead. Will be removed in 2027.1.0.", "2026.1.0")
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id, void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
const std::string &attribute = "") { const std::string &attribute = "") {
auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1); auto f = std::bind(callback, (T *) this, entity_id, std::placeholders::_1);
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute), f); // Explicit type to disambiguate overload resolution
global_api_server->subscribe_home_assistant_state(entity_id, optional<std::string>(attribute),
std::function<void(const std::string &)>(f));
} }
#else #else
template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(StringRef), const std::string &entity_id,
const std::string &attribute = "") {
static_assert(sizeof(T) == 0,
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
"of your YAML configuration");
}
template<typename T> template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id, void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
const std::string &attribute = "") { const std::string &attribute = "") {
@@ -173,6 +210,14 @@ class CustomAPIDevice {
"of your YAML configuration"); "of your YAML configuration");
} }
template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(const std::string &, StringRef), const std::string &entity_id,
const std::string &attribute = "") {
static_assert(sizeof(T) == 0,
"subscribe_homeassistant_state() requires 'homeassistant_states: true' in the 'api:' section "
"of your YAML configuration");
}
template<typename T> template<typename T>
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id, void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
const std::string &attribute = "") { const std::string &attribute = "") {
@@ -195,7 +240,7 @@ class CustomAPIDevice {
*/ */
void call_homeassistant_service(const std::string &service_name) { void call_homeassistant_service(const std::string &service_name) {
HomeassistantActionRequest resp; HomeassistantActionRequest resp;
resp.set_service(StringRef(service_name)); resp.service = StringRef(service_name);
global_api_server->send_homeassistant_action(resp); global_api_server->send_homeassistant_action(resp);
} }
@@ -215,12 +260,12 @@ class CustomAPIDevice {
*/ */
void call_homeassistant_service(const std::string &service_name, const std::map<std::string, std::string> &data) { void call_homeassistant_service(const std::string &service_name, const std::map<std::string, std::string> &data) {
HomeassistantActionRequest resp; HomeassistantActionRequest resp;
resp.set_service(StringRef(service_name)); resp.service = StringRef(service_name);
resp.data.init(data.size()); resp.data.init(data.size());
for (auto &it : data) { for (auto &it : data) {
auto &kv = resp.data.emplace_back(); auto &kv = resp.data.emplace_back();
kv.set_key(StringRef(it.first)); kv.key = StringRef(it.first);
kv.value = it.second; kv.value = StringRef(it.second); // data map lives until send completes
} }
global_api_server->send_homeassistant_action(resp); global_api_server->send_homeassistant_action(resp);
} }
@@ -237,7 +282,7 @@ class CustomAPIDevice {
*/ */
void fire_homeassistant_event(const std::string &event_name) { void fire_homeassistant_event(const std::string &event_name) {
HomeassistantActionRequest resp; HomeassistantActionRequest resp;
resp.set_service(StringRef(event_name)); resp.service = StringRef(event_name);
resp.is_event = true; resp.is_event = true;
global_api_server->send_homeassistant_action(resp); global_api_server->send_homeassistant_action(resp);
} }
@@ -257,13 +302,13 @@ class CustomAPIDevice {
*/ */
void fire_homeassistant_event(const std::string &service_name, const std::map<std::string, std::string> &data) { void fire_homeassistant_event(const std::string &service_name, const std::map<std::string, std::string> &data) {
HomeassistantActionRequest resp; HomeassistantActionRequest resp;
resp.set_service(StringRef(service_name)); resp.service = StringRef(service_name);
resp.is_event = true; resp.is_event = true;
resp.data.init(data.size()); resp.data.init(data.size());
for (auto &it : data) { for (auto &it : data) {
auto &kv = resp.data.emplace_back(); auto &kv = resp.data.emplace_back();
kv.set_key(StringRef(it.first)); kv.key = StringRef(it.first);
kv.value = it.second; kv.value = StringRef(it.second); // data map lives until send completes
} }
global_api_server->send_homeassistant_action(resp); global_api_server->send_homeassistant_action(resp);
} }

View File

@@ -67,10 +67,10 @@ template<typename... Ts> class TemplatableKeyValuePair {
// the callback is invoked synchronously while the message is on the stack). // the callback is invoked synchronously while the message is on the stack).
class ActionResponse { class ActionResponse {
public: public:
ActionResponse(bool success, const std::string &error_message) : success_(success), error_message_(error_message) {} ActionResponse(bool success, StringRef error_message) : success_(success), error_message_(error_message) {}
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
ActionResponse(bool success, const std::string &error_message, const uint8_t *data, size_t data_len) ActionResponse(bool success, StringRef error_message, const uint8_t *data, size_t data_len)
: success_(success), error_message_(error_message) { : success_(success), error_message_(error_message) {
if (data == nullptr || data_len == 0) if (data == nullptr || data_len == 0)
return; return;
@@ -147,13 +147,23 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
void play(const Ts &...x) override { void play(const Ts &...x) override {
HomeassistantActionRequest resp; HomeassistantActionRequest resp;
std::string service_value = this->service_.value(x...); std::string service_value = this->service_.value(x...);
resp.set_service(StringRef(service_value)); resp.service = StringRef(service_value);
resp.is_event = this->flags_.is_event; resp.is_event = this->flags_.is_event;
this->populate_service_map(resp.data, this->data_, x...);
this->populate_service_map(resp.data_template, this->data_template_, x...); // Local storage for lambda-evaluated strings - lives until after send
this->populate_service_map(resp.variables, this->variables_, x...); FixedVector<std::string> data_storage;
FixedVector<std::string> data_template_storage;
FixedVector<std::string> variables_storage;
this->populate_service_map(resp.data, this->data_, data_storage, x...);
this->populate_service_map(resp.data_template, this->data_template_, data_template_storage, x...);
this->populate_service_map(resp.variables, this->variables_, variables_storage, x...);
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES #ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
// IMPORTANT: Declare at outer scope so it lives until send_homeassistant_action returns.
std::string response_template_value;
#endif
if (this->flags_.wants_status) { if (this->flags_.wants_status) {
// Generate a unique call ID for this service call // Generate a unique call ID for this service call
static uint32_t call_id_counter = 1; static uint32_t call_id_counter = 1;
@@ -164,8 +174,8 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
resp.wants_response = true; resp.wants_response = true;
// Set response template if provided // Set response template if provided
if (this->flags_.has_response_template) { if (this->flags_.has_response_template) {
std::string response_template_value = this->response_template_.value(x...); response_template_value = this->response_template_.value(x...);
resp.response_template = response_template_value; resp.response_template = StringRef(response_template_value);
} }
} }
#endif #endif
@@ -205,12 +215,31 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
} }
template<typename VectorType, typename SourceType> template<typename VectorType, typename SourceType>
static void populate_service_map(VectorType &dest, SourceType &source, Ts... x) { static void populate_service_map(VectorType &dest, SourceType &source, FixedVector<std::string> &value_storage,
Ts... x) {
dest.init(source.size()); dest.init(source.size());
// Count non-static strings to allocate exact storage needed
size_t lambda_count = 0;
for (const auto &it : source) {
if (!it.value.is_static_string()) {
lambda_count++;
}
}
value_storage.init(lambda_count);
for (auto &it : source) { for (auto &it : source) {
auto &kv = dest.emplace_back(); auto &kv = dest.emplace_back();
kv.set_key(StringRef(it.key)); kv.key = StringRef(it.key);
kv.value = it.value.value(x...);
if (it.value.is_static_string()) {
// Static string from YAML - zero allocation
kv.value = StringRef(it.value.get_static_string());
} else {
// Lambda evaluation - store result, reference it
value_storage.push_back(it.value.value(x...));
kv.value = StringRef(value_storage.back());
}
} }
} }

View File

@@ -73,6 +73,12 @@ LIST_ENTITIES_HANDLER(media_player, media_player::MediaPlayer, ListEntitiesMedia
LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel, LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel,
ListEntitiesAlarmControlPanelResponse) ListEntitiesAlarmControlPanelResponse)
#endif #endif
#ifdef USE_WATER_HEATER
LIST_ENTITIES_HANDLER(water_heater, water_heater::WaterHeater, ListEntitiesWaterHeaterResponse)
#endif
#ifdef USE_INFRARED
LIST_ENTITIES_HANDLER(infrared, infrared::Infrared, ListEntitiesInfraredResponse)
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse) LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
#endif #endif

View File

@@ -9,11 +9,10 @@ namespace esphome::api {
class APIConnection; class APIConnection;
// Macro for generating ListEntitiesIterator handlers // Macro for generating ListEntitiesIterator handlers
// Calls schedule_message_ with try_send_*_info // Calls schedule_message_ which dispatches to try_send_*_info
#define LIST_ENTITIES_HANDLER(entity_type, EntityClass, ResponseType) \ #define LIST_ENTITIES_HANDLER(entity_type, EntityClass, ResponseType) \
bool ListEntitiesIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \ bool ListEntitiesIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \
return this->client_->schedule_message_(entity, &APIConnection::try_send_##entity_type##_info, \ return this->client_->schedule_message_(entity, ResponseType::MESSAGE_TYPE, ResponseType::ESTIMATED_SIZE); \
ResponseType::MESSAGE_TYPE, ResponseType::ESTIMATED_SIZE); \
} }
class ListEntitiesIterator : public ComponentIterator { class ListEntitiesIterator : public ComponentIterator {
@@ -82,6 +81,12 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override; bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif #endif
#ifdef USE_WATER_HEATER
bool on_water_heater(water_heater::WaterHeater *entity) override;
#endif
#ifdef USE_INFRARED
bool on_infrared(infrared::Infrared *entity) override;
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *entity) override; bool on_event(event::Event *entity) override;
#endif #endif

View File

@@ -48,14 +48,14 @@ uint32_t ProtoDecodableMessage::count_repeated_field(const uint8_t *buffer, size
} }
uint32_t field_length = res->as_uint32(); uint32_t field_length = res->as_uint32();
ptr += consumed; ptr += consumed;
if (ptr + field_length > end) { if (field_length > static_cast<size_t>(end - ptr)) {
return count; // Out of bounds return count; // Out of bounds
} }
ptr += field_length; ptr += field_length;
break; break;
} }
case WIRE_TYPE_FIXED32: { // 32-bit - skip 4 bytes case WIRE_TYPE_FIXED32: { // 32-bit - skip 4 bytes
if (ptr + 4 > end) { if (end - ptr < 4) {
return count; return count;
} }
ptr += 4; ptr += 4;
@@ -110,7 +110,7 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
} }
uint32_t field_length = res->as_uint32(); uint32_t field_length = res->as_uint32();
ptr += consumed; ptr += consumed;
if (ptr + field_length > end) { if (field_length > static_cast<size_t>(end - ptr)) {
ESP_LOGV(TAG, "Out-of-bounds Length Delimited at offset %ld", (long) (ptr - buffer)); ESP_LOGV(TAG, "Out-of-bounds Length Delimited at offset %ld", (long) (ptr - buffer));
return; return;
} }
@@ -121,7 +121,7 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
break; break;
} }
case WIRE_TYPE_FIXED32: { // 32-bit case WIRE_TYPE_FIXED32: { // 32-bit
if (ptr + 4 > end) { if (end - ptr < 4) {
ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at offset %ld", (long) (ptr - buffer)); ESP_LOGV(TAG, "Out-of-bounds Fixed32-bit at offset %ld", (long) (ptr - buffer));
return; return;
} }
@@ -139,12 +139,4 @@ void ProtoDecodableMessage::decode(const uint8_t *buffer, size_t length) {
} }
} }
#ifdef HAS_PROTO_MESSAGE_DUMP
std::string ProtoMessage::dump() const {
std::string out;
this->dump_to(out);
return out;
}
#endif
} // namespace esphome::api } // namespace esphome::api

View File

@@ -39,6 +39,24 @@ inline constexpr int64_t decode_zigzag64(uint64_t value) {
return (value & 1) ? static_cast<int64_t>(~(value >> 1)) : static_cast<int64_t>(value >> 1); return (value & 1) ? static_cast<int64_t>(~(value >> 1)) : static_cast<int64_t>(value >> 1);
} }
/// Count number of varints in a packed buffer
inline uint16_t count_packed_varints(const uint8_t *data, size_t len) {
uint16_t count = 0;
while (len > 0) {
// Skip varint bytes until we find one without continuation bit
while (len > 0 && (*data & 0x80)) {
data++;
len--;
}
if (len > 0) {
data++;
len--;
count++;
}
}
return count;
}
/* /*
* StringRef Ownership Model for API Protocol Messages * StringRef Ownership Model for API Protocol Messages
* =================================================== * ===================================================
@@ -54,16 +72,16 @@ inline constexpr int64_t decode_zigzag64(uint64_t value) {
* 3. Global/static strings: StringRef(GLOBAL_CONSTANT) - Always safe * 3. Global/static strings: StringRef(GLOBAL_CONSTANT) - Always safe
* 4. Local variables: Safe ONLY if encoding happens before function returns: * 4. Local variables: Safe ONLY if encoding happens before function returns:
* std::string temp = compute_value(); * std::string temp = compute_value();
* msg.set_field(StringRef(temp)); * msg.field = StringRef(temp);
* return this->send_message(msg); // temp is valid during encoding * return this->send_message(msg); // temp is valid during encoding
* *
* Unsafe Patterns (WILL cause crashes/corruption): * Unsafe Patterns (WILL cause crashes/corruption):
* 1. Temporaries: msg.set_field(StringRef(obj.get_string())) // get_string() returns by value * 1. Temporaries: msg.field = StringRef(obj.get_string()) // get_string() returns by value
* 2. Concatenation: msg.set_field(StringRef(str1 + str2)) // Result is temporary * 2. Concatenation: msg.field = StringRef(str1 + str2) // Result is temporary
* *
* For unsafe patterns, store in a local variable first: * For unsafe patterns, store in a local variable first:
* std::string temp = get_string(); // or str1 + str2 * std::string temp = get_string(); // or str1 + str2
* msg.set_field(StringRef(temp)); * msg.field = StringRef(temp);
* *
* The send_*_response pattern ensures proper lifetime management by encoding * The send_*_response pattern ensures proper lifetime management by encoding
* within the same function scope where temporaries are created. * within the same function scope where temporaries are created.
@@ -180,9 +198,10 @@ class ProtoVarInt {
uint64_t value_; uint64_t value_;
}; };
// Forward declaration for decode_to_message and encode_to_writer // Forward declarations for decode_to_message, encode_message and encode_packed_sint32
class ProtoMessage;
class ProtoDecodableMessage; class ProtoDecodableMessage;
class ProtoMessage;
class ProtoSize;
class ProtoLengthDelimited { class ProtoLengthDelimited {
public: public:
@@ -334,15 +353,71 @@ class ProtoWriteBuffer {
void encode_sint64(uint32_t field_id, int64_t value, bool force = false) { void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
this->encode_uint64(field_id, encode_zigzag64(value), force); this->encode_uint64(field_id, encode_zigzag64(value), force);
} }
void encode_message(uint32_t field_id, const ProtoMessage &value, bool force = false); /// Encode a packed repeated sint32 field (zero-copy from vector)
void encode_packed_sint32(uint32_t field_id, const std::vector<int32_t> &values);
void encode_message(uint32_t field_id, const ProtoMessage &value);
std::vector<uint8_t> *get_buffer() const { return buffer_; } std::vector<uint8_t> *get_buffer() const { return buffer_; }
protected: protected:
std::vector<uint8_t> *buffer_; std::vector<uint8_t> *buffer_;
}; };
// Forward declaration #ifdef HAS_PROTO_MESSAGE_DUMP
class ProtoSize; /**
* Fixed-size buffer for message dumps - avoids heap allocation.
* Sized to match the logger's default tx_buffer_size (512 bytes)
* since anything larger gets truncated anyway.
*/
class DumpBuffer {
public:
// Matches default tx_buffer_size in logger component
static constexpr size_t CAPACITY = 512;
DumpBuffer() : pos_(0) { buf_[0] = '\0'; }
DumpBuffer &append(const char *str) {
if (str) {
append_impl_(str, strlen(str));
}
return *this;
}
DumpBuffer &append(const char *str, size_t len) {
append_impl_(str, len);
return *this;
}
DumpBuffer &append(size_t n, char c) {
size_t space = CAPACITY - 1 - pos_;
if (n > space)
n = space;
if (n > 0) {
memset(buf_ + pos_, c, n);
pos_ += n;
buf_[pos_] = '\0';
}
return *this;
}
const char *c_str() const { return buf_; }
size_t size() const { return pos_; }
private:
void append_impl_(const char *str, size_t len) {
size_t space = CAPACITY - 1 - pos_;
if (len > space)
len = space;
if (len > 0) {
memcpy(buf_ + pos_, str, len);
pos_ += len;
buf_[pos_] = '\0';
}
}
char buf_[CAPACITY];
size_t pos_;
};
#endif
class ProtoMessage { class ProtoMessage {
public: public:
@@ -352,8 +427,7 @@ class ProtoMessage {
// Default implementation for messages with no fields // Default implementation for messages with no fields
virtual void calculate_size(ProtoSize &size) const {} virtual void calculate_size(ProtoSize &size) const {}
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
std::string dump() const; virtual const char *dump_to(DumpBuffer &out) const = 0;
virtual void dump_to(std::string &out) const = 0;
virtual const char *message_name() const { return "unknown"; } virtual const char *message_name() const { return "unknown"; }
#endif #endif
}; };
@@ -792,10 +866,45 @@ class ProtoSize {
} }
} }
} }
/**
* @brief Calculate size of a packed repeated sint32 field
*/
inline void add_packed_sint32(uint32_t field_id_size, const std::vector<int32_t> &values) {
if (values.empty())
return;
size_t packed_size = 0;
for (int value : values) {
packed_size += varint(encode_zigzag32(value));
}
// field_id + length varint + packed data
total_size_ += field_id_size + varint(static_cast<uint32_t>(packed_size)) + static_cast<uint32_t>(packed_size);
}
}; };
// Implementation of encode_packed_sint32 - must be after ProtoSize is defined
inline void ProtoWriteBuffer::encode_packed_sint32(uint32_t field_id, const std::vector<int32_t> &values) {
if (values.empty())
return;
// Calculate packed size
size_t packed_size = 0;
for (int value : values) {
packed_size += ProtoSize::varint(encode_zigzag32(value));
}
// Write tag (LENGTH_DELIMITED) + length + all zigzag-encoded values
this->encode_field_raw(field_id, WIRE_TYPE_LENGTH_DELIMITED);
this->encode_varint_raw(packed_size);
for (int value : values) {
this->encode_varint_raw(encode_zigzag32(value));
}
}
// Implementation of encode_message - must be after ProtoMessage is defined // Implementation of encode_message - must be after ProtoMessage is defined
inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessage &value, bool force) { inline void ProtoWriteBuffer::encode_message(uint32_t field_id, const ProtoMessage &value) {
this->encode_field_raw(field_id, 2); // type 2: Length-delimited message this->encode_field_raw(field_id, 2); // type 2: Length-delimited message
// Calculate the message size first // Calculate the message size first
@@ -833,9 +942,6 @@ class ProtoService {
virtual bool is_authenticated() = 0; virtual bool is_authenticated() = 0;
virtual bool is_connection_setup() = 0; virtual bool is_connection_setup() = 0;
virtual void on_fatal_error() = 0; virtual void on_fatal_error() = 0;
#ifdef USE_API_PASSWORD
virtual void on_unauthenticated_access() = 0;
#endif
virtual void on_no_setup_connection() = 0; virtual void on_no_setup_connection() = 0;
/** /**
* Create a buffer with a reserved size. * Create a buffer with a reserved size.
@@ -873,20 +979,7 @@ class ProtoService {
return true; return true;
} }
inline bool check_authenticated_() { inline bool check_authenticated_() { return this->check_connection_setup_(); }
#ifdef USE_API_PASSWORD
if (!this->check_connection_setup_()) {
return false;
}
if (!this->is_authenticated()) {
this->on_unauthenticated_access();
return false;
}
return true;
#else
return this->check_connection_setup_();
#endif
}
}; };
} // namespace esphome::api } // namespace esphome::api

View File

@@ -60,6 +60,9 @@ INITIAL_STATE_HANDLER(media_player, media_player::MediaPlayer)
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
INITIAL_STATE_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel) INITIAL_STATE_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel)
#endif #endif
#ifdef USE_WATER_HEATER
INITIAL_STATE_HANDLER(water_heater, water_heater::WaterHeater)
#endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
INITIAL_STATE_HANDLER(update, update::UpdateEntity) INITIAL_STATE_HANDLER(update, update::UpdateEntity)
#endif #endif

View File

@@ -76,6 +76,12 @@ class InitialStateIterator : public ComponentIterator {
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override; bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif #endif
#ifdef USE_WATER_HEATER
bool on_water_heater(water_heater::WaterHeater *entity) override;
#endif
#ifdef USE_INFRARED
bool on_infrared(infrared::Infrared *infrared) override { return true; };
#endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override { return true; }; bool on_event(event::Event *event) override { return true; };
#endif #endif

View File

@@ -46,7 +46,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
ListEntitiesServicesResponse encode_list_service_response() override { ListEntitiesServicesResponse encode_list_service_response() override {
ListEntitiesServicesResponse msg; ListEntitiesServicesResponse msg;
msg.set_name(StringRef(this->name_)); msg.name = StringRef(this->name_);
msg.key = this->key_; msg.key = this->key_;
msg.supports_response = this->supports_response_; msg.supports_response = this->supports_response_;
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...}; std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
@@ -54,7 +54,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
for (size_t i = 0; i < sizeof...(Ts); i++) { for (size_t i = 0; i < sizeof...(Ts); i++) {
auto &arg = msg.args.emplace_back(); auto &arg = msg.args.emplace_back();
arg.type = arg_types[i]; arg.type = arg_types[i];
arg.set_name(StringRef(this->arg_names_[i])); arg.name = StringRef(this->arg_names_[i]);
} }
return msg; return msg;
} }
@@ -108,7 +108,7 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
ListEntitiesServicesResponse encode_list_service_response() override { ListEntitiesServicesResponse encode_list_service_response() override {
ListEntitiesServicesResponse msg; ListEntitiesServicesResponse msg;
msg.set_name(StringRef(this->name_)); msg.name = StringRef(this->name_);
msg.key = this->key_; msg.key = this->key_;
msg.supports_response = enums::SUPPORTS_RESPONSE_NONE; // Dynamic services don't support responses yet msg.supports_response = enums::SUPPORTS_RESPONSE_NONE; // Dynamic services don't support responses yet
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...}; std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
@@ -116,7 +116,7 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
for (size_t i = 0; i < sizeof...(Ts); i++) { for (size_t i = 0; i < sizeof...(Ts); i++) {
auto &arg = msg.args.emplace_back(); auto &arg = msg.args.emplace_back();
arg.type = arg_types[i]; arg.type = arg_types[i];
arg.set_name(StringRef(this->arg_names_[i])); arg.name = StringRef(this->arg_names_[i]);
} }
return msg; return msg;
} }
@@ -255,7 +255,7 @@ template<typename... Ts> class APIRespondAction : public Action<Ts...> {
bool return_response = std::get<1>(args); bool return_response = std::get<1>(args);
if (!return_response) { if (!return_response) {
// Client doesn't want response data, just send success/error // Client doesn't want response data, just send success/error
this->parent_->send_action_response(call_id, success, error_message); this->parent_->send_action_response(call_id, success, StringRef(error_message));
return; return;
} }
} }
@@ -265,12 +265,12 @@ template<typename... Ts> class APIRespondAction : public Action<Ts...> {
json::JsonBuilder builder; json::JsonBuilder builder;
this->json_builder_(x..., builder.root()); this->json_builder_(x..., builder.root());
std::string json_str = builder.serialize(); std::string json_str = builder.serialize();
this->parent_->send_action_response(call_id, success, error_message, this->parent_->send_action_response(call_id, success, StringRef(error_message),
reinterpret_cast<const uint8_t *>(json_str.data()), json_str.size()); reinterpret_cast<const uint8_t *>(json_str.data()), json_str.size());
return; return;
} }
#endif #endif
this->parent_->send_action_response(call_id, success, error_message); this->parent_->send_action_response(call_id, success, StringRef(error_message));
} }
protected: protected:

View File

@@ -0,0 +1,14 @@
import esphome.codegen as cg
CODEOWNERS = ["@jasstrong", "@ximex", "@freekode"]
aqi_ns = cg.esphome_ns.namespace("aqi")
AQICalculatorType = aqi_ns.enum("AQICalculatorType")
CONF_AQI = "aqi"
CONF_CALCULATION_TYPE = "calculation_type"
AQI_CALCULATION_TYPE = {
"CAQI": AQICalculatorType.CAQI_TYPE,
"AQI": AQICalculatorType.AQI_TYPE,
}

View File

@@ -0,0 +1,12 @@
#pragma once
#include <cstdint>
namespace esphome::aqi {
class AbstractAQICalculator {
public:
virtual uint16_t get_aqi(float pm2_5_value, float pm10_0_value) = 0;
};
} // namespace esphome::aqi

View File

@@ -0,0 +1,56 @@
#pragma once
#include <cmath>
#include <limits>
#include "abstract_aqi_calculator.h"
// https://document.airnow.gov/technical-assistance-document-for-the-reporting-of-daily-air-quailty.pdf
namespace esphome::aqi {
class AQICalculator : public AbstractAQICalculator {
public:
uint16_t get_aqi(float pm2_5_value, float pm10_0_value) override {
float pm2_5_index = calculate_index(pm2_5_value, PM2_5_GRID);
float pm10_0_index = calculate_index(pm10_0_value, PM10_0_GRID);
return static_cast<uint16_t>(std::round((pm2_5_index < pm10_0_index) ? pm10_0_index : pm2_5_index));
}
protected:
static constexpr int NUM_LEVELS = 6;
static constexpr int INDEX_GRID[NUM_LEVELS][2] = {{0, 50}, {51, 100}, {101, 150}, {151, 200}, {201, 300}, {301, 500}};
static constexpr float PM2_5_GRID[NUM_LEVELS][2] = {{0.0f, 9.0f}, {9.1f, 35.4f},
{35.5f, 55.4f}, {55.5f, 125.4f},
{125.5f, 225.4f}, {225.5f, std::numeric_limits<float>::max()}};
static constexpr float PM10_0_GRID[NUM_LEVELS][2] = {{0.0f, 54.0f}, {55.0f, 154.0f},
{155.0f, 254.0f}, {255.0f, 354.0f},
{355.0f, 424.0f}, {425.0f, std::numeric_limits<float>::max()}};
static float calculate_index(float value, const float array[NUM_LEVELS][2]) {
int grid_index = get_grid_index(value, array);
if (grid_index == -1) {
return -1.0f;
}
float aqi_lo = INDEX_GRID[grid_index][0];
float aqi_hi = INDEX_GRID[grid_index][1];
float conc_lo = array[grid_index][0];
float conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
}
static int get_grid_index(float value, const float array[NUM_LEVELS][2]) {
for (int i = 0; i < NUM_LEVELS; i++) {
if (value >= array[i][0] && value <= array[i][1]) {
return i;
}
}
return -1;
}
};
} // namespace esphome::aqi

View File

@@ -3,8 +3,7 @@
#include "caqi_calculator.h" #include "caqi_calculator.h"
#include "aqi_calculator.h" #include "aqi_calculator.h"
namespace esphome { namespace esphome::aqi {
namespace hm3301 {
enum AQICalculatorType { CAQI_TYPE = 0, AQI_TYPE = 1 }; enum AQICalculatorType { CAQI_TYPE = 0, AQI_TYPE = 1 };
@@ -12,18 +11,17 @@ class AQICalculatorFactory {
public: public:
AbstractAQICalculator *get_calculator(AQICalculatorType type) { AbstractAQICalculator *get_calculator(AQICalculatorType type) {
if (type == 0) { if (type == 0) {
return caqi_calculator_; return &this->caqi_calculator_;
} else if (type == 1) { } else if (type == 1) {
return aqi_calculator_; return &this->aqi_calculator_;
} }
return nullptr; return nullptr;
} }
protected: protected:
CAQICalculator *caqi_calculator_ = new CAQICalculator(); CAQICalculator caqi_calculator_;
AQICalculator *aqi_calculator_ = new AQICalculator(); AQICalculator aqi_calculator_;
}; };
} // namespace hm3301 } // namespace esphome::aqi
} // namespace esphome

View File

@@ -0,0 +1,51 @@
#include "aqi_sensor.h"
#include "esphome/core/log.h"
namespace esphome::aqi {
static const char *const TAG = "aqi";
void AQISensor::setup() {
if (this->pm_2_5_sensor_ != nullptr) {
this->pm_2_5_sensor_->add_on_state_callback([this](float value) {
this->pm_2_5_value_ = value;
// Defer calculation to avoid double-publishing if both sensors update in the same loop
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
if (this->pm_10_0_sensor_ != nullptr) {
this->pm_10_0_sensor_->add_on_state_callback([this](float value) {
this->pm_10_0_value_ = value;
this->defer("update", [this]() { this->calculate_aqi_(); });
});
}
}
void AQISensor::dump_config() {
ESP_LOGCONFIG(TAG, "AQI Sensor:");
ESP_LOGCONFIG(TAG, " Calculation Type: %s", this->aqi_calc_type_ == AQI_TYPE ? "AQI" : "CAQI");
if (this->pm_2_5_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " PM2.5 Sensor: '%s'", this->pm_2_5_sensor_->get_name().c_str());
}
if (this->pm_10_0_sensor_ != nullptr) {
ESP_LOGCONFIG(TAG, " PM10 Sensor: '%s'", this->pm_10_0_sensor_->get_name().c_str());
}
LOG_SENSOR(" ", "AQI", this);
}
void AQISensor::calculate_aqi_() {
if (std::isnan(this->pm_2_5_value_) || std::isnan(this->pm_10_0_value_)) {
return;
}
AbstractAQICalculator *calculator = this->aqi_calculator_factory_.get_calculator(this->aqi_calc_type_);
if (calculator == nullptr) {
ESP_LOGW(TAG, "Unknown AQI calculator type");
return;
}
uint16_t aqi = calculator->get_aqi(this->pm_2_5_value_, this->pm_10_0_value_);
this->publish_state(aqi);
}
} // namespace esphome::aqi

View File

@@ -0,0 +1,31 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/sensor/sensor.h"
#include "aqi_calculator_factory.h"
namespace esphome::aqi {
class AQISensor : public sensor::Sensor, public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_pm_2_5_sensor(sensor::Sensor *sensor) { this->pm_2_5_sensor_ = sensor; }
void set_pm_10_0_sensor(sensor::Sensor *sensor) { this->pm_10_0_sensor_ = sensor; }
void set_aqi_calculation_type(AQICalculatorType type) { this->aqi_calc_type_ = type; }
protected:
void calculate_aqi_();
sensor::Sensor *pm_2_5_sensor_{nullptr};
sensor::Sensor *pm_10_0_sensor_{nullptr};
AQICalculatorType aqi_calc_type_{AQI_TYPE};
AQICalculatorFactory aqi_calculator_factory_;
float pm_2_5_value_{NAN};
float pm_10_0_value_{NAN};
};
} // namespace esphome::aqi

View File

@@ -0,0 +1,53 @@
#pragma once
#include <cmath>
#include <limits>
#include "abstract_aqi_calculator.h"
namespace esphome::aqi {
class CAQICalculator : public AbstractAQICalculator {
public:
uint16_t get_aqi(float pm2_5_value, float pm10_0_value) override {
float pm2_5_index = calculate_index(pm2_5_value, PM2_5_GRID);
float pm10_0_index = calculate_index(pm10_0_value, PM10_0_GRID);
return static_cast<uint16_t>(std::round((pm2_5_index < pm10_0_index) ? pm10_0_index : pm2_5_index));
}
protected:
static constexpr int NUM_LEVELS = 5;
static constexpr int INDEX_GRID[NUM_LEVELS][2] = {{0, 25}, {26, 50}, {51, 75}, {76, 100}, {101, 400}};
static constexpr float PM2_5_GRID[NUM_LEVELS][2] = {
{0.0f, 15.0f}, {15.1f, 30.0f}, {30.1f, 55.0f}, {55.1f, 110.0f}, {110.1f, std::numeric_limits<float>::max()}};
static constexpr float PM10_0_GRID[NUM_LEVELS][2] = {
{0.0f, 25.0f}, {25.1f, 50.0f}, {50.1f, 90.0f}, {90.1f, 180.0f}, {180.1f, std::numeric_limits<float>::max()}};
static float calculate_index(float value, const float array[NUM_LEVELS][2]) {
int grid_index = get_grid_index(value, array);
if (grid_index == -1) {
return -1.0f;
}
float aqi_lo = INDEX_GRID[grid_index][0];
float aqi_hi = INDEX_GRID[grid_index][1];
float conc_lo = array[grid_index][0];
float conc_hi = array[grid_index][1];
return (value - conc_lo) * (aqi_hi - aqi_lo) / (conc_hi - conc_lo) + aqi_lo;
}
static int get_grid_index(float value, const float array[NUM_LEVELS][2]) {
for (int i = 0; i < NUM_LEVELS; i++) {
if (value >= array[i][0] && value <= array[i][1]) {
return i;
}
}
return -1;
}
};
} // namespace esphome::aqi

View File

@@ -0,0 +1,51 @@
import esphome.codegen as cg
from esphome.components import sensor
import esphome.config_validation as cv
from esphome.const import (
CONF_PM_2_5,
CONF_PM_10_0,
DEVICE_CLASS_AQI,
STATE_CLASS_MEASUREMENT,
)
from . import AQI_CALCULATION_TYPE, CONF_CALCULATION_TYPE, aqi_ns
CODEOWNERS = ["@jasstrong"]
DEPENDENCIES = ["sensor"]
UNIT_INDEX = "index"
AQISensor = aqi_ns.class_("AQISensor", sensor.Sensor, cg.Component)
CONFIG_SCHEMA = (
sensor.sensor_schema(
AQISensor,
unit_of_measurement=UNIT_INDEX,
accuracy_decimals=0,
device_class=DEVICE_CLASS_AQI,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.Required(CONF_PM_2_5): cv.use_id(sensor.Sensor),
cv.Required(CONF_PM_10_0): cv.use_id(sensor.Sensor),
cv.Required(CONF_CALCULATION_TYPE): cv.enum(
AQI_CALCULATION_TYPE, upper=True
),
}
)
.extend(cv.COMPONENT_SCHEMA)
)
async def to_code(config):
var = await sensor.new_sensor(config)
await cg.register_component(var, config)
pm_2_5_sensor = await cg.get_variable(config[CONF_PM_2_5])
cg.add(var.set_pm_2_5_sensor(pm_2_5_sensor))
pm_10_0_sensor = await cg.get_variable(config[CONF_PM_10_0])
cg.add(var.set_pm_10_0_sensor(pm_10_0_sensor))
cg.add(var.set_aqi_calculation_type(config[CONF_CALCULATION_TYPE]))

View File

@@ -305,12 +305,14 @@ bool AS3935Component::calibrate_oscillator() {
} }
void AS3935Component::tune_antenna() { void AS3935Component::tune_antenna() {
ESP_LOGI(TAG, "Starting antenna tuning");
uint8_t div_ratio = this->read_div_ratio(); uint8_t div_ratio = this->read_div_ratio();
uint8_t tune_val = this->read_capacitance(); uint8_t tune_val = this->read_capacitance();
ESP_LOGI(TAG, "Division Ratio is set to: %d", div_ratio); ESP_LOGI(TAG,
ESP_LOGI(TAG, "Internal Capacitor is set to: %d", tune_val); "Starting antenna tuning\n"
ESP_LOGI(TAG, "Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio"); "Division Ratio is set to: %d\n"
"Internal Capacitor is set to: %d\n"
"Displaying oscillator on INT pin. Measure its frequency - multiply value by Division Ratio",
div_ratio, tune_val);
this->display_oscillator(true, ANTFREQ); this->display_oscillator(true, ANTFREQ);
} }

View File

@@ -1,37 +1,50 @@
# Dummy integration to allow relying on AsyncTCP # Async TCP client support for all platforms
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_LN882X,
PLATFORM_RTL87XX,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
DEPENDENCIES = ["network"]
CONFIG_SCHEMA = cv.All(
cv.Schema({}), def AUTO_LOAD() -> list[str]:
cv.only_with_arduino, # Socket component needed for platforms using socket-based implementation
cv.only_on( # ESP32, ESP8266, RP2040, and LibreTiny use AsyncTCP libraries, others use sockets
[ if (
PLATFORM_ESP32, not CORE.is_esp32
PLATFORM_ESP8266, and not CORE.is_esp8266
PLATFORM_BK72XX, and not CORE.is_rp2040
PLATFORM_LN882X, and not CORE.is_libretiny
PLATFORM_RTL87XX, ):
] return ["socket"]
), return []
)
# Support all platforms - Arduino/ESP-IDF get libraries, other platforms use socket implementation
CONFIG_SCHEMA = cv.Schema({})
@coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT) @coroutine_with_priority(CoroPriority.NETWORK_TRANSPORT)
async def to_code(config): async def to_code(config):
if CORE.is_esp32 or CORE.is_libretiny: if CORE.is_esp32:
# https://github.com/ESP32Async/AsyncTCP
from esphome.components.esp32 import add_idf_component
add_idf_component(name="esp32async/asynctcp", ref="3.4.91")
elif CORE.is_libretiny:
# https://github.com/ESP32Async/AsyncTCP # https://github.com/ESP32Async/AsyncTCP
cg.add_library("ESP32Async/AsyncTCP", "3.4.5") cg.add_library("ESP32Async/AsyncTCP", "3.4.5")
elif CORE.is_esp8266: elif CORE.is_esp8266:
# https://github.com/ESP32Async/ESPAsyncTCP # https://github.com/ESP32Async/ESPAsyncTCP
cg.add_library("ESP32Async/ESPAsyncTCP", "2.0.0") cg.add_library("ESP32Async/ESPAsyncTCP", "2.0.0")
elif CORE.is_rp2040:
# https://github.com/khoih-prog/AsyncTCP_RP2040W
cg.add_library("khoih-prog/AsyncTCP_RP2040W", "1.2.0")
# Other platforms (host, etc) use socket-based implementation
def FILTER_SOURCE_FILES() -> list[str]:
# Exclude socket implementation for platforms that use AsyncTCP libraries
if CORE.is_esp32 or CORE.is_esp8266 or CORE.is_rp2040 or CORE.is_libretiny:
return ["async_tcp_socket.cpp"]
return []

View File

@@ -0,0 +1,16 @@
#pragma once
#include "esphome/core/defines.h"
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
// Use AsyncTCP library for ESP32 (Arduino or ESP-IDF) and LibreTiny
#include <AsyncTCP.h>
#elif defined(USE_ESP8266)
// Use ESPAsyncTCP library for ESP8266 (always Arduino)
#include <ESPAsyncTCP.h>
#elif defined(USE_RP2040)
// Use AsyncTCP_RP2040W library for RP2040
#include <AsyncTCP_RP2040W.h>
#else
// Use socket-based implementation for other platforms
#include "async_tcp_socket.h"
#endif

View File

@@ -0,0 +1,162 @@
#include "async_tcp_socket.h"
#if !defined(USE_ESP32) && !defined(USE_ESP8266) && !defined(USE_RP2040) && !defined(USE_LIBRETINY) && \
(defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS))
#include "esphome/components/network/util.h"
#include "esphome/core/log.h"
#include <cerrno>
#include <sys/select.h>
namespace esphome::async_tcp {
static const char *const TAG = "async_tcp";
// Read buffer size matches TCP MSS (1500 MTU - 40 bytes IP/TCP headers).
// This implementation only runs on ESP-IDF and host which have ample stack.
static constexpr size_t READ_BUFFER_SIZE = 1460;
bool AsyncClient::connect(const char *host, uint16_t port) {
if (connected_ || connecting_) {
ESP_LOGW(TAG, "Already connected/connecting");
return false;
}
// Resolve address
struct sockaddr_storage addr;
socklen_t addrlen = esphome::socket::set_sockaddr((struct sockaddr *) &addr, sizeof(addr), host, port);
if (addrlen == 0) {
ESP_LOGE(TAG, "Invalid address: %s", host);
if (error_cb_)
error_cb_(error_arg_, this, -1);
return false;
}
// Create socket with loop monitoring
int family = ((struct sockaddr *) &addr)->sa_family;
socket_ = esphome::socket::socket_loop_monitored(family, SOCK_STREAM, IPPROTO_TCP);
if (!socket_) {
ESP_LOGE(TAG, "Failed to create socket");
if (error_cb_)
error_cb_(error_arg_, this, -1);
return false;
}
socket_->setblocking(false);
int err = socket_->connect((struct sockaddr *) &addr, addrlen);
if (err == 0) {
// Connection succeeded immediately (rare, but possible for localhost)
connected_ = true;
if (connect_cb_)
connect_cb_(connect_arg_, this);
return true;
}
if (errno != EINPROGRESS) {
ESP_LOGE(TAG, "Connect failed: %d", errno);
close();
if (error_cb_)
error_cb_(error_arg_, this, errno);
return false;
}
connecting_ = true;
return true;
}
void AsyncClient::close() {
socket_.reset();
bool was_connected = connected_;
connected_ = false;
connecting_ = false;
if (was_connected && disconnect_cb_)
disconnect_cb_(disconnect_arg_, this);
}
size_t AsyncClient::write(const char *data, size_t len) {
if (!socket_ || !connected_)
return 0;
ssize_t sent = socket_->write(data, len);
if (sent < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
ESP_LOGE(TAG, "Write error: %d", errno);
close();
if (error_cb_)
error_cb_(error_arg_, this, errno);
}
return 0;
}
return sent;
}
void AsyncClient::loop() {
if (!socket_)
return;
if (connecting_) {
// For connecting, we need to check writability, not readability
// The Application's select() only monitors read FDs, so we do our own check here
// For ESP platforms lwip_select() might be faster, but this code isn't used
// on those platforms anyway. If it was, we'd fix the Application select()
// to report writability instead of doing it this way.
int fd = socket_->get_fd();
if (fd < 0) {
ESP_LOGW(TAG, "Invalid socket fd");
close();
return;
}
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
struct timeval tv = {0, 0};
int ret = select(fd + 1, nullptr, &writefds, nullptr, &tv);
if (ret > 0 && FD_ISSET(fd, &writefds)) {
int error = 0;
socklen_t len = sizeof(error);
if (socket_->getsockopt(SOL_SOCKET, SO_ERROR, &error, &len) == 0 && error == 0) {
connecting_ = false;
connected_ = true;
if (connect_cb_)
connect_cb_(connect_arg_, this);
} else {
ESP_LOGW(TAG, "Connection failed: %d", error);
close();
if (error_cb_)
error_cb_(error_arg_, this, error);
}
} else if (ret < 0) {
ESP_LOGE(TAG, "Select error: %d", errno);
close();
if (error_cb_)
error_cb_(error_arg_, this, errno);
}
} else if (connected_) {
// For connected sockets, use the Application's select() results
if (!socket_->ready())
return;
uint8_t buf[READ_BUFFER_SIZE];
ssize_t len = socket_->read(buf, READ_BUFFER_SIZE);
if (len == 0) {
ESP_LOGI(TAG, "Connection closed by peer");
close();
} else if (len > 0) {
if (data_cb_)
data_cb_(data_arg_, this, buf, len);
} else if (errno != EAGAIN && errno != EWOULDBLOCK) {
ESP_LOGW(TAG, "Read error: %d", errno);
close();
if (error_cb_)
error_cb_(error_arg_, this, errno);
}
}
}
} // namespace esphome::async_tcp
#endif

View File

@@ -0,0 +1,73 @@
#pragma once
#include "esphome/core/defines.h"
#if !defined(USE_ESP32) && !defined(USE_ESP8266) && !defined(USE_RP2040) && !defined(USE_LIBRETINY) && \
(defined(USE_SOCKET_IMPL_LWIP_SOCKETS) || defined(USE_SOCKET_IMPL_BSD_SOCKETS))
#include "esphome/components/socket/socket.h"
#include <functional>
#include <memory>
#include <string>
#include <utility>
namespace esphome::async_tcp {
/// AsyncClient API for platforms using sockets (ESP-IDF, host, etc.)
/// NOTE: This class is NOT thread-safe. All methods must be called from the main loop.
class AsyncClient {
public:
using AcConnectHandler = std::function<void(void *, AsyncClient *)>;
using AcDataHandler = std::function<void(void *, AsyncClient *, void *data, size_t len)>;
using AcErrorHandler = std::function<void(void *, AsyncClient *, int8_t error)>;
AsyncClient() = default;
~AsyncClient() = default;
[[nodiscard]] bool connect(const char *host, uint16_t port);
void close();
[[nodiscard]] bool connected() const { return connected_; }
size_t write(const char *data, size_t len);
void onConnect(AcConnectHandler cb, void *arg = nullptr) { // NOLINT(readability-identifier-naming)
connect_cb_ = std::move(cb);
connect_arg_ = arg;
}
void onDisconnect(AcConnectHandler cb, void *arg = nullptr) { // NOLINT(readability-identifier-naming)
disconnect_cb_ = std::move(cb);
disconnect_arg_ = arg;
}
/// Set data callback. NOTE: data pointer is only valid during callback execution.
void onData(AcDataHandler cb, void *arg = nullptr) { // NOLINT(readability-identifier-naming)
data_cb_ = std::move(cb);
data_arg_ = arg;
}
void onError(AcErrorHandler cb, void *arg = nullptr) { // NOLINT(readability-identifier-naming)
error_cb_ = std::move(cb);
error_arg_ = arg;
}
// Must be called from loop()
void loop();
private:
std::unique_ptr<esphome::socket::Socket> socket_;
AcConnectHandler connect_cb_{nullptr};
void *connect_arg_{nullptr};
AcConnectHandler disconnect_cb_{nullptr};
void *disconnect_arg_{nullptr};
AcDataHandler data_cb_{nullptr};
void *data_arg_{nullptr};
AcErrorHandler error_cb_{nullptr};
void *error_arg_{nullptr};
bool connected_{false};
bool connecting_{false};
};
} // namespace esphome::async_tcp
// Expose AsyncClient in global namespace to match library behavior
using esphome::async_tcp::AsyncClient; // NOLINT(google-global-names-in-headers)
#endif

View File

@@ -21,7 +21,9 @@ bool ATCMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device
ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
return false; return false;
} }
ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
const char *addr_str = device.address_str_to(addr_buf);
ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", addr_str);
bool success = false; bool success = false;
for (auto &service_data : device.get_service_datas()) { for (auto &service_data : device.get_service_datas()) {
@@ -32,7 +34,7 @@ bool ATCMiThermometer::parse_device(const esp32_ble_tracker::ESPBTDevice &device
if (!(parse_message_(service_data.data, *res))) { if (!(parse_message_(service_data.data, *res))) {
continue; continue;
} }
if (!(report_results_(res, device.address_str()))) { if (!(report_results_(res, addr_str))) {
continue; continue;
} }
if (res->temperature.has_value() && this->temperature_ != nullptr) if (res->temperature.has_value() && this->temperature_ != nullptr)
@@ -103,13 +105,13 @@ bool ATCMiThermometer::parse_message_(const std::vector<uint8_t> &message, Parse
return true; return true;
} }
bool ATCMiThermometer::report_results_(const optional<ParseResult> &result, const std::string &address) { bool ATCMiThermometer::report_results_(const optional<ParseResult> &result, const char *address) {
if (!result.has_value()) { if (!result.has_value()) {
ESP_LOGVV(TAG, "report_results(): no results available."); ESP_LOGVV(TAG, "report_results(): no results available.");
return false; return false;
} }
ESP_LOGD(TAG, "Got ATC MiThermometer (%s):", address.c_str()); ESP_LOGD(TAG, "Got ATC MiThermometer (%s):", address);
if (result->temperature.has_value()) { if (result->temperature.has_value()) {
ESP_LOGD(TAG, " Temperature: %.1f °C", *result->temperature); ESP_LOGD(TAG, " Temperature: %.1f °C", *result->temperature);

View File

@@ -41,7 +41,7 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
optional<ParseResult> parse_header_(const esp32_ble_tracker::ServiceData &service_data); optional<ParseResult> parse_header_(const esp32_ble_tracker::ServiceData &service_data);
bool parse_message_(const std::vector<uint8_t> &message, ParseResult &result); bool parse_message_(const std::vector<uint8_t> &message, ParseResult &result);
bool report_results_(const optional<ParseResult> &result, const std::string &address); bool report_results_(const optional<ParseResult> &result, const char *address);
}; };
} // namespace atc_mithermometer } // namespace atc_mithermometer

View File

@@ -158,12 +158,14 @@ void ATM90E32Component::setup() {
if (this->enable_offset_calibration_) { if (this->enable_offset_calibration_) {
// Initialize flash storage for offset calibrations // Initialize flash storage for offset calibrations
uint32_t o_hash = fnv1_hash(std::string("_offset_calibration_") + this->cs_summary_); uint32_t o_hash = fnv1_hash("_offset_calibration_");
o_hash = fnv1_hash_extend(o_hash, this->cs_summary_);
this->offset_pref_ = global_preferences->make_preference<OffsetCalibration[3]>(o_hash, true); this->offset_pref_ = global_preferences->make_preference<OffsetCalibration[3]>(o_hash, true);
this->restore_offset_calibrations_(); this->restore_offset_calibrations_();
// Initialize flash storage for power offset calibrations // Initialize flash storage for power offset calibrations
uint32_t po_hash = fnv1_hash(std::string("_power_offset_calibration_") + this->cs_summary_); uint32_t po_hash = fnv1_hash("_power_offset_calibration_");
po_hash = fnv1_hash_extend(po_hash, this->cs_summary_);
this->power_offset_pref_ = global_preferences->make_preference<PowerOffsetCalibration[3]>(po_hash, true); this->power_offset_pref_ = global_preferences->make_preference<PowerOffsetCalibration[3]>(po_hash, true);
this->restore_power_offset_calibrations_(); this->restore_power_offset_calibrations_();
} else { } else {
@@ -183,7 +185,8 @@ void ATM90E32Component::setup() {
if (this->enable_gain_calibration_) { if (this->enable_gain_calibration_) {
// Initialize flash storage for gain calibration // Initialize flash storage for gain calibration
uint32_t g_hash = fnv1_hash(std::string("_gain_calibration_") + this->cs_summary_); uint32_t g_hash = fnv1_hash("_gain_calibration_");
g_hash = fnv1_hash_extend(g_hash, this->cs_summary_);
this->gain_calibration_pref_ = global_preferences->make_preference<GainCalibration[3]>(g_hash, true); this->gain_calibration_pref_ = global_preferences->make_preference<GainCalibration[3]>(g_hash, true);
this->restore_gain_calibrations_(); this->restore_gain_calibrations_();

View File

@@ -1,6 +1,6 @@
#include "audio_reader.h" #include "audio_reader.h"
#ifdef USE_ESP_IDF #ifdef USE_ESP32
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
@@ -185,18 +185,16 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
return err; return err;
} }
std::string url_string = str_lower_case(url); if (str_endswith_ignore_case(url, ".wav")) {
if (str_endswith(url_string, ".wav")) {
file_type = AudioFileType::WAV; file_type = AudioFileType::WAV;
} }
#ifdef USE_AUDIO_MP3_SUPPORT #ifdef USE_AUDIO_MP3_SUPPORT
else if (str_endswith(url_string, ".mp3")) { else if (str_endswith_ignore_case(url, ".mp3")) {
file_type = AudioFileType::MP3; file_type = AudioFileType::MP3;
} }
#endif #endif
#ifdef USE_AUDIO_FLAC_SUPPORT #ifdef USE_AUDIO_FLAC_SUPPORT
else if (str_endswith(url_string, ".flac")) { else if (str_endswith_ignore_case(url, ".flac")) {
file_type = AudioFileType::FLAC; file_type = AudioFileType::FLAC;
} }
#endif #endif

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#ifdef USE_ESP_IDF #ifdef USE_ESP32
#include "audio.h" #include "audio.h"
#include "audio_transfer_buffer.h" #include "audio_transfer_buffer.h"

View File

@@ -22,7 +22,8 @@ bool BParasite::parse_device(const esp32_ble_tracker::ESPBTDevice &device) {
ESP_LOGVV(TAG, "parse_device(): unknown MAC address."); ESP_LOGVV(TAG, "parse_device(): unknown MAC address.");
return false; return false;
} }
ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str().c_str()); char addr_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
ESP_LOGVV(TAG, "parse_device(): MAC address %s found.", device.address_str_to(addr_buf));
const auto &service_datas = device.get_service_datas(); const auto &service_datas = device.get_service_datas();
if (service_datas.size() != 1) { if (service_datas.size() != 1) {
ESP_LOGE(TAG, "Unexpected service_datas size (%d)", service_datas.size()); ESP_LOGE(TAG, "Unexpected service_datas size (%d)", service_datas.size());

View File

@@ -3,6 +3,7 @@
#include "bedjet_hub.h" #include "bedjet_hub.h"
#include "bedjet_child.h" #include "bedjet_child.h"
#include "bedjet_const.h" #include "bedjet_const.h"
#include "esphome/components/esp32_ble/ble_uuid.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include <cinttypes> #include <cinttypes>
@@ -193,8 +194,9 @@ bool BedJetHub::discover_characteristics_() {
result = false; result = false;
} else if (descr->uuid.get_uuid().len != ESP_UUID_LEN_16 || } else if (descr->uuid.get_uuid().len != ESP_UUID_LEN_16 ||
descr->uuid.get_uuid().uuid.uuid16 != ESP_GATT_UUID_CHAR_CLIENT_CONFIG) { descr->uuid.get_uuid().uuid.uuid16 != ESP_GATT_UUID_CHAR_CLIENT_CONFIG) {
char uuid_buf[espbt::UUID_STR_LEN];
ESP_LOGW(TAG, "Config descriptor 0x%x (uuid %s) is not a client config char uuid", this->char_handle_status_, ESP_LOGW(TAG, "Config descriptor 0x%x (uuid %s) is not a client config char uuid", this->char_handle_status_,
descr->uuid.to_string().c_str()); descr->uuid.to_str(uuid_buf));
result = false; result = false;
} else { } else {
this->config_descr_status_ = descr->handle; this->config_descr_status_ = descr->handle;
@@ -216,11 +218,14 @@ bool BedJetHub::discover_characteristics_() {
} }
} }
ESP_LOGI(TAG, "[%s] Discovered service characteristics: ", this->get_name().c_str()); ESP_LOGI(TAG,
ESP_LOGI(TAG, " - Command char: 0x%x", this->char_handle_cmd_); "[%s] Discovered service characteristics:\n"
ESP_LOGI(TAG, " - Status char: 0x%x", this->char_handle_status_); " - Command char: 0x%x\n"
ESP_LOGI(TAG, " - config descriptor: 0x%x", this->config_descr_status_); " - Status char: 0x%x\n"
ESP_LOGI(TAG, " - Name char: 0x%x", this->char_handle_name_); " - config descriptor: 0x%x\n"
" - Name char: 0x%x",
this->get_name().c_str(), this->char_handle_cmd_, this->char_handle_status_, this->config_descr_status_,
this->char_handle_name_);
return result; return result;
} }

View File

@@ -1,12 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import ble_client, climate from esphome.components import climate
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import CONF_HEAT_MODE, CONF_TEMPERATURE_SOURCE
CONF_HEAT_MODE,
CONF_RECEIVE_TIMEOUT,
CONF_TEMPERATURE_SOURCE,
CONF_TIME_ID,
)
from .. import BEDJET_CLIENT_SCHEMA, bedjet_ns, register_bedjet_child from .. import BEDJET_CLIENT_SCHEMA, bedjet_ns, register_bedjet_child
@@ -38,22 +33,6 @@ CONFIG_SCHEMA = (
} }
) )
.extend(cv.polling_component_schema("60s")) .extend(cv.polling_component_schema("60s"))
.extend(
# TODO: remove compat layer.
{
cv.Optional(ble_client.CONF_BLE_CLIENT_ID): cv.invalid(
"The 'ble_client_id' option has been removed. Please migrate "
"to the new `bedjet_id` option in the `bedjet` component.\n"
"See https://esphome.io/components/climate/bedjet/"
),
cv.Optional(CONF_TIME_ID): cv.invalid(
"The 'time_id' option has been moved to the `bedjet` component."
),
cv.Optional(CONF_RECEIVE_TIMEOUT): cv.invalid(
"The 'receive_timeout' option has been moved to the `bedjet` component."
),
}
)
.extend(BEDJET_CLIENT_SCHEMA) .extend(BEDJET_CLIENT_SCHEMA)
) )

View File

@@ -164,21 +164,21 @@ void BedJetClimate::control(const ClimateCall &call) {
return; return;
} }
} else if (call.has_custom_preset()) { } else if (call.has_custom_preset()) {
const char *preset = call.get_custom_preset(); auto preset = call.get_custom_preset();
bool result; bool result;
if (strcmp(preset, "M1") == 0) { if (preset == "M1") {
result = this->parent_->button_memory1(); result = this->parent_->button_memory1();
} else if (strcmp(preset, "M2") == 0) { } else if (preset == "M2") {
result = this->parent_->button_memory2(); result = this->parent_->button_memory2();
} else if (strcmp(preset, "M3") == 0) { } else if (preset == "M3") {
result = this->parent_->button_memory3(); result = this->parent_->button_memory3();
} else if (strcmp(preset, "LTD HT") == 0) { } else if (preset == "LTD HT") {
result = this->parent_->button_heat(); result = this->parent_->button_heat();
} else if (strcmp(preset, "EXT HT") == 0) { } else if (preset == "EXT HT") {
result = this->parent_->button_ext_heat(); result = this->parent_->button_ext_heat();
} else { } else {
ESP_LOGW(TAG, "Unsupported preset: %s", preset); ESP_LOGW(TAG, "Unsupported preset: %.*s", (int) preset.size(), preset.c_str());
return; return;
} }
@@ -208,10 +208,11 @@ void BedJetClimate::control(const ClimateCall &call) {
this->set_fan_mode_(fan_mode); this->set_fan_mode_(fan_mode);
} }
} else if (call.has_custom_fan_mode()) { } else if (call.has_custom_fan_mode()) {
const char *fan_mode = call.get_custom_fan_mode(); auto fan_mode = call.get_custom_fan_mode();
auto fan_index = bedjet_fan_speed_to_step(fan_mode); auto fan_index = bedjet_fan_speed_to_step(fan_mode.c_str());
if (fan_index <= 19) { if (fan_index <= 19) {
ESP_LOGV(TAG, "[%s] Converted fan mode %s to bedjet fan step %d", this->get_name().c_str(), fan_mode, fan_index); ESP_LOGV(TAG, "[%s] Converted fan mode %.*s to bedjet fan step %d", this->get_name().c_str(),
(int) fan_mode.size(), fan_mode.c_str(), fan_index);
bool result = this->parent_->set_fan_index(fan_index); bool result = this->parent_->set_fan_index(fan_index);
if (result) { if (result) {
this->set_custom_fan_mode_(fan_mode); this->set_custom_fan_mode_(fan_mode);

Some files were not shown because too many files have changed in this diff Show More