Compare commits

...

2185 Commits

Author SHA1 Message Date
J. Nick Koston
bb0f85c48c [vbus] Use stack-based hex formatting in verbose logging 2025-12-31 22:02: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
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
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
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
J. Nick Koston
ce717e2276 Merge branch 'integration' into memory_api 2025-12-12 19:24:21 -06:00
J. Nick Koston
20b6d28c90 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-12 19:24:14 -06:00
David Woodhouse
ff7651875e Add HMAC-MD5 component tests (#12459) 2025-12-12 19:19:31 -06:00
David Woodhouse
1a43a06dd4 Add USE_SHA256 define to sha256 component to enable tests (#12457) 2025-12-12 19:15:50 -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
dependabot[bot]
51b187954a Bump ruff from 0.14.8 to 0.14.9 (#12448)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-12 19:20:06 +00:00
dependabot[bot]
9126b32c35 Bump actions/cache from 4.3.0 to 5.0.1 in /.github/actions/restore-python (#12453)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-12 13:17:08 -06:00
dependabot[bot]
4993bb2f49 Bump github/codeql-action from 4.31.7 to 4.31.8 (#12451)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-12 13:16:41 -06:00
dependabot[bot]
2b40af3459 Bump actions/cache from 4.3.0 to 5.0.1 (#12450)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-12 13:16:29 -06:00
dependabot[bot]
b3e967a233 Bump actions/download-artifact from 6.0.0 to 7.0.0 (#12449)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-12 13:15:41 -06:00
dependabot[bot]
26a08e3ae3 Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#12452)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-12 13:15:28 -06: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
J. Nick Koston
b2a1448fe4 Merge branch 'integration' into memory_api 2025-12-12 12:37:42 -06:00
J. Nick Koston
e05e5bc82c Merge branch 'wifi_cleanups' into integration 2025-12-12 12:37:36 -06:00
J. Nick Koston
eeefc0e6c4 [wifi] Replace optional with sentinel values to reduce RAM and clarify API 2025-12-12 12:35:30 -06:00
J. Nick Koston
d54088d1fb Merge branch 'integration' into memory_api 2025-12-12 11:39:41 -06:00
J. Nick Koston
16a532f565 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-12 11:39:31 -06:00
Jonathan Swoboda
64d650c65c Merge branch 'beta' into dev 2025-12-12 12:15:52 -05:00
Jonathan Swoboda
375e53105f Merge pull request #12444 from esphome/bump-2025.12.0b2
2025.12.0b2
2025-12-12 12:15:41 -05: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
Jonathan Swoboda
c9506b056d Bump version to 2025.12.0b2 2025-12-12 11:12:58 -05:00
Jonathan Swoboda
2c77668a05 [http_request] Skip update check when network not connected (#12418)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-12 11:12:58 -05:00
J. Nick Koston
5567d96dd9 [esp8266] Eliminate up to 16ms socket latency (#12397) 2025-12-12 11:12:58 -05:00
J. Nick Koston
78b76045ce [api] Fix potential buffer overflow in noise PSK base64 decode (#12395) 2025-12-12 11:12:58 -05:00
J. Nick Koston
1d13d18a16 [light] Add zero-copy support for API effect commands (#12384) 2025-12-12 11:12:58 -05:00
Jonathan Swoboda
d30d8156c1 [http_request] Skip update check when network not connected (#12418)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-12 10:31:17 -05:00
David Woodhouse
25805da008 Merge branch 'dev' into buildinfo 2025-12-12 09:54:47 +09:00
dependabot[bot]
8d1e68c4c1 Bump tornado from 6.5.2 to 6.5.3 (#12430)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-11 17:53:12 -06: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
74218bc742 [api] Release prologue memory after noise handshake completes (#12412) 2025-12-10 19:33:22 -06:00
J. Nick Koston
369cc70fdf [climate] Save 48 bytes per entity by conditionally compiling visual overrides (#12406) 2025-12-10 19:10:42 -06:00
dependabot[bot]
1f0a27b181 Bump codecov/codecov-action from 5.5.1 to 5.5.2 (#12408)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-10 22:34:24 +01:00
J. Nick Koston
d7cb3d8e35 Merge branch 'integration' into memory_api 2025-12-10 22:32:19 +01:00
J. Nick Koston
6519b90829 Merge branch 'noise_prologue_not_released' into integration 2025-12-10 22:31:59 +01:00
J. Nick Koston
5c39ff7b5c [api] Release prologue memory after noise handshake completes 2025-12-10 22:31:09 +01:00
dependabot[bot]
22918d3bd5 Bump peter-evans/create-pull-request from 7.0.11 to 8.0.0 (#12409)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-10 22:21:29 +01:00
J. Nick Koston
7a9fce90cb [text] Add integration tests for text command API (#12401) 2025-12-10 12:13:40 -05:00
J. Nick Koston
4f9c00382e Merge branch 'integration' into memory_api 2025-12-10 13:50:46 +01:00
J. Nick Koston
afd9fc6c96 Merge branch 'visual_overrides_rarely_used' into integration 2025-12-10 13:50:33 +01:00
J. Nick Koston
a3017ca3be [climate] Save 48 bytes per entity by conditionally compiling visual overrides 2025-12-10 13:46:50 +01:00
dependabot[bot]
d1d376ebc8 Bump actions/create-github-app-token from 2.2.0 to 2.2.1 (#12370)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-10 13:05:01 +01: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
J. Nick Koston
c124d72ea9 [esp8266] Eliminate up to 16ms socket latency (#12397) 2025-12-10 03:45:27 +00:00
J. Nick Koston
5b83e9e81b Merge branch 'integration' into memory_api 2025-12-10 04:34:28 +01:00
J. Nick Koston
e85aa1e24b Merge remote-tracking branch 'upstream/dev' into integration 2025-12-10 04:34:16 +01:00
J. Nick Koston
567e82cfec [api] Fix potential buffer overflow in noise PSK base64 decode (#12395) 2025-12-10 04:20:23 +01:00
J. Nick Koston
b1f9100b02 [core] Add constexpr parse_hex_char helper and simplify parse_hex (#12394) 2025-12-10 04:20:08 +01:00
J. Nick Koston
d0fbc82f47 [esp32_ble_client] Use stack-based MAC formatting in auth logging (#12393)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-10 04:19:52 +01:00
J. Nick Koston
03c391bd43 [light] Add zero-copy support for API effect commands (#12384) 2025-12-10 04:19:29 +01:00
J. Nick Koston
95609480b7 Merge branch 'integration' into memory_api 2025-12-10 04:01:12 +01:00
J. Nick Koston
7dca3c9eee Merge branch 'esp8266_wake' into integration 2025-12-10 04:01:07 +01:00
J. Nick Koston
cbbb3bbabc wake flag 2025-12-10 04:00:54 +01:00
J. Nick Koston
3aaca9e668 Merge branch 'integration' into memory_api 2025-12-10 03:57:59 +01:00
J. Nick Koston
33bba52a79 Merge branch 'esp8266_wake' into integration 2025-12-10 03:57:54 +01:00
J. Nick Koston
e160fcce0e fixes 2025-12-10 03:51:20 +01:00
Jonathan Swoboda
5601a2b686 Merge branch 'beta' into dev 2025-12-09 21:34:12 -05:00
Jonathan Swoboda
a3a2a6d965 Merge pull request #12396 from esphome/bump-2025.12.0b1
2025.12.0b1
2025-12-09 21:33:58 -05:00
J. Nick Koston
fa58cf7f9f Merge branch 'integration' into memory_api 2025-12-10 03:25:47 +01:00
J. Nick Koston
5b9053c678 Merge branch 'esp8266_wake' into integration 2025-12-10 03:25:41 +01:00
J. Nick Koston
a9a3103a0d more legacy code that clang-tidy is complaining about 2025-12-10 03:25:31 +01:00
J. Nick Koston
ccd0df87ac Merge branch 'integration' into memory_api 2025-12-10 03:21:03 +01:00
J. Nick Koston
79b6f2a288 Merge branch 'esp8266_wake' into integration 2025-12-10 03:20:58 +01:00
J. Nick Koston
795ace5eaa make clang-tidy happy 2025-12-10 03:17:17 +01:00
J. Nick Koston
0a5e8af69f Merge branch 'integration' into memory_api 2025-12-10 03:10:49 +01:00
J. Nick Koston
a84de27831 Merge branch 'esp8266_wake' into integration 2025-12-10 03:10:37 +01:00
J. Nick Koston
a4e81dc176 [socket] Wake loop immediately on socket data for ESP8266 2025-12-10 03:09:47 +01:00
J. Nick Koston
882838c389 Merge branch 'integration' into memory_api 2025-12-10 02:35:03 +01:00
J. Nick Koston
564bc7caf1 Merge branch 'noise_eliminate_temp_std_vector' into integration 2025-12-10 02:34:58 +01:00
J. Nick Koston
f10a2ed6bc fix buffer overflow 2025-12-10 02:26:49 +01:00
J. Nick Koston
d442095d9a fix buffer overflow 2025-12-10 02:26:12 +01:00
J. Nick Koston
d52981fe01 Merge branch 'integration' into memory_api 2025-12-10 02:22:38 +01:00
J. Nick Koston
29f2b358d1 Merge branch 'noise_eliminate_temp_std_vector' into integration 2025-12-10 02:22:30 +01:00
J. Nick Koston
9fd952c18b [core] Eliminate temporary vector in base64_decode buffer overload 2025-12-10 02:18:23 +01:00
Jonathan Swoboda
84d5348bd8 Bump version to 2026.1.0-dev 2025-12-09 20:08:35 -05:00
Jonathan Swoboda
26770e09dc Bump version to 2025.12.0b1 2025-12-09 20:08:35 -05:00
J. Nick Koston
45e843779c Merge branch 'integration' into memory_api 2025-12-10 02:04:37 +01:00
J. Nick Koston
a56c8e4d37 Merge branch 'parse_hex_constexpr' into integration 2025-12-10 02:04:23 +01:00
J. Nick Koston
0ece36ecc5 [core] Add constexpr parse_hex_char helper and simplify parse_hex 2025-12-10 02:02:53 +01:00
J. Nick Koston
231199defe Merge branch 'integration' into memory_api 2025-12-10 01:50:33 +01:00
J. Nick Koston
eb2781e418 Merge branch 'ble_mac_address_formatting_cleanup' into integration 2025-12-10 01:50:27 +01:00
J. Nick Koston
7bdee7261d Update esphome/components/esp32_ble_client/ble_client_base.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-10 01:50:06 +01:00
J. Nick Koston
efbd202518 Merge branch 'integration' into memory_api 2025-12-10 01:47:10 +01:00
J. Nick Koston
f50feca026 Merge branch 'ble_mac_address_formatting_cleanup' into integration 2025-12-10 01:46:56 +01:00
J. Nick Koston
602f25ba89 [esp32_ble_client] Use stack-based MAC formatting in auth logging 2025-12-10 01:46:28 +01:00
J. Nick Koston
56f699e897 Merge branch 'integration' into memory_api 2025-12-10 01:36:18 +01:00
J. Nick Koston
efbdbc63d0 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-10 01:36:11 +01:00
Javier Peletier
9f2693ead5 [core] Packages refactor and conditional package inclusion (package refactor part 1) (#11605)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-10 00:59:58 +01:00
J. Nick Koston
3642399460 [tests] Fix clang-tidy warnings in custom_api_device_component fixture (#12390) 2025-12-10 00:50:26 +01:00
J. Nick Koston
3a6edbc2c7 [micronova] Fix test UART package key to match directory name (#12391) 2025-12-10 00:49:44 +01:00
J. Nick Koston
608f834eaa [ci] Isolate usb_cdc_acm in component tests due to tinyusb/usb_host conflict (#12392) 2025-12-10 00:49:29 +01:00
J. Nick Koston
5919355d18 [ci] Allow memory impact target branch build to fail without blocking CI (#12381) 2025-12-10 00:26:24 +01:00
J. Nick Koston
e0147aab16 Merge branch 'light_effects_call_zero_copy' into integration 2025-12-09 23:52:12 +01:00
J. Nick Koston
724fb222dc Merge remote-tracking branch 'upstream/dev' into integration
# Conflicts:
#	esphome/components/api/api_connection.cpp
#	esphome/components/api/api_server.cpp
#	esphome/components/api/api_server.h
#	esphome/components/wifi_signal/wifi_signal_sensor.h
#	esphome/core/string_ref.h
2025-12-09 23:51:44 +01:00
dependabot[bot]
1e23b10eed Bump aioesphomeapi from 43.1.0 to 43.2.1 (#12385)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 22:02:42 +00:00
Clyde Stubbs
ad0218fd40 [mipi_rgb] Add Waveshare 3.16 (#12309) 2025-12-10 08:17:59 +11:00
J. Nick Koston
8525f24a3b [light] Add zero-copy support for API effect commands 2025-12-09 21:53:03 +01:00
Clyde Stubbs
87142efbb4 [epaper_spi] Set reasonable default update interval (#12331) 2025-12-10 06:42:11 +11:00
Robert Resch
329b38fa29 [micronova] Require memory location and address for custom entities (#12371) 2025-12-09 14:30:55 -05:00
Jonathan Swoboda
4b44c7384b Merge branch 'release' into dev 2025-12-09 12:54:45 -05:00
Jonathan Swoboda
a593965372 Merge pull request #12380 from esphome/bump-2025.11.5
2025.11.5
2025-12-09 12:54:30 -05:00
Jonathan Swoboda
4743e5592a Bump version to 2025.11.5 2025-12-09 12:02:53 -05:00
Jonathan Swoboda
464607011c [mqtt] Fix logger method case sensitivity error (#12379)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-09 12:02:53 -05:00
J. Nick Koston
16fe8f9e9e [libretiny] Fix WiFi scan timeout loop when scan fails (#12356) 2025-12-09 12:02:46 -05:00
J. Nick Koston
436d2c44e8 [wifi] Fix scan timeout loop when scan returns zero networks (#12354) 2025-12-09 12:01:51 -05:00
J. Nick Koston
b213555dd2 [scheduler] Fix missing lock when recycling items in defer queue processing (#12343) 2025-12-09 12:01:51 -05:00
Clyde Stubbs
b6336f9e63 [lvgl] Number saves value on interactive change (#12315) 2025-12-09 12:01:51 -05:00
Clyde Stubbs
fb7800a22f [binary_sensor] Fix reporting of 'unknown' (#12296)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-09 12:01:51 -05:00
J. Nick Koston
2c0f4d8f80 [api] Reduce heap usage for Home Assistant service call string storage (#12151) 2025-12-09 16:35:14 +01:00
J. Nick Koston
e96c37965c [wifi] Fix LibreTiny spurious disconnect events aborting connections (#12357) 2025-12-09 16:26:27 +01:00
J. Nick Koston
72c74bc0b3 [api] Store Home Assistant state subscriptions in flash instead of heap (#12008) 2025-12-09 16:26:11 +01:00
J. Nick Koston
443f9c3f57 [api] Use StringRef for ActionResponse error message to avoid copy (#12240) 2025-12-09 16:10:43 +01:00
Javier Peletier
88a2e75989 [packages] Add more information and deprecation deadline for "single package" includes (#12280) 2025-12-09 16:04:10 +01:00
J. Nick Koston
e1afd65fae [api] Store device info strings in flash on ESP8266 (#12173) 2025-12-09 15:59:27 +01:00
Jonathan Swoboda
27e031c257 [mqtt] Fix logger method case sensitivity error (#12379)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-09 09:43:47 -05:00
Jonathan Swoboda
74f509c754 [core] Add PR template instruction to AI instructions (#12375)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-09 15:42:06 +01:00
J. Nick Koston
f9aa48295c [mdns] Reduce RAM usage by eliminating MAC address heap allocation (#12073) 2025-12-09 09:33:23 -05:00
J. Nick Koston
861ed8dd41 [scheduler] Avoid std::string allocation in RetryArgs (#12311) 2025-12-09 09:27:12 -05:00
Clyde Stubbs
750f4ea797 [pio] Rationalise library definitions in platformio.ini (#12374) 2025-12-09 08:40:58 -05:00
Clyde Stubbs
6945b44af5 [psram] Fix boot failure with 120MHz Octal flash (#12377) 2025-12-09 08:38:16 -05:00
Mirko Vogt
fcae13836c [sx1509] Change setup priority from HARDWARE to IO (#12373)
Co-authored-by: Your Name <you@example.com>
2025-12-08 22:50:07 -05:00
Robert Resch
3eaa9f164b [micronova] Remove MicroNovaFunctions (#12363)
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>
2025-12-08 14:38:13 -05:00
smarthome-10
4c31961ae9 Update URLs (#12369)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-08 14:37:45 -05:00
Sébastien Blanchet
7a20c85eec [i2c] Fix port logic with ESP-IDF (#12063)
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-08 14:12:15 -05:00
Robert Resch
9f60aed9b0 [micronova] Make stove switch entity independent (#12355)
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>
2025-12-08 11:18:44 -05:00
J. Nick Koston
801d1135ab [select] Add zero-copy support for API select commands (#12329) 2025-12-08 10:37:51 -05:00
J. Nick Koston
d635892ecf [core] Use StringRef for get_comment and get_compilation_time to avoid allocations (#12219)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-08 10:36:13 -05:00
Johannes Nau
7e486b1c25 [pca9685] Allow to disable the phase balancer for PCA9685 (#9792) 2025-12-08 10:34:26 -05:00
Keith Burzinski
eda743ee48 [usb_cdc_acm] New component (#11687)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-08 09:50:23 -05:00
Sébastien Blanchet
5144154f91 [hub75] fix id conflict (#12365) 2025-12-08 14:31:05 +00:00
J. Nick Koston
4466c4c69f [libretiny] Fix WiFi scan timeout loop when scan fails (#12356) 2025-12-08 09:09:04 -05:00
Richard Kubíček
c7382fc494 [hlw8032] Single-phase metering IC (#7241)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-08 09:07:10 -05:00
Robert Resch
95efb37045 [micronova] Set the write bit automatically (#12318)
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>
2025-12-08 08:39:43 -05:00
Berik Visschers
2515f1c080 Add seeed_xiao_esp32c6 board definition (#12307)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-08 08:37:59 -05:00
J. Nick Koston
53ddd1a1cd [wifi_signal] Add ifdef guards for clang-tidy compatibility (#12362) 2025-12-08 07:43:48 -05:00
J. Nick Koston
b953c0322c Merge branch 'integration' into memory_api 2025-12-07 22:13:53 -06:00
J. Nick Koston
ed8b21aec3 Merge branch 'libretiny_wifi' into integration 2025-12-07 22:13:42 -06:00
J. Nick Koston
93a85d7979 [wifi_signal] Update signal strength immediately on WiFi connect/disconnect (#12347) 2025-12-07 22:08:46 -06:00
J. Nick Koston
159194587b [core] Move Color::gradient to cpp to avoid duplicate code (#12348) 2025-12-07 22:08:21 -06:00
J. Nick Koston
590f9ca488 Merge branch 'dev' into libretiny_wifi 2025-12-07 22:00:15 -06:00
J. Nick Koston
ffb3e2eb0a [wifi] Fix scan timeout loop when scan returns zero networks (#12354) 2025-12-07 22:00:04 -06:00
J. Nick Koston
da4bd321f0 [libretiny] Fix WiFi scan timeout loop when scan fails 2025-12-07 21:54:09 -06:00
Robert Resch
c5cc91f6f0 [micronova] Add FINAL_VALIDATE_SCHEMA to validate uart (#12350)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-07 21:02:05 -05:00
J. Nick Koston
26475cd7d3 Merge branch 'integration' into memory_api 2025-12-07 18:51:22 -06:00
J. Nick Koston
50ce7b361a Merge branch 'wifi_scan_failure_recover' into integration 2025-12-07 18:51:16 -06:00
J. Nick Koston
02acfeac2c [wifi] Fix scan timeout loop when scan returns zero networks 2025-12-07 18:50:43 -06:00
Robert Resch
e36e6fbc3f [micronova] Move STOVE_STATES to text sensor file as it's used only there (#12349) 2025-12-07 19:08:41 -05:00
Robert Resch
1134251c32 [micronova] Set update_interval on entities instead on hub (#12226)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-07 23:55:36 +00:00
J. Nick Koston
68a7634228 [text] Store pattern as const char* to reduce memory usage (#12335) 2025-12-07 15:33:15 -06:00
J. Nick Koston
dd65488f91 Merge branch 'integration' into memory_api 2025-12-07 15:27:09 -06:00
J. Nick Koston
659f257703 Merge branch 'stale_wifi_signal_on_connect' into integration 2025-12-07 15:27:01 -06:00
J. Nick Koston
9c28bbcfa8 [wifi_signal] Update signal strength immediately on WiFi connect/disconnect 2025-12-07 15:25:04 -06:00
J. Nick Koston
3d5d89ff00 [template] Use C++17 nested namespace syntax (#12346) 2025-12-07 15:09:25 -06:00
Joakim Plate
f015130f2e [esp8266] Allow use of recvfrom for esphome sockets (#12342) 2025-12-07 14:59:59 -06:00
J. Nick Koston
acda5bcd5a [text] Add component tests with pattern coverage (#12345) 2025-12-07 14:34:12 -06:00
Edward Firmo
4b5435fd93 [nextion] Use 16-bit id for pics (#12330)
Co-authored-by: Szczepan <szczepan.staszak@gmail.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-07 15:16:49 -05:00
J. Nick Koston
05826d5ead [scheduler] Fix missing lock when recycling items in defer queue processing (#12343) 2025-12-07 13:30:22 -06:00
J. Nick Koston
e7a3cccb4d [text_sensor] Reduce filter memory usage using const char* (#12334) 2025-12-07 13:30:06 -06:00
J. Nick Koston
dbbb5f25e3 Merge branch 'integration' into memory_api 2025-12-07 13:22:04 -06:00
J. Nick Koston
40f865e185 Merge branch 'text_pattern' into integration 2025-12-07 13:21:55 -06:00
J. Nick Koston
6b0128b683 Merge branch 'text_sensor_filters_no_alloc' into integration 2025-12-07 13:21:47 -06:00
J. Nick Koston
475ce1f3fa tweaks 2025-12-07 12:43:02 -06:00
J. Nick Koston
d881e6055e tweak 2025-12-07 10:31:33 -06:00
J. Nick Koston
188148546e [text] Store pattern as const char* to reduce memory usage 2025-12-06 23:55:38 -06:00
J. Nick Koston
e63673f5ef [text] Store pattern as const char* to reduce memory usage 2025-12-06 23:55:15 -06:00
J. Nick Koston
789faca7c4 [text] Store pattern as const char* to reduce memory usage 2025-12-06 23:50:48 -06:00
J. Nick Koston
0610b3a60a [text] Store pattern as const char* to reduce memory usage 2025-12-06 23:49:09 -06:00
J. Nick Koston
36036014cc reduce 2025-12-06 23:30:15 -06:00
J. Nick Koston
5264584202 reduce 2025-12-06 23:29:26 -06:00
J. Nick Koston
716a868da6 reduce 2025-12-06 23:29:10 -06:00
J. Nick Koston
02fcd83461 Merge branch 'text_sensor_filters_no_alloc' into integration 2025-12-06 22:55:54 -06:00
J. Nick Koston
f3a039e70f cover 2025-12-06 22:55:28 -06:00
J. Nick Koston
81f4add324 [text_sensor] Use StringRef for filter static data to avoid heap allocation 2025-12-06 22:31:21 -06:00
J. Nick Koston
8fd7c00613 [text_sensor] Use StringRef for filter static data to avoid heap allocation 2025-12-06 22:29:24 -06:00
J. Nick Koston
49e7ccd937 [text_sensor] Use StringRef for filter static data to avoid heap allocation 2025-12-06 22:25:00 -06:00
J. Nick Koston
c90e91eef8 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-06 21:53:51 -06:00
J. Nick Koston
a100caff9f Merge branch 'zero_copy_select' into integration 2025-12-06 21:33:32 -06:00
dependabot[bot]
1f271e7c10 Bump pytest from 9.0.1 to 9.0.2 (#12332)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 21:32:08 -06:00
dependabot[bot]
aeedfdcaf3 Bump aioesphomeapi from 43.0.0 to 43.1.0 (#12333)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-06 21:31:56 -06:00
J. Nick Koston
96108a1277 [select] Add zero-copy support for API select commands 2025-12-06 14:35:43 -06:00
J. Nick Koston
f23428fbaf Merge remote-tracking branch 'upstream/dev' into integration 2025-12-06 14:10:44 -06:00
Jesse Hills
f20aaf3981 [api] Device defined action responses (#12136)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-06 09:47:57 -06:00
Clyde Stubbs
75c41b11d1 [lvgl] Number saves value on interactive change (#12315) 2025-12-06 08:49:15 -06:00
Clyde Stubbs
3c7d6b7fc6 [ci-custom] Fix after switch from string to path (#12314) 2025-12-06 07:49:23 -06:00
Clyde Stubbs
7eae0a4972 [image] Add USE_IMAGE in defines.h (#12317) 2025-12-06 07:46:39 -06:00
Jonathan Swoboda
6220427524 [cc1101] Use Hz and cv.frequency instead of kHz (#12313) 2025-12-05 22:32:20 -05:00
J. Nick Koston
aba883a7a7 Merge branch 'retry_no_double_copy' into integration 2025-12-05 20:52:07 -06:00
J. Nick Koston
554ce30fca add missing overloads 2025-12-05 20:46:26 -06:00
J. Nick Koston
05dd1e4602 [scheduler] Avoid std::string allocation in RetryArgs 2025-12-05 20:38:57 -06:00
Clyde Stubbs
6716194e47 [binary_sensor] Fix reporting of 'unknown' (#12296)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-05 16:59:29 -06:00
J. Nick Koston
d89aeca65a Merge remote-tracking branch 'upstream/dev' into integration 2025-12-05 15:58:18 -06:00
Jonathan Swoboda
a517e0ec80 [esp32] Add missing variant support (#12305)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-05 16:28:24 -05:00
dependabot[bot]
10b54df771 Bump github/codeql-action from 4.31.6 to 4.31.7 (#12304)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-05 15:17:10 -06:00
dependabot[bot]
bbb71b5359 Bump peter-evans/create-pull-request from 7.0.9 to 7.0.11 (#12303)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-05 15:16:55 -06:00
Ludovic BOUÉ
1fa7adbe8d [mipi_spi] Add M5CORE2 model (#12301) 2025-12-06 07:24:57 +11:00
Stuart Parmenter
7421f31160 [hub75] HUB75 display component (#11153)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-05 18:51:32 +00:00
c0mputerguru
78bef42473 [sps30] Add idle mode functionality (#12255)
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-05 13:33:00 -05:00
J. Nick Koston
7f7c913a85 [light] Fix schedule_show not enabling loop for idle addressable lights (#12302) 2025-12-05 11:47:54 -06:00
Jonathan Swoboda
1a308583b3 [esp32] Add support for ESP32-C61 variant (#12285)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-12-05 12:16:19 -05:00
J. Nick Koston
27fcff2092 [api] Simplify MessageCreator to trivially copyable type (#12295)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-05 10:27:41 -06:00
Jonathan Swoboda
f4d1c9df71 [remote_receiver] Fix Zephyr clang tidy (#12299)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-05 09:56:11 -06:00
Jesse Hills
7fd79fdded [esp32] Change imports to use esp32 only, not .const (#12243) 2025-12-05 09:53:08 -05:00
Jesse Hills
19fa768730 Update readme logo (#12294)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-05 08:48:04 -05:00
J. Nick Koston
948a6f2134 Merge branch 'batch_cleanup' into integration 2025-12-04 22:50:56 -06:00
J. Nick Koston
5cb2128cd5 [api] Simplify MessageCreator to trivially copyable type 2025-12-04 22:50:20 -06:00
Jonathan Swoboda
ca1d17562a Merge branch 'release' into dev 2025-12-04 22:55:08 -05:00
Jonathan Swoboda
42811edeb4 Merge pull request #12293 from esphome/bump-2025.11.4
2025.11.4
2025-12-04 22:54:55 -05:00
Citizen07
22481d9c0e [remote_receiver] buffer usage fix and idle optimizations (#9999)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-04 22:50:23 -05:00
J. Nick Koston
202b580e71 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-04 21:43:05 -06:00
Jonathan Swoboda
8f20abebf6 Bump version to 2025.11.4 2025-12-04 21:52:48 -05:00
J. Nick Koston
7077488dc7 [scheduler] Fix use-after-free when cancelling timeouts from non-main-loop threads (#12288) 2025-12-04 21:52:48 -05:00
Jesse Hills
ef34239064 [CI] Trigger generic version notifier job on release (#12292) 2025-12-04 21:52:48 -05:00
Jonathan Swoboda
44148c0c6b [esp32_hosted] Fix build and bump IDF component version to 2.7.0 (#12282)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 21:52:48 -05:00
Jonathan Swoboda
1b53fcf634 [es8311] Remove MIN and MAX from mic_gain enum options (#12281)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 21:52:48 -05:00
Clyde Stubbs
b18e3d943a [config] Provide path for has_at_most_one_of messages (#12277) 2025-12-04 21:52:48 -05:00
Jonathan Swoboda
f0673f6304 [ld2420] Add missing USE_SELECT ifdefs (#12275)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 21:52:48 -05:00
Clyde Stubbs
320ba30d50 [esp32] Add build flag to suppress noexecstack message (#12272) 2025-12-04 21:52:48 -05:00
J. Nick Koston
637cb3f04a [api] Use loop-based reboot timeout check to avoid scheduler heap churn (#12291)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 19:14:35 -06:00
J. Nick Koston
80e881655f [scheduler] Fix use-after-free when cancelling timeouts from non-main-loop threads (#12288) 2025-12-04 19:14:22 -06:00
Jesse Hills
78b2ae8a35 [CI] Trigger generic version notifier job on release (#12292) 2025-12-05 14:00:08 +13:00
Jesse Hills
8caaf53ef0 [CI] Update renamed action repo (#12290) 2025-12-05 12:53:13 +13:00
J. Nick Koston
ad688a88b0 Merge branch 'back_to_loop_check_for_api_reboot' into integration 2025-12-04 17:50:45 -06:00
J. Nick Koston
501a5f8df4 Update esphome/components/api/api_server.cpp
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 17:49:49 -06:00
J. Nick Koston
2134e4eaea Merge branch 'back_to_loop_check_for_api_reboot' into integration 2025-12-04 17:08:03 -06:00
J. Nick Koston
5f2afe4b82 tweak 2025-12-04 17:04:44 -06:00
J. Nick Koston
d950d3868d fix 2025-12-04 17:01:38 -06:00
J. Nick Koston
2b54f96d67 [api] Use loop-based reboot timeout check to avoid scheduler heap churn 2025-12-04 16:58:09 -06:00
J. Nick Koston
62da4b7057 Merge branch 'scheduler_recycle_safety' into integration 2025-12-04 16:34:36 -06:00
dependabot[bot]
4db7748815 Bump ruff from 0.14.7 to 0.14.8 (#12286)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-12-04 21:53:36 +00:00
Jonathan Swoboda
0da157ab98 [tests] Bump esp32_hosted in the test code (#12289)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 21:14:30 +00:00
J. Nick Koston
3e96a86869 [scheduler] Fix use-after-free when cancelling timeouts from non-main-loop threads 2025-12-04 19:58:07 +00:00
Jonathan Swoboda
cafa275579 [esp32_hosted] Fix build and bump IDF component version to 2.7.0 (#12282)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 14:47:21 -05:00
Jonathan Swoboda
a31fb223f3 [es8311] Remove MIN and MAX from mic_gain enum options (#12281)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 10:00:45 -05:00
J. Nick Koston
f819b740dd Merge remote-tracking branch 'upstream/dev' into integration 2025-12-04 09:36:20 +00:00
Javier Peletier
37019231de [lvgl] refactor hello world to yaml file (#12274) 2025-12-04 20:18:27 +11:00
Clyde Stubbs
2af66bd6fc [config] Provide path for has_at_most_one_of messages (#12277) 2025-12-04 21:20:55 +13:00
Jonathan Swoboda
951c5377c5 [ld2420] Add missing USE_SELECT ifdefs (#12275)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-04 20:25:13 +13:00
Thomas Rupprecht
22803ef54b [esp32] Sort variants in situ (#10410)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-03 20:48:11 -05:00
Clyde Stubbs
20f82a3820 [esp32] Add build flag to suppress noexecstack message (#12272) 2025-12-03 23:49:57 +00:00
dependabot[bot]
fb331e1c5a Bump actions/stale from 10.1.0 to 10.1.1 (#12270)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-03 21:04:09 +00:00
Kevin Ahrendt
a8518d3cea [wifi, wifi_info] Add a WiFi power mode text sensor (#11480)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-04 09:18:59 +13:00
jsmarion
03aaa66f8e [cst816] Fix CST826 & CST836 (#12260)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-03 14:35:14 -05:00
J. Nick Koston
a24ba26068 [core] Improve CORE.data documentation with dataclass pattern (#12170)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-04 07:33:57 +13:00
Javier Peletier
623cdac689 [tests] Add testing of command line substitutions (#12210)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-03 12:36:35 -05:00
Jonathan Swoboda
1fbd91dc71 Merge branch 'release' into dev 2025-12-03 11:37:13 -05:00
Jonathan Swoboda
cfd88376b9 Merge pull request #12266 from esphome/bump-2025.11.3
2025.11.3
2025-12-03 11:36:57 -05:00
J. Nick Koston
b3812b5811 [text_sensor] Fix spurious raw_state deprecation warnings (#12262) 2025-12-03 16:22:06 +00:00
Jonathan Swoboda
577a6b2941 Bump version to 2025.11.3 2025-12-03 10:50:28 -05:00
Jonathan Swoboda
de68b56c4a [rtl87xx] Fix FreeRTOS version for RTL8720C boards (#12261)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:50:28 -05:00
Jonathan Swoboda
ccd23e692b [analog_threshold] Fix oscillation when using invert filter (#12251)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:50:28 -05:00
Jonathan Swoboda
1f5a44be3d [rtl87xx] Fix AsyncTCP compilation by upgrading FreeRTOS to 8.2.3 (#12230)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:50:28 -05:00
Jonathan Swoboda
1d1e47c757 [core] Fix clean all windows (#12217)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-03 10:50:28 -05:00
3fbed1fa79 [ade7953] Apply voltage_gain setting to both channels (#12180) 2025-12-03 10:50:28 -05:00
Jonathan Swoboda
5c71520635 [mopeka_pro_check] Fix negative temperatures (#12198)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 10:50:28 -05:00
J. Nick Koston
9d6c81ec23 [hlk_fm22x] Fix Action::play method signatures (#12192) 2025-12-03 10:50:28 -05:00
Clyde Stubbs
73fa9230e6 [helpers] Add conversion from FixedVector to std::vector (#12179) 2025-12-03 10:50:28 -05:00
J. Nick Koston
48caff13c9 [espnow] Initialize LwIP stack when running without WiFi component (#12169) 2025-12-03 10:50:28 -05:00
J. Nick Koston
71bb94524e [usb_uart] Wake main loop immediately when USB data arrives (#12148) 2025-12-03 10:50:28 -05:00
Clyde Stubbs
a3199792c6 [build] Don't clear pio cache unless requested (#11966) 2025-12-03 10:50:28 -05:00
lygris
87ac4baf3a [cc1101] Add new cc1101 component (#11849)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-12-03 10:42:04 -05:00
J. Nick Koston
84d4ca61a3 Merge branch 'debug-wifi-power-mode-sensor' into integration 2025-12-03 15:33:02 +00:00
Jonathan Swoboda
669bcad458 [rtl87xx] Fix FreeRTOS version for RTL8720C boards (#12261)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-03 15:31:12 +00:00
H. Árkosi Róbert
6f91c75f86 [gree] turbo, light, health, xfan switches (#12160)
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
2025-12-03 09:20:17 +00:00
J. Nick Koston
29c260858f Merge branch 'parition_callbacks' into integration 2025-12-02 22:42:13 -06:00
Kevin Ahrendt
d85d8745f6 use progmem to store strings on ESP8266s 2025-12-02 17:48:05 -05:00
Kevin Ahrendt
224866dfbb fix typo in test 2025-12-02 17:47:25 -05:00
Javier Peletier
ab60ae092d [tests] Allow substitution tests to run independently for debugging (#12224)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-12-02 16:17:24 -06:00
J. Nick Koston
4634eb3ce4 Merge upstream/dev into parition_callbacks
Resolved conflicts in text_sensor.cpp by preserving the PartitionedCallbackManager
implementation while adding back pragma directives for deprecation warnings.
2025-12-02 15:25:25 -06:00
Kevin Ahrendt
7c532ba812 remove unusued include 2025-12-02 15:12:40 -05:00
Kevin Ahrendt
2821f3041c move ifdef guard to outside if statement 2025-12-02 15:08:43 -05:00
Kevin Ahrendt
2a27a3a95a add a power save mode listener and use it for the text sensor 2025-12-02 15:01:39 -05:00
dependabot[bot]
708496c101 Bump actions/checkout from 6.0.0 to 6.0.1 (#12259)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 13:45:38 -06:00
Kevin Ahrendt
85d8a26d51 remove icon 2025-12-02 14:27:20 -05:00
Kevin Ahrendt
70fa4dc3b2 fix codegen and increase update interval 2025-12-02 14:26:24 -05:00
Kevin Ahrendt
7dfd20fb4f remove arduino test 2025-12-02 14:11:57 -05:00
Kevin Ahrendt
8ffdfc2aad move sensor to wifi_info 2025-12-02 14:06:24 -05:00
Kevin Ahrendt
3934c1563c Fix bad rebase 2025-12-02 14:03:39 -05:00
Kevin Ahrendt
8c6917fe8b only implement for esp32 2025-12-02 14:03:39 -05:00
Kevin Ahrendt
5115aeeb2b remove untested support for rp2040 and libretiny platforms 2025-12-02 14:03:38 -05:00
Kevin Ahrendt
a3677daee1 ln882x doesn't support it, so remove it 2025-12-02 14:03:38 -05:00
Kevin Ahrendt
4a84221641 Add a WiFi power mode debug text sensor 2025-12-02 14:03:38 -05:00
Jonathan Swoboda
2f75962b19 [analog_threshold] Fix oscillation when using invert filter (#12251)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-02 13:40:46 -05:00
J. Nick Koston
a6a6f482e6 [core] Add PROGMEM macros and move web_server JSON keys to flash (#12214) 2025-12-02 16:51:05 +00:00
dependabot[bot]
638c59e162 Bump pylint from 4.0.3 to 4.0.4 (#12239)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-02 10:13:20 -06:00
Flo
8f97f3b81f [wifi] Fix ap_active condition (#12227) 2025-12-02 10:12:27 -06:00
J. Nick Koston
6ce2a45691 [text_sensor] Add deprecation warning for raw_state member access (#12246) 2025-12-02 10:03:58 -06:00
J. Nick Koston
77477bd330 [web_server_idf] Fix SSE multi-line message formatting (#12247) 2025-12-02 10:03:29 -06:00
J. Nick Koston
3f08cacf71 [valve] Store valve state strings in flash on ESP8266 (#12202) 2025-12-02 10:02:51 -06:00
J. Nick Koston
d1583456e9 [web_server] Store update state strings in flash on ESP8266 (#12204) 2025-12-02 10:02:29 -06:00
J. Nick Koston
101103c666 [core] Add RAM strings and symbols analysis to analyze-memory command (#12161) 2025-12-02 10:02:09 -06:00
J. Nick Koston
5142ff372b [light] Use listener pattern for state callbacks with lazy allocation (#12166) 2025-12-02 10:01:54 -06:00
J. Nick Koston
f9ad832e7b [esp32_camera] Replace std::function callbacks with CameraListener interface (#12165)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-12-02 09:59:32 -06:00
J. Nick Koston
deda7a1bf3 [lock] Store lock state strings in flash on ESP8266 (#12163) 2025-12-02 09:59:05 -06:00
Jonathan Swoboda
29be1423f5 [core] Filter noisy platformio log messages (#12218)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-02 08:59:50 -05:00
J. Nick Koston
347dcdc018 Merge branch 'give_six_months_for_text_sensor_raw_state' into integration 2025-12-01 23:37:09 -06:00
J. Nick Koston
754f320382 Merge branch 'web_server_idf_fix_sse_line_breaks' into integration 2025-12-01 23:35:57 -06:00
J. Nick Koston
4b83401835 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-01 23:35:45 -06:00
J. Nick Koston
7ad63849f0 [web_server_idf] Fix SSE multi-line message formatting 2025-12-01 23:31:13 -06:00
J. Nick Koston
9f5e04c3d3 [text_sensor] Add deprecation warning for raw_state member access 2025-12-01 22:36:03 -06:00
J. Nick Koston
10ddebc737 [text_sensor] Avoid duplicate string storage when no filters configured (#12205) 2025-12-01 22:17:31 -06:00
dependabot[bot]
9a0731437a Bump aioesphomeapi from 42.9.0 to 42.10.0 (#12245)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 22:11:33 -06:00
J. Nick Koston
82a06c697e [esp32] Place ring buffer functions in flash by default (prep for IDF 6.0) (#12184) 2025-12-02 03:57:41 +00:00
dependabot[bot]
c45cd44bb8 Bump github/codeql-action from 4.31.5 to 4.31.6 (#12234)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-01 21:49:25 -06:00
Jonathan Swoboda
2903a4aa92 [ota] Use ESP-IDF OTA backend for all ESP32 builds (#12244)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-02 03:41:34 +00:00
J. Nick Koston
6943803176 [cover] Store cover state strings in flash on ESP8266 (#12196) 2025-12-01 21:26:13 -06:00
J. Nick Koston
6dafc5137e [esp32] Place FreeRTOS functions in flash by default (prep for IDF 6.0) (#12182) 2025-12-01 21:24:08 -06:00
J. Nick Koston
f34e464ccb Merge remote-tracking branch 'swoboda1337/ota-use-idf-backend-for-all-esp32' into integration 2025-12-01 21:05:48 -06:00
J. Nick Koston
e19529cccc Merge branch 'dev' into ota-use-idf-backend-for-all-esp32 2025-12-01 21:05:33 -06:00
J. Nick Koston
db70f8117d Merge remote-tracking branch 'upstream/dev' into integration 2025-12-01 20:58:37 -06:00
Jonathan Swoboda
9bdff288d1 [ota] Use ESP-IDF OTA backend for all ESP32 builds
Remove the Arduino-specific ESP32 OTA backend and use the ESP-IDF
backend for both Arduino and ESP-IDF framework builds on ESP32.

Since Arduino-ESP32 is built on top of ESP-IDF, the ESP-IDF OTA APIs
(esp_ota_begin, esp_ota_write, esp_ota_end, etc.) are available
regardless of which framework is used.

This simplifies the codebase by removing ~100 lines of duplicate code
and ensures consistent OTA behavior across all ESP32 builds.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 20:45:46 -05:00
Djordje Mandic
df58e832e5 [esp8266] Allow IN&OUT pin config for ESP8266 (#12238) 2025-12-01 15:44:33 -08:00
Peter Popovec
e42cf9a4f4 [mqtt] Enable support for the RTL87XX platform (#7697)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
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-01 23:06:47 +00:00
J. Nick Koston
96f28f0ab4 [button] Convert to C++17 nested namespace style (#12233)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2025-12-01 17:50:29 -05:00
J. Nick Koston
d332edfaca [datetime] Convert to C++17 nested namespace style (#12235) 2025-12-01 17:50:03 -05:00
J. Nick Koston
0e8e0ca9a8 Merge branch 'action_response_error_ref' into integration 2025-12-01 16:29:34 -06:00
J. Nick Koston
73f3cf9703 [api] Use StringRef for ActionResponse error message to avoid copy 2025-12-01 16:25:06 -06:00
Keith Burzinski
d4bd282bb4 [helpers] Fix unit tests following #12135 (#12237) 2025-12-01 22:08:49 +00:00
J. Nick Koston
a3a6b77cd0 Merge branch 'button_cpp17' into integration 2025-12-01 15:16:17 -06:00
J. Nick Koston
e1f9f68421 Merge branch 'datetime_cpp17' into integration 2025-12-01 15:16:08 -06:00
J. Nick Koston
76d540d6a6 [datetime] Convert to C++17 nested namespace style 2025-12-01 15:09:52 -06:00
J. Nick Koston
0fd878d3c4 [button] Convert to C++17 nested namespace style 2025-12-01 15:06:43 -06:00
Jonathan Swoboda
78df884bb5 [rtl87xx] Fix AsyncTCP compilation by upgrading FreeRTOS to 8.2.3 (#12230)
Co-authored-by: Claude <noreply@anthropic.com>
2025-12-01 16:03:00 -05:00
J. Nick Koston
a09481a352 Merge remote-tracking branch 'upstream/dev' into integration 2025-12-01 14:52:51 -06:00
Keith Burzinski
52fe3de78f [zwave_proxy] Use new socket wake infrastructure to reduce latency, convert to C++17 namespace style (#12135)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-01 14:27:20 -06:00
Keith Burzinski
6a79ce8eff [uart] Automatically enable the socket wake infrastructure when RX wake requested (#12221) 2025-12-01 14:16:39 -06:00
Jonathan Swoboda
2b7695ba3f [core] Fix clean all windows (#12217)
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-12-01 12:40:56 -05:00
Juri Berlanda
6d336676a2 [remote_transmitter, remote_receiver] Add RP2040 support (#12048)
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-01 12:09:58 -05:00
Robert Resch
b322622ef1 [micronova] Convert to C++17 namespace style (#12229) 2025-12-01 10:47:00 -05:00
J. Nick Koston
065c1bfc6a [core] Fix status_momentary API misuse and optimize parameter type (#12216) 2025-12-01 08:34:07 -06:00
Keith Burzinski
664881bc13 [uart] Convert to C++17 namespace style (#12220) 2025-12-01 07:57:18 -05:00
Keith Burzinski
dbc16ce468 [wifi_info] Fix compilation error when using only mac_address sensor, add tests (#12222) 2025-12-01 02:48:47 -06:00
Keith Burzinski
161a18b326 [uart] Add wake_loop_on_rx flag for low latency processing (#12172)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-12-01 00:33:23 -06:00
J. Nick Koston
8e8b2f3a9c Merge branch 'comment_comp_time' into integration 2025-12-01 00:26:04 -06:00
J. Nick Koston
ae6c123784 cleaner 2025-11-30 23:40:25 -06:00
J. Nick Koston
8c828884c0 Merge branch 'comment_comp_time' into integration 2025-11-30 22:51:39 -06:00
J. Nick Koston
edf19b8dd4 [core] Use StringRef for get_comment and get_compilation_time to avoid allocations 2025-11-30 22:49:23 -06:00
J. Nick Koston
b5a3c0be21 [core] Use StringRef for get_comment and get_compilation_time to avoid allocations 2025-11-30 22:47:40 -06:00
J. Nick Koston
de6b20d495 [core] Use StringRef for get_comment and get_compilation_time to avoid allocations 2025-11-30 22:44:30 -06:00
J. Nick Koston
4dbe0dab51 [core] Use StringRef for get_comment and get_compilation_time to avoid allocations 2025-11-30 22:42:20 -06:00
Jonathan Swoboda
4335fcdb72 [psram] Add C5 support (#12215)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-30 23:27:10 -05:00
J. Nick Koston
5996ae4dc5 Merge branch 'moment_api_misuse_fix' into integration 2025-11-30 22:02:10 -06:00
J. Nick Koston
d9a8bb9774 [core] Fix status_momentary API misuse and optimize parameter type 2025-11-30 21:56:22 -06:00
bf4ef36c3a [ade7953] Apply voltage_gain setting to both channels (#12180) 2025-11-30 19:17:50 -05:00
J. Nick Koston
cbc03fc342 Merge branch 'web_server_keys_progmem' into integration 2025-11-30 17:53:43 -06:00
J. Nick Koston
675b5d4501 merge 2025-11-30 17:51:23 -06:00
J. Nick Koston
1e38d0445e Merge branch 'web_server_keys_progmem' into integration
# Conflicts:
#	esphome/components/web_server/web_server.cpp
2025-11-30 17:47:55 -06:00
J. Nick Koston
2ac9f44377 store web_server keys in progmem 2025-11-30 17:39:37 -06:00
J. Nick Koston
2ca118f371 [web_server] Replace routing table with if-else chain to save 116 bytes RAM (#12139) 2025-12-01 12:25:46 +13:00
J. Nick Koston
7b541e3d80 Merge branch 'integration' into memory_api 2025-11-30 17:19:49 -06:00
J. Nick Koston
eebfa6584c Merge branch 'text_sensor_dupe_storage' into integration 2025-11-30 17:19:43 -06:00
J. Nick Koston
e8f6f86a02 cover 2025-11-30 17:17:15 -06:00
J. Nick Koston
c23e5c5c03 Merge branch 'integration' into memory_api 2025-11-30 17:10:36 -06:00
J. Nick Koston
fbf2ee9d39 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-30 17:10:30 -06:00
J. Nick Koston
82e1238330 [lock] Refactor trigger classes to template and add integration tests (#12193) 2025-11-30 17:09:02 -06:00
Jimmy Hedman
8308bc2911 [mdns] Bump mDNS component to 1.9.1 (#12207) 2025-11-30 08:06:06 -05:00
Jonathan Swoboda
47c767fa5e [openthread] Add C5 support (#12200) 2025-11-30 08:04:45 -05:00
Jonathan Swoboda
e95ceafc17 [mopeka_pro_check] Fix negative temperatures (#12198)
Co-authored-by: Claude <noreply@anthropic.com>
2025-11-30 08:04:33 -05:00
Jonathan Swoboda
7317bf4a5d [esp32_can] Add P4 support (#12201) 2025-11-30 08:04:19 -05:00
J. Nick Koston
4762f9a52a Merge branch 'integration' into memory_api 2025-11-29 23:38:36 -06:00
J. Nick Koston
858b0c0957 Merge branch 'text_sensor_dupe_storage' into integration 2025-11-29 23:38:05 -06:00
J. Nick Koston
4b16a4bca2 merge 2025-11-29 23:35:05 -06:00
J. Nick Koston
3cc9411d5a Merge branch 'text_sensor_dupe_storage' into integration 2025-11-29 23:32:51 -06:00
J. Nick Koston
b4e6c38d65 [text_sensor] Avoid duplicate string storage when no filters configured 2025-11-29 23:30:01 -06:00
J. Nick Koston
62d144932b Merge branch 'integration' into memory_api 2025-11-29 23:06:14 -06:00
J. Nick Koston
159580d56a Merge branch 'update_state_strings_flash' into integration 2025-11-29 23:05:51 -06:00
J. Nick Koston
7699928339 Merge branch 'valve_state_strings_flash' into integration 2025-11-29 23:05:47 -06:00
J. Nick Koston
0219125397 Merge branch 'integration' of https://github.com/esphome/esphome into integration 2025-11-29 23:05:41 -06:00
J. Nick Koston
278f3e2914 [web_server] Store update state strings in flash on ESP8266 2025-11-29 23:04:57 -06:00
J. Nick Koston
87ab10b8dc [valve] Store valve state strings in flash on ESP8266 2025-11-29 22:44:01 -06:00
J. Nick Koston
042a08887f [climate] Use C++17 nested namespace syntax (#12194) 2025-11-30 00:54:49 +00:00
J. Nick Koston
8f8828d5b8 Merge branch 'integration' into memory_api 2025-11-29 18:36:33 -06:00
J. Nick Koston
d5139ff0e7 Merge remote-tracking branch 'origin/cover_state_strings_flash' into integration 2025-11-29 18:36:21 -06:00
J. Nick Koston
77f5f2326f [hlk_fm22x] Fix Action::play method signatures (#12192) 2025-11-29 19:36:12 -05:00
J. Nick Koston
b14a1b3fd4 Merge branch 'climate_nested_namespace' into integration 2025-11-29 18:35:55 -06:00
J. Nick Koston
a54a0e54b2 [cover] Store cover state strings in flash on ESP8266 2025-11-29 18:34:50 -06:00
J. Nick Koston
24f34cf782 [climate] Use C++17 nested namespace syntax 2025-11-29 18:29:46 -06:00
J. Nick Koston
415c56e324 Merge branch 'integration' into memory_api 2025-11-29 18:21:24 -06:00
J. Nick Koston
428ee718a9 Merge remote-tracking branch 'origin/hlk_fm22x_signatures' into integration 2025-11-29 18:21:18 -06:00
J. Nick Koston
ffdc391c7b Merge branch 'lock_cleanups' into integration 2025-11-29 18:21:00 -06:00
J. Nick Koston
a80435af0f [lock] Refactor trigger classes to template and add integration tests 2025-11-29 18:20:18 -06:00
J. Nick Koston
0dc6c6f563 [hlk_fm22x] Fix Action::play method signatures 2025-11-29 18:19:00 -06:00
d82a92b406 [ade7953_base] Add missing CODEOWNERS (#12181) 2025-11-29 18:41:47 -05:00
J. Nick Koston
7d7e0f98f6 Merge branch 'integration' into memory_api 2025-11-29 17:09:57 -06:00
J. Nick Koston
544a70253f Merge remote-tracking branch 'upstream/dev' into integration 2025-11-29 17:09:52 -06:00
dependabot[bot]
ec88bf0cb1 Bump ruff from 0.14.5 to 0.14.7 (#12190)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-11-29 22:56:26 +00:00
dependabot[bot]
46567c4716 Bump aioesphomeapi from 42.8.0 to 42.9.0 (#12189)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-29 22:55:27 +00:00
Jakub Čermák
1f47797007 Add MEASUREMENT_ANGLE to SensorStateClass (#12085) 2025-11-29 16:26:25 -06:00
J. Nick Koston
9ec2733b09 Merge branch 'integration' into memory_api 2025-11-29 03:26:08 -06:00
J. Nick Koston
e24407344e Merge branch 'prepare_idf_6_rtos_ring_buf_flash' into integration 2025-11-29 03:26:02 -06:00
J. Nick Koston
b44abfce57 [esp32] Place ring buffer functions in flash by default (prep for IDF 6.0) 2025-11-29 03:18:39 -06:00
J. Nick Koston
22de35b202 [esp32] Place ring buffer functions in flash by default (prep for IDF 6.0) 2025-11-29 03:17:08 -06:00
J. Nick Koston
75b72a08f2 Merge branch 'integration' into memory_api 2025-11-29 02:46:18 -06:00
J. Nick Koston
5938d85cb0 Merge branch 'prepare_idf_6_rtos_funcs_flash' into integration 2025-11-29 02:46:11 -06:00
J. Nick Koston
e7c54598cd tweak 2025-11-29 02:44:27 -06:00
Javier Peletier
cf444fc3b8 [mipi_spi] add guition JC4827W543 C/R (#12034) 2025-11-29 19:40:13 +11:00
Clyde Stubbs
c40e8e7f5c [helpers] Add conversion from FixedVector to std::vector (#12179) 2025-11-29 19:38:29 +11:00
J. Nick Koston
64281631a1 [esp32] Place FreeRTOS functions in flash by default (prep for IDF 6.0) 2025-11-29 02:32:40 -06:00
J. Nick Koston
b71d8010d2 [light] Store log_percent parameter strings in flash on ESP8266 (#12174) 2025-11-28 22:59:31 -05:00
J. Nick Koston
2174795b27 [number] Reduce NumberCall size by 4 bytes on 32-bit platforms (#12178)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 22:57:36 -05:00
J. Nick Koston
5fa4ff754c [ble_client] Convert to C++17 namespace style (#12176) 2025-11-28 22:57:01 -05:00
J. Nick Koston
29334b3584 Merge branch 'integration' into memory_api 2025-11-28 21:23:41 -06:00
J. Nick Koston
584902fa94 Merge branch 'number_reorder_reduce' into integration 2025-11-28 21:23:34 -06:00
J. Nick Koston
e851493080 Update esphome/components/number/number_call.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 21:20:42 -06:00
J. Nick Koston
3dce0587cf Merge branch 'integration' into memory_api 2025-11-28 21:20:07 -06:00
J. Nick Koston
835f7198e4 Merge branch 'speed_count_255' into integration 2025-11-28 21:19:58 -06:00
J. Nick Koston
a30786b055 clamp 2025-11-28 21:19:47 -06:00
J. Nick Koston
76a596d3b5 Merge branch 'integration' into memory_api 2025-11-28 21:15:46 -06:00
J. Nick Koston
260e8bdd75 Merge branch 'number_reorder_reduce' into integration 2025-11-28 21:15:39 -06:00
J. Nick Koston
4e379ab235 [number] Reduce NumberCall size by 4 bytes on 32-bit platforms 2025-11-28 21:15:09 -06:00
J. Nick Koston
9e7086c11e Merge branch 'integration' into memory_api 2025-11-28 21:08:02 -06:00
J. Nick Koston
e983a19160 Merge branch 'speed_count_255' into integration 2025-11-28 21:07:53 -06:00
J. Nick Koston
192abf95ce [fan] Use uint8_t for speed_count and fix tuya max=256 validation bug 2025-11-28 21:07:02 -06:00
J. Nick Koston
28faecfc26 Merge branch 'integration' into memory_api 2025-11-28 20:53:47 -06:00
J. Nick Koston
8e6a4e94db Merge branch 'ble_client_ns' into integration 2025-11-28 20:53:39 -06:00
J. Nick Koston
1aaea4d3ab [ble_client] Convert to C++17 namespace style 2025-11-28 20:52:31 -06:00
J. Nick Koston
1120236f06 Revert "[api] Use shared static string for reboot timeout scheduler name"
This reverts commit bd958c5859.
2025-11-28 19:32:17 -06:00
J. Nick Koston
0bb79afa1f Revert "[api] Use shared static string for reboot timeout scheduler name"
This reverts commit bd958c5859.
2025-11-28 19:32:06 -06:00
J. Nick Koston
adbab2c288 Merge branch 'integration' into memory_api 2025-11-28 19:28:02 -06:00
J. Nick Koston
92131f2542 Merge branch 'reboot_timeout_cleanup' into integration 2025-11-28 19:27:54 -06:00
J. Nick Koston
bd958c5859 [api] Use shared static string for reboot timeout scheduler name 2025-11-28 19:27:21 -06:00
J. Nick Koston
f1dcd478bb Merge branch 'integration' into memory_api 2025-11-28 19:06:36 -06:00
J. Nick Koston
3d5987b701 Merge branch 'light_call_strings_flash' into integration 2025-11-28 19:06:28 -06:00
J. Nick Koston
23a177f9d7 [light] Store log_percent parameter strings in flash on ESP8266 2025-11-28 19:05:52 -06:00
J. Nick Koston
e6ea164a75 Merge branch 'integration' into memory_api 2025-11-28 18:55:13 -06:00
J. Nick Koston
d8e95a835f Merge branch 'esp8266_device_info_flash' into integration 2025-11-28 18:54:56 -06:00
J. Nick Koston
7f7ccd6c9c [api] Store device info strings in flash on ESP8266 2025-11-28 18:53:19 -06:00
J. Nick Koston
8a90fa302e Merge branch 'integration' into memory_api 2025-11-28 16:57:14 -06:00
J. Nick Koston
83dd53954b Merge branch 'alarm_control_panel_reduce_complexity' into integration 2025-11-28 16:57:04 -06:00
J. Nick Koston
ff8dbac54e Merge branch 'camera_listen' into integration 2025-11-28 16:57:00 -06:00
J. Nick Koston
b872d10583 simplify 2025-11-28 16:52:46 -06:00
J. Nick Koston
c7e8a3eea5 reduce 2025-11-28 16:43:22 -06:00
J. Nick Koston
913581e7ee reduce 2025-11-28 16:42:03 -06:00
J. Nick Koston
4ab1911d82 reduce 2025-11-28 16:40:27 -06:00
J. Nick Koston
d3918dc784 reduce 2025-11-28 16:39:05 -06:00
J. Nick Koston
2060ed0a92 tests 2025-11-28 16:32:28 -06:00
J. Nick Koston
3c1c19da1c tweaks 2025-11-28 16:23:31 -06:00
J. Nick Koston
bc50be6053 [logger] Conditionally compile log level change listener (#12168)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 22:14:00 +00:00
J. Nick Koston
e8bc19a07d [alarm_control_panel] Replace callbacks with listener interface 2025-11-28 16:11:23 -06:00
J. Nick Koston
ca599b25c2 [espnow] Initialize LwIP stack when running without WiFi component (#12169) 2025-11-28 16:33:28 -05:00
J. Nick Koston
22a60ec789 Merge branch 'integration' into memory_api 2025-11-28 14:49:29 -06:00
J. Nick Koston
9e7d6d7702 Merge branch 'logger_level_only_one_place' into integration 2025-11-28 14:49:24 -06:00
J. Nick Koston
3c7d48a5ef Merge branch 'dev' into logger_level_only_one_place 2025-11-28 14:49:06 -06:00
J. Nick Koston
200c0c77c7 Update esphome/components/logger/logger.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 14:48:52 -06:00
J. Nick Koston
2e55296640 [sensor] Replace timeout filter scheduler with loop-based implementation (#11922) 2025-11-28 20:43:11 +00:00
J. Nick Koston
6b756b81f3 Merge branch 'integration' into memory_api 2025-11-28 14:33:33 -06:00
J. Nick Koston
a01eeaa796 Merge branch 'logger_level_only_one_place' into integration 2025-11-28 14:33:26 -06:00
J. Nick Koston
ed0751246a [logger] Conditionally compile log level change listener 2025-11-28 14:28:02 -06:00
J. Nick Koston
63842b3795 Merge branch 'integration' into memory_api 2025-11-28 14:14:40 -06:00
J. Nick Koston
dc1b2d7a4b Merge branch 'ota_listeners' into integration 2025-11-28 14:14:31 -06:00
J. Nick Koston
e3dc9a715f tweak 2025-11-28 14:14:03 -06:00
J. Nick Koston
b1a318c0d7 simplify, no more register needed 2025-11-28 14:07:55 -06:00
J. Nick Koston
a45a2e8f5f guards 2025-11-28 14:01:37 -06:00
J. Nick Koston
ee91bb2405 dry 2025-11-28 13:54:46 -06:00
J. Nick Koston
ab6b4c77d2 dry 2025-11-28 13:52:58 -06:00
J. Nick Koston
d9701af9c1 dry 2025-11-28 13:51:21 -06:00
J. Nick Koston
a224d0acbd dry 2025-11-28 13:50:20 -06:00
J. Nick Koston
515cdf9b9f its always on 2025-11-28 13:48:19 -06:00
J. Nick Koston
8fe981b9f1 [ota] Replace std::function callbacks with listener interface 2025-11-28 13:46:00 -06:00
J. Nick Koston
f678686cde Merge branch 'integration' into memory_api 2025-11-28 13:02:54 -06:00
J. Nick Koston
8fe3717665 Merge branch 'timeout_filter_scheduler_churn_fix' into integration 2025-11-28 13:02:47 -06:00
J. Nick Koston
cc40f08574 use TimeoutFilterBase 2025-11-28 13:02:37 -06:00
J. Nick Koston
01f58e8662 Merge branch 'integration' into memory_api 2025-11-28 12:57:28 -06:00
J. Nick Koston
a8cd2d6728 Merge branch 'timeout_filter_scheduler_churn_fix' into integration 2025-11-28 12:57:24 -06:00
J. Nick Koston
087ed48dba cleanups per review 2025-11-28 12:56:13 -06:00
J. Nick Koston
30ee14813f cover 2025-11-28 12:48:41 -06:00
J. Nick Koston
9fa9ff6200 Merge branch 'integration' into memory_api 2025-11-28 12:38:33 -06:00
J. Nick Koston
695f2c949d Merge branch 'light_lazy_callbacks' into integration 2025-11-28 12:38:28 -06:00
J. Nick Koston
149f5e59ec [light] Use listener pattern for state callbacks with lazy allocation 2025-11-28 12:36:40 -06:00
J. Nick Koston
dcce2e3fbd Merge branch 'integration' into memory_api 2025-11-28 12:25:45 -06:00
J. Nick Koston
0229c200bc Merge branch 'camera_listen' into integration 2025-11-28 12:25:39 -06:00
Javier Peletier
d6ca01775e [packages] Restore remote shorthand vars and !remove in early package contents validation (#12158)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-28 18:24:09 +00:00
J. Nick Koston
13626680ca Merge branch 'integration' into memory_api 2025-11-28 12:22:27 -06:00
J. Nick Koston
6e0336c3cd Merge remote-tracking branch 'upstream/dev' into integration 2025-11-28 12:22:19 -06:00
Javier Peletier
e15f3a08ae [tests] Remote packages with substitutions (#12145) 2025-11-28 12:15:55 -06:00
J. Nick Koston
d43189cb07 Update esphome/components/camera/camera.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-28 12:14:19 -06:00
J. Nick Koston
fb82362e9c [api] Eliminate rx_buf heap churn and release buffers after initial sync (#12133) 2025-11-28 12:13:29 -06:00
J. Nick Koston
f1d8281489 [esp32_camera] Replace std::function callbacks with CameraListener interface 2025-11-28 12:05:41 -06:00
J. Nick Koston
26e979d3d5 [wifi] Replace std::function callbacks with listener interfaces (#12155) 2025-11-28 11:27:17 -06:00
J. Nick Koston
60ffa0e52e [esp32_ble_tracker] Replace scanner state callback with listener interface (#12156) 2025-11-28 11:27:08 -06:00
J. Nick Koston
0df9c2372c Merge branch 'integration' into memory_api 2025-11-28 10:30:48 -06:00
J. Nick Koston
7cc7883b17 Merge branch 'lock_state_store_progmem_esp8266' into integration 2025-11-28 10:30:43 -06:00
J. Nick Koston
2a67933062 small cleanups 2025-11-28 10:30:33 -06:00
J. Nick Koston
a212161f68 cleanup 2025-11-28 10:30:12 -06:00
J. Nick Koston
a57accc52e Merge branch 'integration' into memory_api 2025-11-28 10:13:39 -06:00
J. Nick Koston
345c0124a1 Merge branch 'lock_state_store_progmem_esp8266' into integration 2025-11-28 10:13:34 -06:00
J. Nick Koston
632af6bda3 [lock] Store lock state strings in flash on ESP8266 2025-11-28 10:13:03 -06:00
J. Nick Koston
b0c099c26e Merge branch 'integration' into memory_api 2025-11-28 09:58:42 -06:00
J. Nick Koston
9489021ea5 Merge branch 'analyze_memory_include_ram' into integration 2025-11-28 09:58:31 -06:00
J. Nick Koston
cd11f31887 address bot review 2025-11-28 09:57:34 -06:00
J. Nick Koston
e22d78cf4c tweaks 2025-11-28 09:47:25 -06:00
J. Nick Koston
eea02a5f0b ram 2025-11-28 09:44:29 -06:00
J. Nick Koston
3c854a02d7 add ram 2025-11-28 09:39:32 -06:00
J. Nick Koston
44127eec59 Merge branch 'integration' into memory_api 2025-11-27 22:43:40 -06:00
J. Nick Koston
775748f689 Merge branch 'bluetooth_scanner_state_listen' into integration 2025-11-27 22:43:33 -06:00
J. Nick Koston
e3ea585d54 [esp32_ble_tracker] Replace scanner state callback with listener interface 2025-11-27 22:42:21 -06:00
J. Nick Koston
b13369ab96 Merge branch 'integration' into memory_api 2025-11-27 22:29:45 -06:00
J. Nick Koston
6aee023eb3 Merge branch 'wifi_listener' into integration 2025-11-27 22:29:36 -06:00
J. Nick Koston
3752d5d2ab tweaks 2025-11-27 22:28:43 -06:00
J. Nick Koston
3a27a4d34e Merge branch 'integration' into memory_api 2025-11-27 22:18:35 -06:00
J. Nick Koston
4e96c17c42 Merge branch 'wifi_listener' into integration 2025-11-27 22:18:29 -06:00
J. Nick Koston
c9bb9c4d24 [wifi] Replace std::function callbacks with listener interfaces 2025-11-27 22:17:56 -06:00
J. Nick Koston
e1ec6146c0 [wifi] Save 112 bytes BSS on ESP8266 by calling SDK directly for BSSID (#12137)
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>
2025-11-27 22:09:41 -06:00
J. Nick Koston
450065fdae [light] Replace sparse enum switch with linear search to save 156 bytes RAM (#12140) 2025-11-27 22:09:27 -06:00
J. Nick Koston
3c0241d013 Merge branch 'integration' into memory_api 2025-11-27 22:06:03 -06:00
J. Nick Koston
5a19ff4a89 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-27 22:05:48 -06:00
J. Nick Koston
71dc402a30 [logger] Replace std::function callbacks with LogListener interface (#12153) 2025-11-28 04:00:33 +00:00
J. Nick Koston
f448a21df6 Merge branch 'integration' into memory_api 2025-11-27 20:54:11 -06:00
J. Nick Koston
4b0882ac76 Merge branch 'log_listener' into integration 2025-11-27 20:54:04 -06:00
J. Nick Koston
5c6d60ca2e unused param 2025-11-27 20:53:49 -06:00
J. Nick Koston
200491f9ce Merge branch 'integration' into memory_api 2025-11-27 20:03:54 -06:00
J. Nick Koston
8c4d886b4a Merge branch 'log_listener' into integration 2025-11-27 20:03:47 -06:00
J. Nick Koston
c1b12791c6 [logger] Replace std::function callbacks with LogListener interface 2025-11-27 20:02:31 -06:00
J. Nick Koston
eb2aa62d0d [logger] Replace std::function callbacks with LogListener interface 2025-11-27 20:01:15 -06:00
J. Nick Koston
9d191a61fe Merge branch 'integration' into memory_api 2025-11-27 18:42:29 -06:00
J. Nick Koston
483a8dd4c5 Merge branch 'ha_service_storage_strings_rodata' into integration 2025-11-27 18:42:20 -06:00
J. Nick Koston
9bc65c15be Merge remote-tracking branch 'origin/ha_service_storage_strings_rodata' into ha_service_storage_strings_rodata 2025-11-27 18:41:50 -06:00
J. Nick Koston
f94e4a30ac safer 2025-11-27 18:41:36 -06:00
J. Nick Koston
73990a8d45 Merge branch 'integration' into memory_api 2025-11-27 18:29:34 -06:00
J. Nick Koston
294cedc730 Merge remote-tracking branch 'origin/ha_service_storage_strings_rodata' into integration 2025-11-27 18:29:17 -06:00
J. Nick Koston
dbc2078b2e assert 2025-11-27 18:27:27 -06:00
J. Nick Koston
bb67f5a048 Merge branch 'integration' into memory_api 2025-11-27 18:20:20 -06:00
J. Nick Koston
14ca2d889d Merge branch 'ha_service_storage_strings_rodata' into integration 2025-11-27 18:20:15 -06:00
J. Nick Koston
09151e6814 [api] Reduce heap usage for Home Assistant service call string storage 2025-11-27 18:16:56 -06:00
J. Nick Koston
4fa6d04861 Merge branch 'integration' into memory_api 2025-11-27 17:42:57 -06:00
J. Nick Koston
4cdec33c85 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-27 17:42:50 -06:00
Jonathan Swoboda
9bd148dfd1 Merge branch 'release' into dev 2025-11-27 18:19:20 -05:00
Jonathan Swoboda
50c1720c16 Merge pull request #12149 from esphome/bump-2025.11.2
2025.11.2
2025-11-27 18:19:05 -05:00
J. Nick Koston
4c549798bc [usb_uart] Wake main loop immediately when USB data arrives (#12148) 2025-11-27 16:33:08 -06:00
J. Nick Koston
a9d804cfbb Merge branch 'integration' into memory_api 2025-11-27 16:26:23 -06:00
J. Nick Koston
178b83c7f8 Merge branch 'usb_uart_wake' into integration 2025-11-27 16:26:17 -06:00
Jonathan Swoboda
4115dd7222 Bump version to 2025.11.2 2025-11-27 17:23:28 -05:00
J. Nick Koston
25e3d5bf91 [usb_uart] Wake main loop immediately when USB data arrives 2025-11-27 16:23:28 -06:00
J. Nick Koston
d5e2543751 [scheduler] Fix use-after-move crash in heap operations (#12124) 2025-11-27 17:23:28 -05:00
Clyde Stubbs
b4b34aee13 [wifi] Restore blocking setup until connected for RP2040 (#12142) 2025-11-27 17:23:28 -05:00
Jonathan Swoboda
6645994700 [esp32] Fix hosted update when there is no wifi (#12123) 2025-11-27 17:23:28 -05:00
Clyde Stubbs
ae140f52e3 [lvgl] Fix position of errors in widget config (#12111)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-27 17:23:28 -05:00
Clyde Stubbs
46ae6d35a2 [lvgl] Allow multiple widgets per grid cell (#12091) 2025-11-27 17:23:27 -05:00
J. Nick Koston
278f12fb99 [script] Fix script.wait hanging when triggered from on_boot (#12102) 2025-11-27 17:23:27 -05:00
Jonathan Swoboda
acdcd56395 [esp32] Fix platformio flash size print (#12099)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-27 17:23:27 -05:00
Edward Firmo
9289fc36f7 [nextion] Do not set alternative baud rate when not specified or <= 0 (#12097) 2025-11-27 17:23:27 -05:00
J. Nick Koston
1fadd1227d [scheduler] Fix use-after-move crash in heap operations (#12124) 2025-11-27 10:50:21 -06:00
Clyde Stubbs
91df0548ef [wifi] Restore blocking setup until connected for RP2040 (#12142) 2025-11-27 10:30:03 -05:00
J. Nick Koston
09cd056a3c Merge branch 'integration' into memory_api 2025-11-26 22:58:23 -06:00
J. Nick Koston
d93987f61a Merge branch 'light_sparse_table' into integration 2025-11-26 22:58:08 -06:00
J. Nick Koston
ca20a877bf Merge branch 'integration' into memory_api 2025-11-26 22:57:59 -06:00
J. Nick Koston
88ef4359b3 Merge branch 'webserver_reduce_ram' into integration 2025-11-26 22:57:44 -06:00
J. Nick Koston
75b4401cd4 disable tidy 2025-11-26 22:57:17 -06:00
J. Nick Koston
22eea92534 [light] Replace sparse enum switch with linear search to save 156 bytes RAM 2025-11-26 22:54:45 -06:00
J. Nick Koston
b6f589710d Merge branch 'integration' into memory_api 2025-11-26 22:47:17 -06:00
J. Nick Koston
da1e31ba0e Merge branch 'webserver_reduce_ram' into integration 2025-11-26 22:47:00 -06:00
J. Nick Koston
91ff949399 [web_server] Replace routing table with if-else chain to save 116 bytes RAM 2025-11-26 22:45:51 -06:00
J. Nick Koston
1a1bfd021a Merge branch 'integration' into memory_api 2025-11-26 22:18:57 -06:00
J. Nick Koston
ec151b477a Merge branch 'wifi_sta_8266' into integration 2025-11-26 22:18:41 -06:00
J. Nick Koston
8ecd40608b [wifi] Save 112 bytes BSS on ESP8266 by calling SDK directly for BSSID 2025-11-26 22:18:13 -06:00
J. Nick Koston
60d4b8da92 Merge branch 'integration' into memory_api 2025-11-26 21:52:24 -06:00
J. Nick Koston
2cd2c15911 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-26 21:52:13 -06:00
Jonathan Swoboda
a7a5a0b9a2 [esp32] Improve IDF component support (#12127) 2025-11-26 22:46:17 -05:00
Jonathan Swoboda
9c85ec9182 [esp32] Fix hosted update when there is no wifi (#12123) 2025-11-26 20:01:35 -05:00
J. Nick Koston
4a7bdd4388 Merge branch 'integration' into memory_api 2025-11-26 18:59:52 -06:00
J. Nick Koston
7e53f96c4c Merge branch 'buffer_churn_init_sync' into integration 2025-11-26 18:59:47 -06:00
J. Nick Koston
406fa220f5 logs! 2025-11-26 18:59:11 -06:00
J. Nick Koston
31a9558445 Merge branch 'integration' into memory_api 2025-11-26 18:22:37 -06:00
J. Nick Koston
747341efa4 Merge branch 'buffer_churn_init_sync' into integration 2025-11-26 18:22:33 -06:00
J. Nick Koston
bbf7e8c1f2 [api] Eliminate rx_buf heap churn and release buffers after initial sync 2025-11-26 18:17:25 -06:00
J. Nick Koston
a42a84b9c3 Merge branch 'integration' into memory_api 2025-11-26 17:09:04 -06:00
J. Nick Koston
c81945e9be Merge remote-tracking branch 'upstream/dev' into integration 2025-11-26 17:08:54 -06:00
Jesse Hills
23e58c1c7b [inkplate] Ignore strapping pin warnings on default pins (#12110) 2025-11-26 17:08:40 -06:00
J. Nick Koston
5fa1d72d35 Merge branch 'integration' into memory_api 2025-11-26 17:08:12 -06:00
J. Nick Koston
6357f88abc Merge remote-tracking branch 'upstream/dev' into integration 2025-11-26 17:08:07 -06:00
Clyde Stubbs
b3955cd151 [epaper_spi] Add SSD1677 and Waveshare 4.26 (#11887)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 17:07:51 -06:00
J. Nick Koston
b2cc760ad2 Merge branch 'integration' into memory_api 2025-11-26 17:07:05 -06:00
J. Nick Koston
66652c5928 Merge branch 'dev' into integration 2025-11-26 17:06:58 -06:00
Clyde Stubbs
927d3715c1 [lvgl] Allow setting text directly on a button (#11964)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 17:06:40 -06:00
Clyde Stubbs
a2d9941c62 [lvgl] Add option to sync updates with display (#11896)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 17:06:32 -06:00
Clyde Stubbs
caaa08d678 [core] Fix for missing arguments to shared_lambda (#12115) 2025-11-26 17:05:45 -06:00
Jon Oberheide
eb970cf44e make thermostat humidification_action public (#12132) 2025-11-26 16:56:22 -06:00
J. Nick Koston
8d8ded74ae Merge branch 'schedule_use_after_free' into integration 2025-11-26 16:40:56 -06:00
J. Nick Koston
877d2b914c tweaks 2025-11-26 16:38:39 -06:00
J. Nick Koston
1d59c7a838 [scheduler] Fix use-after-move crash in heap operations 2025-11-26 12:08:49 -06:00
Pawelo
083886c4b0 [prometheus] Avoid generating unused light color metrics to reduce memory usage on ESP8266 (#9530)
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-11-26 18:06:51 +00:00
Javier Peletier
12a51ff047 [packages] Fix package schema validation (#12116)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 11:00:44 -06:00
J. Nick Koston
b328758634 Revert "[core] Deduplicate identical stateless lambdas to reduce flash usage" (#12117) 2025-11-26 10:53:44 -06:00
J. Nick Koston
83db380dfa Merge branch 'integration' into memory_api 2025-11-25 21:41:45 -06:00
J. Nick Koston
70089e03d5 Merge branch 'timeout_filter_scheduler_churn_fix' into integration 2025-11-25 21:41:38 -06:00
J. Nick Koston
1d24bf8438 Merge branch 'integration' into memory_api 2025-11-25 21:21:30 -06:00
J. Nick Koston
cbbdd634c1 Merge upstream/dev into integration 2025-11-25 21:21:03 -06:00
Clyde Stubbs
1207b9e995 [lvgl] Automatically pad rows and columns (#11879)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 01:53:51 +00:00
Clyde Stubbs
e071380532 [lvgl] Add missing obj scroll properties (#11901)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 01:49:47 +00:00
Clyde Stubbs
f071b6232a [lvgl] Fix position of errors in widget config (#12111)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-26 01:47:27 +00:00
J. Nick Koston
d443dbbf34 [lvgl] Fix lambda return types for coord and font validators (#12113) 2025-11-25 19:42:09 -06:00
J. Nick Koston
03a8ef71ff [esp32_ble_client] Replace std::string with char[18] for BLE address storage (#12070) 2025-11-25 18:37:49 -06:00
J. Nick Koston
bda17180df [core] Deduplicate identical stateless lambdas to reduce flash usage (#11918) 2025-11-26 12:48:08 +13:00
J. Nick Koston
ffae3501ab [core] Replace seq<>/gens<> with std::index_sequence for code clarity (#11921) 2025-11-26 12:44:50 +13:00
Jesse Hills
50bdcdee0c Add developer-breaking-change labelling (#12095) 2025-11-26 12:39:41 +13:00
J. Nick Koston
2c6500511f Merge branch 'dev' into timeout_filter_scheduler_churn_fix 2025-11-25 14:30:36 -06:00
dependabot[bot]
ae60b5e6a1 Bump actions/setup-python from 6.0.0 to 6.1.0 in /.github/actions/restore-python (#12108)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 14:27:49 -06:00
dependabot[bot]
70df4ecaa9 Bump actions/setup-python from 6.0.0 to 6.1.0 (#12106)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 13:35:40 -06:00
Clyde Stubbs
b6be5e3eda [lvgl] Allow multiple widgets per grid cell (#12091) 2025-11-26 06:06:42 +11:00
Nikolai Ryzhkov
dec323e786 [sht4x] Read and store a serial number of SHT4x sensors (#12089)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-25 13:27:35 -05:00
J. Nick Koston
6ca0cd1e8b [ltr390] Simplify mode tracking with bitmask instead of vector/function (#12093) 2025-11-25 12:16:48 -06:00
J. Nick Koston
3106934678 [esp32_ble] Optimize name storage to reduce RAM and eliminate heap allocations (#12071) 2025-11-25 12:16:27 -06:00
J. Nick Koston
8c5985f68a [web_server] Consolidate turn_on/turn_off handlers to eliminate duplicate lambdas (#12094) 2025-11-25 12:16:02 -06:00
J. Nick Koston
cf8c205644 [core] Reduce flash size by combining set_name() and set_object_id() calls (#11941) 2025-11-25 12:15:45 -06:00
J. Nick Koston
a571033b43 [script] Fix script.wait hanging when triggered from on_boot (#12102) 2025-11-25 10:30:01 -06:00
Jonathan Swoboda
cdf27f1447 [esp32] Fix platformio flash size print (#12099)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-25 11:14:53 -05:00
Edward Firmo
c30b920193 [nextion] Do not set alternative baud rate when not specified or <= 0 (#12097) 2025-11-25 07:48:32 -05:00
J. Nick Koston
697c5f424e [api] Use const char* pointers for light effects to eliminate heap allocations (#12090) 2025-11-25 08:17:53 +00:00
J. Nick Koston
18c97a08c3 [esp8266] Use C++17 nested namespaces and constexpr (#12096) 2025-11-25 01:47:06 -06:00
bdm310
66a871840e Add more lvgl arc update parameters (#12066) 2025-11-25 17:14:23 +11:00
J. Nick Koston
dc3366c431 Merge branch 'integration' into memory_api 2025-11-24 21:35:43 -06:00
J. Nick Koston
e01aec79e3 Merge branch 'web_server_turn_on_off_cleanup' into integration 2025-11-24 21:35:37 -06:00
J. Nick Koston
b06c730a26 [web_server] Consolidate turn_on/turn_off handlers to eliminate duplicate lambdas 2025-11-24 21:34:36 -06:00
J. Nick Koston
46a26560fd [template.alarm_control_panel] Replace std::map with FixedVector for heap and flash savings (#11893) 2025-11-25 16:21:56 +13:00
J. Nick Koston
1c808a3375 [ble_client] Write static BLE data directly from flash without allocation (#11826) 2025-11-25 16:19:18 +13:00
J. Nick Koston
1969d1a9ff Merge branch 'integration' into memory_api 2025-11-24 21:04:37 -06:00
J. Nick Koston
ee18f19e88 Merge branch 'ltr390_containers' into integration 2025-11-24 21:04:17 -06:00
J. Nick Koston
24217eb257 [ltr390] Simplify mode tracking with bitmask instead of vector/function 2025-11-24 20:58:38 -06:00
Keith Burzinski
2bc8a4a779 [wifi_info] Use callbacks instead of polling (#10748)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-24 20:23:10 -06:00
dependabot[bot]
7f1a9a611f Bump aioesphomeapi from 42.7.0 to 42.8.0 (#12092)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-25 02:09:02 +00:00
J. Nick Koston
f478e2e841 Merge branch 'integration' into memory_api 2025-11-24 19:39:40 -06:00
J. Nick Koston
7a9e1964b1 Merge branch 'effects_are_const_char' into integration 2025-11-24 19:39:33 -06:00
J. Nick Koston
a018809404 [api] Use const char* pointers for light effects to eliminate heap allocations 2025-11-24 19:38:13 -06:00
J. Nick Koston
781de689c0 merge 2025-11-24 19:14:00 -06:00
J. Nick Koston
4496a6e7b2 Merge branch 'integration' into memory_api 2025-11-24 18:35:42 -06:00
J. Nick Koston
1a882ab406 Merge remote-tracking branch 'kbx81/20250915-wifi-info-use-callbacks' into integration 2025-11-24 18:35:31 -06:00
kbx81
27547313cd Suggestions from review 2025-11-24 18:31:11 -06:00
Keith Burzinski
f5bdbc7af2 More const
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-24 18:19:27 -06:00
Keith Burzinski
90f38566ea Update esphome/components/wifi/__init__.py
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-24 18:05:40 -06:00
J. Nick Koston
a50c744714 Update text_sensor.py
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2025-11-24 17:50:36 -06:00
kbx81
c7d485e8bd Use set.intersection 2025-11-24 17:08:55 -06:00
Keith Burzinski
da23215e05 Merge branch 'dev' into 20250915-wifi-info-use-callbacks 2025-11-24 16:59:23 -06:00
Jonathan Swoboda
b51409ed5e Merge branch 'release' into dev 2025-11-24 17:30:08 -05:00
Jonathan Swoboda
3775b54554 Merge pull request #12086 from esphome/bump-2025.11.1
2025.11.1
2025-11-24 17:29:53 -05:00
kbx81
9b50ed3589 conditionally compile callbacks 2025-11-24 16:09:12 -06:00
kbx81
0398b92de5 Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-11-24 15:45:28 -06:00
J. Nick Koston
22b47eb258 Merge branch 'integration' into memory_api 2025-11-24 15:40:03 -06:00
J. Nick Koston
7912f19230 mege 2025-11-24 15:39:52 -06:00
J. Nick Koston
c3a81dbbaa Merge branch 'integration' into memory_api 2025-11-24 15:36:47 -06:00
J. Nick Koston
decba7c233 Merge branch 'mdns_arduino' into integration 2025-11-24 15:36:42 -06:00
J. Nick Koston
f5736303c3 fixs 2025-11-24 15:36:31 -06:00
J. Nick Koston
e6012f8f76 Merge branch 'integration' into memory_api 2025-11-24 15:34:54 -06:00
J. Nick Koston
39c2fea116 Merge branch 'mdns_arduino' into integration 2025-11-24 15:34:43 -06:00
J. Nick Koston
03767474b7 [mdns] Extract common Arduino mDNS registration to shared header 2025-11-24 15:28:45 -06:00
J. Nick Koston
fca4512370 [mdns] Extract common Arduino mDNS registration to shared header 2025-11-24 15:28:38 -06:00
Keith Burzinski
88b898458b [bluetooth_proxy] Fix crash due to null pointer (#12084)
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>
2025-11-24 21:25:49 +00:00
Jonathan Swoboda
9186144dcd Bump version to 2025.11.1 2025-11-24 16:24:38 -05:00
Jesse Hills
25bcd0ea25 [online_image] Fix some large PNGs causing watchdog timeout (#12025)
Co-authored-by: guillempages <guillempages@users.noreply.github.com>
2025-11-24 16:24:38 -05:00
J. Nick Koston
50d08a2eba [esp_ldo,mipi_dsi,mipi_rgb] Fix dangling pointer bugs in mark_failed() (#12077) 2025-11-24 16:24:38 -05:00
J. Nick Koston
3a7a0c66ab [script][wait_until] Fix FIFO ordering and reentrancy bugs (#12049)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 16:24:38 -05:00
Jonathan Swoboda
83525b7a92 [core] Add support for passing yaml files to clean-all (#12039) 2025-11-24 16:24:38 -05:00
Jonathan Swoboda
f31f023c89 [esp32] Fix C2 builds (#12050) 2025-11-24 16:24:37 -05:00
J. Nick Koston
f8efefffaa [cst816][http_request] Fix status_set_error() dangling pointer bugs (#12033) 2025-11-24 16:24:37 -05:00
Jonathan Swoboda
d698083ede [jsn_sr04t] Fix model AJ_SR04M (#11992) 2025-11-24 16:24:37 -05:00
Jonathan Swoboda
11ba6440d7 [cst816][packet_transport][udp][wake_on_lan] Fix error messages (#12019) 2025-11-24 16:24:37 -05:00
Jonathan Swoboda
89ee37a2d5 [ltr501][ltr_als_ps] Rename enum to avoid collision with lwip defines (#12017) 2025-11-24 16:24:37 -05:00
J. Nick Koston
45b8c1e267 [network] Fix IPAddress constructor causing comparison failures and garbage output (#12005) 2025-11-24 16:24:37 -05:00
Jonathan Swoboda
fbe091f167 [graph] Fix legend border (#12000) 2025-11-24 16:24:37 -05:00
dependabot[bot]
e09656f20e Bump bleak from 1.1.1 to 2.0.0 (#12083)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 15:21:03 -06:00
Jesse Hills
eeb373fca9 [online_image] Fix some large PNGs causing watchdog timeout (#12025)
Co-authored-by: guillempages <guillempages@users.noreply.github.com>
2025-11-25 09:15:30 +13:00
J. Nick Koston
97ba67f4ee [core] Deprecate unsafe const char* APIs in mark_failed() and status_set_error(), add LogString* overloads (#12021) 2025-11-24 13:45:56 -06:00
J. Nick Koston
909baf5e7a [prometheus] Use current_option() instead of deprecated .state for select entities (#12079) 2025-11-24 13:45:29 -06:00
J. Nick Koston
a0440603b7 [wifi] Use ESP-IDF IP formatting macros directly to eliminate heap allocations (#12078) 2025-11-24 13:45:06 -06:00
dependabot[bot]
e2cd0ccd0e Bump actions/create-github-app-token from 2.1.4 to 2.2.0 (#12081)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 13:44:43 -06:00
dependabot[bot]
378fc4120a Bump peter-evans/create-pull-request from 7.0.8 to 7.0.9 (#12082)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 13:44:27 -06:00
dependabot[bot]
0dd842744a Bump github/codeql-action from 4.31.4 to 4.31.5 (#12080)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-24 13:44:09 -06:00
J. Nick Koston
a95f2ec484 Merge branch 'integration' into memory_api 2025-11-24 12:45:44 -06:00
J. Nick Koston
537ddcc880 Merge branch 'wifi_idf_cleanup' into integration 2025-11-24 12:45:38 -06:00
J. Nick Koston
d2483347d0 [wifi] Use ESP-IDF IP formatting macros directly to eliminate heap allocations 2025-11-24 12:44:41 -06:00
J. Nick Koston
b311d610df Merge branch 'integration' into memory_api 2025-11-24 12:24:06 -06:00
J. Nick Koston
301cf54ca6 Merge branch 'error_logstr' into integration 2025-11-24 12:24:02 -06:00
J. Nick Koston
bc7f67e0a2 clear 2025-11-24 12:23:51 -06:00
J. Nick Koston
7a73a524b9 [logger] Eliminate strlen overhead on LibreTiny (#11938) 2025-11-24 12:21:09 -06:00
J. Nick Koston
990a4442c7 Merge branch 'integration' into memory_api 2025-11-24 12:19:15 -06:00
J. Nick Koston
4eca6a7442 Merge branch 'error_logstr' into integration 2025-11-24 12:19:10 -06:00
J. Nick Koston
7496d20ae6 fix ambiguous 2025-11-24 12:18:59 -06:00
J. Nick Koston
83b5f061da Merge branch 'integration' into memory_api 2025-11-24 12:17:10 -06:00
J. Nick Koston
29999b3148 Merge branch 'error_logstr' into integration 2025-11-24 12:17:05 -06:00
J. Nick Koston
9d49ca58b5 silence warning for nullptr 2025-11-24 12:16:52 -06:00
J. Nick Koston
a279cc623a Merge branch 'integration' into memory_api 2025-11-24 12:12:22 -06:00
J. Nick Koston
7fc04c094c Merge branch 'error_logstr' into integration 2025-11-24 12:12:13 -06:00
J. Nick Koston
84b2bea706 fix dual dep 2025-11-24 12:12:05 -06:00
J. Nick Koston
fa1efb1048 Merge branch 'integration' into memory_api 2025-11-24 12:10:08 -06:00
J. Nick Koston
a6446ee179 Merge branch 'error_logstr' into integration 2025-11-24 12:09:58 -06:00
J. Nick Koston
04bb60fe5a Merge branch 'integration' into memory_api 2025-11-24 12:09:31 -06:00
J. Nick Koston
e2311d70e6 Merge branch 'libretiny_no_strlen' into integration 2025-11-24 12:09:26 -06:00
Kevin Ahrendt
d1a1bb446b [wifi] Add runtime power saving mode control (#11478)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-24 17:55:04 +00:00
J. Nick Koston
c146d92425 [api] Remove redundant socket pointer from APIFrameHelper (#11985) 2025-11-25 06:53:42 +13:00
J. Nick Koston
c888becfa7 [api] Optimize APINoiseContext memory usage by removing shared_ptr overhead (#11981) 2025-11-25 06:52:15 +13:00
Flo
09f3f62194 [api] Connected Condition - state_subscription_only flag (#11906)
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>
2025-11-24 11:49:16 -06:00
J. Nick Koston
af9d0634cd Merge branch 'integration' into memory_api 2025-11-24 11:47:23 -06:00
J. Nick Koston
296e79d9e5 Merge branch 'copilot/fix-internal-gpio-attach-issues' into integration 2025-11-24 11:47:18 -06:00
Jordan Zucker
b820e67616 [prometheus] Add event and text base components metrics (#10240)
Co-authored-by: Jordan Zucker <jordan@Jordans-MacBook-Pro.local>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-24 11:42:07 -06:00
Sascha Ittner
d7da559885 [thermopro_ble] Add thermopro ble support (#11835)
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-24 11:31:26 -06:00
Jonathan Swoboda
d7a197b3a3 [esp32] Use the IDF I2C implementation on Arduino (#12076) 2025-11-24 12:27:09 -05:00
Flo
66cda04664 [wifi] ap_active condition (#11852)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
2025-11-24 11:19:38 -06:00
J. Nick Koston
c4dec5b3e3 Merge branch 'dev' into error_logstr 2025-11-24 11:02:54 -06:00
J. Nick Koston
0764f4da86 [esp_ldo,mipi_dsi,mipi_rgb] Fix dangling pointer bugs in mark_failed() (#12077) 2025-11-24 11:02:24 -06:00
J. Nick Koston
b29068cd40 Merge branch 'dev' into mdns_mac_storage_reduce_ram 2025-11-24 10:43:15 -06:00
J. Nick Koston
06815fe177 [script][wait_until] Fix FIFO ordering and reentrancy bugs (#12049)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-24 10:41:24 -06:00
J. Nick Koston
780fe37a13 fix mipi_dsi implementation 2025-11-24 10:27:53 -06:00
J. Nick Koston
4c1ec60d8b Merge remote-tracking branch 'origin/dev' into error_logstr 2025-11-24 10:27:12 -06:00
J. Nick Koston
5248e0139d handle mark_failed case 2025-11-24 10:25:15 -06:00
J. Nick Koston
04ec6a6999 [api] Use stack buffer for MAC address in Noise handshake (#12072) 2025-11-24 10:23:31 -06:00
J. Nick Koston
737f23a0bd [light] Dynamically disable loop when idle to reduce CPU overhead (#11881) 2025-11-24 10:23:11 -06:00
J. Nick Koston
011992f64d Merge branch 'dev' into libretiny_no_strlen 2025-11-24 10:22:44 -06:00
J. Nick Koston
3c48e13c9f [ethernet] Conditionally compile manual_ip to save 24 bytes RAM (#11832) 2025-11-24 10:22:13 -06:00
J. Nick Koston
426734beef [web_server_base] Replace shared_ptr with unique_ptr for AsyncWebServer (#11984) 2025-11-24 10:22:01 -06:00
J. Nick Koston
056b4375eb [api] Reduce heap allocations in DeviceInfoResponse (#11952) 2025-11-24 10:21:47 -06:00
J. Nick Koston
1f0a5e1eea [logger] Reduce UART overhead on ESP32/ESP8266 and fix buffer truncation (#11927) 2025-11-24 10:21:32 -06:00
Jonathan Swoboda
8607a0881d [core] Add support for passing yaml files to clean-all (#12039) 2025-11-24 10:10:24 -05:00
J. Nick Koston
87ded80310 Merge branch 'integration' into memory_api 2025-11-24 08:34:32 -06:00
J. Nick Koston
c141678abc Merge branch 'mdns_mac_storage_reduce_ram' into integration 2025-11-24 08:34:19 -06:00
J. Nick Koston
fd0a4e9111 dry 2025-11-24 08:34:04 -06:00
J. Nick Koston
12051813b8 dry 2025-11-24 08:33:47 -06:00
James
b4b98505ba [mipi_dsi] add guition JC4880P443 display (#12068) 2025-11-24 21:05:02 +11:00
kbx81
5b23b471bb preen 2025-11-24 02:34:46 -06:00
kbx81
84f9cbca58 preen 2025-11-24 02:21:34 -06:00
Keith Burzinski
87edf7ccf4 Merge branch 'dev' into 20250915-wifi-info-use-callbacks 2025-11-24 01:34:24 -06:00
kbx81
c1bc0358c3 preen 2025-11-24 01:33:32 -06:00
kbx81
deb8ffafa8 pico_w 2025-11-24 01:30:29 -06:00
J. Nick Koston
1fa4eedbb4 Merge branch 'integration' into memory_api 2025-11-23 22:43:50 -06:00
J. Nick Koston
9dd3ca7cf5 Merge branch 'mdns_mac_storage_reduce_ram' into integration 2025-11-23 22:43:43 -06:00
J. Nick Koston
b8719319fe cleanup 2025-11-23 22:42:07 -06:00
J. Nick Koston
39a4a0bf10 no dupe storage 2025-11-23 22:35:13 -06:00
Jonathan Swoboda
60d687c2c6 [esp32] Fix C2 builds (#12050) 2025-11-23 23:31:14 -05:00
J. Nick Koston
02c54bb373 Merge branch 'integration' into memory_api 2025-11-23 21:52:16 -06:00
J. Nick Koston
76406c91a5 Merge branch 'mdns_mac_storage_reduce_ram' into integration 2025-11-23 21:52:11 -06:00
J. Nick Koston
792a2b1ee1 tidy 2025-11-23 21:52:02 -06:00
J. Nick Koston
6fa7ad4e80 Merge branch 'integration' into memory_api 2025-11-23 21:46:25 -06:00
J. Nick Koston
98d3fb535f Merge branch 'mdns_mac_storage_reduce_ram' into integration 2025-11-23 21:46:19 -06:00
J. Nick Koston
fa299eed58 [mdns] Store MAC address in fixed buffer to reduce RAM usage 2025-11-23 21:45:28 -06:00
Jonathan Swoboda
5750f7fccb [ci] Fix test grouping (#12067) 2025-11-23 21:25:24 -06:00
J. Nick Koston
a018e07d3f Merge branch 'integration' into memory_api 2025-11-23 21:23:32 -06:00
J. Nick Koston
62823adc19 Merge branch 'esp32_ble_name_char' into integration 2025-11-23 21:23:25 -06:00
J. Nick Koston
2cd71bf273 one more 2025-11-23 21:22:26 -06:00
J. Nick Koston
ff4940d3b5 one more 2025-11-23 21:21:02 -06:00
J. Nick Koston
48f0e52f9d one more 2025-11-23 21:20:23 -06:00
J. Nick Koston
36f109c708 Merge branch 'integration' into memory_api 2025-11-23 21:15:36 -06:00
J. Nick Koston
8ed36e699f Merge branch 'api_noise_reduce_alloc' into integration 2025-11-23 21:15:29 -06:00
J. Nick Koston
268780dbeb [api] Use stack buffer for MAC address in Noise handshake 2025-11-23 21:13:27 -06:00
J. Nick Koston
a0bbce190a Merge branch 'integration' into memory_api 2025-11-23 21:01:42 -06:00
J. Nick Koston
214e6c358b Merge branch 'esp32_ble_name_char' into integration 2025-11-23 21:01:31 -06:00
J. Nick Koston
1e886b8885 [esp32_ble] Store device name in flash to reduce RAM usage 2025-11-23 20:56:27 -06:00
J. Nick Koston
531af6a277 [esp32_ble] Store device name in flash to reduce RAM usage 2025-11-23 20:50:31 -06:00
J. Nick Koston
b432c056dc [esp32_ble] Store device name in flash to reduce RAM usage 2025-11-23 20:48:27 -06:00
J. Nick Koston
cd9323ce70 overload 2025-11-23 20:45:31 -06:00
J. Nick Koston
10cc0c3bff overload 2025-11-23 20:43:51 -06:00
J. Nick Koston
5fcfe31be4 Merge branch 'integration' into memory_api 2025-11-23 20:39:13 -06:00
J. Nick Koston
9b8c9d38f5 Merge branch 'esp32_ble_name_char' into integration 2025-11-23 20:38:54 -06:00
J. Nick Koston
e7d09c0f62 [esp32_ble] Store device name in flash to reduce RAM usage 2025-11-23 20:36:54 -06:00
J. Nick Koston
0f5809765e Merge branch 'integration' into memory_api 2025-11-23 20:17:49 -06:00
J. Nick Koston
d3d5e4c8f4 Merge branch 'ble_address_str' into integration 2025-11-23 20:17:40 -06:00
J. Nick Koston
173912c68b more fixes 2025-11-23 20:10:44 -06:00
J. Nick Koston
4795ac7b1b [esp32_ble_client] Replace std::string with char[18] for BLE address storage 2025-11-23 20:03:25 -06:00
Jonathan Swoboda
c91a9495e6 [ci] Fix filename (#12065) 2025-11-23 16:19:26 -05:00
Javier Peletier
f42b806889 [core] Fix error on invalid id extend/remove (#12064) 2025-11-24 08:03:13 +11:00
Jesse Hills
a5751b294f [api] Rename USE_API_SERVICES to USE_API_USER_DEFINED_ACTIONS (#12029) 2025-11-24 08:13:23 +13:00
kbx81
66d6c85aa7 preen 2025-11-23 02:05:41 -06:00
kbx81
97572cc968 Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-11-23 02:04:55 -06:00
Abílio Costa
3f6f2d7d65 [bm8563] Add bm8563 component (#11616)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-21 15:28:42 -05:00
Marko Draca
782aee92a7 [mcp3204] differential mode support (#7436)
Co-authored-by: marko <marko@>
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-21 14:50:07 -05:00
J. Nick Koston
1fe1a3d2c8 fix date 2025-11-21 11:00:23 -06:00
J. Nick Koston
7de66024ca dry, fix load protected on esp8266 2025-11-21 10:56:12 -06:00
J. Nick Koston
6a48ba8d59 Merge branch 'dev' into error_logstr 2025-11-21 10:28:50 -06:00
Thomas Rupprecht
972b7e84fe [tests] Fix mipi_spi test board (#12031)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-21 08:38:44 -05:00
J. Nick Koston
d68fd02de4 Merge branch 'dev' into error_logstr 2025-11-21 06:42:25 -06:00
J. Nick Koston
150e26dc2b [cst816][http_request] Fix status_set_error() dangling pointer bugs (#12033) 2025-11-21 06:41:48 -06:00
Jonathan Swoboda
0dea7a23e3 [jsn_sr04t] Fix model AJ_SR04M (#11992) 2025-11-21 07:39:59 -05:00
copilot-swe-agent[bot]
ddf1e27ac3 Move gpio_intr_enable after gpio_isr_handler_add per review feedback
Co-authored-by: jesserockz <3060199+jesserockz@users.noreply.github.com>
2025-11-20 22:55:08 +00:00
J. Nick Koston
04c64c0f73 Merge branch 'integration' into memory_api 2025-11-20 15:10:21 -06:00
J. Nick Koston
a2a125a5c2 Merge remote-tracking branch 'upstream/copilot/fix-internal-gpio-attach-issues' into integration 2025-11-20 15:10:08 -06:00
copilot-swe-agent[bot]
55d7344086 Remove gpio_intr_enable() call to fix level-triggered interrupt panic
Co-authored-by: jesserockz <3060199+jesserockz@users.noreply.github.com>
2025-11-20 19:54:05 +00:00
copilot-swe-agent[bot]
fae833b73b Initial plan 2025-11-20 19:49:10 +00:00
dependabot[bot]
01addeae08 Bump actions/checkout from 5.0.1 to 6.0.0 (#12022)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-20 13:11:41 -06:00
J. Nick Koston
e37885ade5 syntax 2025-11-20 12:12:42 -06:00
J. Nick Koston
7cbc890c0d syntax 2025-11-20 12:12:14 -06:00
J. Nick Koston
3955b66379 [core] Deprecate status_set_error(const char*) and require LogString to prevent dangling pointers 2025-11-20 12:04:20 -06:00
Jonathan Swoboda
a1e507baf8 [cst816][packet_transport][udp][wake_on_lan] Fix error messages (#12019) 2025-11-20 12:10:28 -05:00
Jonathan Swoboda
1accb4ff34 [ltr501][ltr_als_ps] Rename enum to avoid collision with lwip defines (#12017) 2025-11-20 10:58:21 -05:00
damib
59cd6dbf70 [climate_ir] Add optional humidity sensor (#9805)
Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: Djordje Mandic <6750655+DjordjeMandic@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-11-20 09:28:14 -05:00
omartijn
3c86f3894b [hc8] Add support for HC8 CO2 sensor (#11872)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-20 09:24:45 -05:00
J. Nick Koston
06bef148f4 [core] Optimize DelayAction for no-argument case using if constexpr (#11913) 2025-11-20 09:06:52 -05:00
tomaszduda23
5d883c6e06 [nrf52,i2c] fix review comment (#11931) 2025-11-20 09:06:40 -05:00
J. Nick Koston
b62053812b [core] Document threading model rationale in ThreadModel enum (#11979) 2025-11-20 09:06:28 -05:00
J. Nick Koston
a2321edf3c [network] Fix IPAddress constructor causing comparison failures and garbage output (#12005) 2025-11-20 08:59:16 -05:00
J. Nick Koston
24a6ad148c [lock] Modernize to C++17 nested namespaces (#11982) 2025-11-20 08:57:49 -05:00
J. Nick Koston
5071473767 [mdns] Modernize to C++17 nested namespace syntax (#11983) 2025-11-20 08:57:33 -05:00
J. Nick Koston
4825da8e9c [select] Modernize namespace declarations to C++17 syntax (#12007) 2025-11-20 08:57:04 -05:00
J. Nick Koston
48ba72ee34 Merge branch 'integration' into memory_api 2025-11-20 07:23:02 -06:00
J. Nick Koston
f494ca8e0f Merge branch 'api_ha_subs' into integration 2025-11-20 07:22:55 -06:00
J. Nick Koston
946f8deb3d tweak naming 2025-11-20 07:22:27 -06:00
Javier Peletier
b346666a52 [st7701s] Add explanatory comment (#12014) 2025-11-20 20:05:22 +11:00
J. Nick Koston
5fadeb5fd3 Merge branch 'integration' into memory_api 2025-11-19 23:26:03 -06:00
J. Nick Koston
56ef46fdd4 Merge branch 'api_ha_subs' into integration 2025-11-19 23:25:55 -06:00
J. Nick Koston
177026d8c4 simplify 2025-11-19 23:25:45 -06:00
J. Nick Koston
4533b8f92c tweaks 2025-11-19 23:20:24 -06:00
J. Nick Koston
0d3919747c Merge branch 'integration' into memory_api 2025-11-19 22:52:08 -06:00
J. Nick Koston
19c377b6de Merge branch 'api_ha_subs' into integration 2025-11-19 22:51:56 -06:00
J. Nick Koston
b9595c0795 cover 2025-11-19 22:49:52 -06:00
J. Nick Koston
efe2a1a506 cleanup 2025-11-19 22:32:41 -06:00
J. Nick Koston
185c1dec43 cleanup 2025-11-19 22:24:00 -06:00
J. Nick Koston
c39d17f864 cleanup 2025-11-19 22:20:12 -06:00
J. Nick Koston
b400a98fb3 [api] Store Home Assistant state subscriptions in flash instead of heap 2025-11-19 22:17:16 -06:00
B48D81EFCC
83307684a3 [stts22h] Add support for STTS22H temperature sensor (#11778)
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-11-20 03:58:39 +00:00
J. Nick Koston
38f9d5d0b6 Merge branch 'integration' into memory_api 2025-11-19 21:39:05 -06:00
J. Nick Koston
c2ee7c7190 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-19 21:38:37 -06:00
David Woodhouse
da25951f6e [socket] Fix IPv6 address parsing for BSD sockets (#11996) 2025-11-19 21:01:32 -06:00
J. Nick Koston
3b3a505283 Merge branch 'integration' into memory_api 2025-11-19 20:54:20 -06:00
J. Nick Koston
8ba330e992 Merge branch 'select_cpp17' into integration 2025-11-19 20:54:08 -06:00
J. Nick Koston
317a6082a1 [select] Modernize namespace declarations to C++17 syntax 2025-11-19 20:53:27 -06:00
J. Nick Koston
9f1b764c59 Merge branch 'integration' into memory_api 2025-11-19 18:25:36 -06:00
J. Nick Koston
463836fbdc Merge branch 'ipaddress_missing_type' into integration 2025-11-19 18:25:26 -06:00
J. Nick Koston
f478e09972 [network] Fix uninitialized type field in IPAddress esp_ip4_addr_t constructor 2025-11-19 18:12:18 -06:00
Jonathan Swoboda
4398fd84d2 [graph] Fix legend border (#12000) 2025-11-20 13:09:22 +13:00
J. Nick Koston
349aa41c1c Merge branch 'integration' into memory_api 2025-11-19 16:42:10 -06:00
J. Nick Koston
f6771dfdae Merge remote-tracking branch 'upstream/dev' into integration 2025-11-19 16:42:04 -06:00
Jonathan Swoboda
bbd6d019e5 Merge branch 'release' into dev 2025-11-19 17:37:58 -05:00
Jonathan Swoboda
625172e07d Merge pull request #12004 from esphome/bump-2025.11.0
2025.11.0
2025-11-19 17:37:42 -05:00
Jonathan Swoboda
1e9c7d3c6d Bump version to 2025.11.0 2025-11-19 16:02:52 -05:00
Jonathan Swoboda
4cdab4e2d8 Merge branch 'beta' into dev 2025-11-19 15:06:55 -05:00
Jonathan Swoboda
c2bc7b3cdc Merge pull request #12003 from esphome/bump-2025.11.0b5
2025.11.0b5
2025-11-19 15:06:44 -05:00
dependabot[bot]
2c3417062a Bump pyupgrade from 3.21.1 to 3.21.2 (#12002)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-19 13:47:40 -06:00
Jonathan Swoboda
c75abfb894 Bump version to 2025.11.0b5 2025-11-19 14:17:03 -05:00
Jesse Hills
1157b4aee8 [epaper_spi] Add basic 7.3in-Spectra-E6 model (#12001) 2025-11-19 14:17:03 -05:00
J. Nick Koston
71dc2d374d [web_server_idf] Fix pbuf_free crash by moving shutdown before close (#11995) 2025-11-19 14:17:03 -05:00
Jonathan Swoboda
0a224f919b [wifi] Fix positive RSSI values on 8266 (#11994) 2025-11-19 14:17:03 -05:00
Jonathan Swoboda
7ef4b4f3d9 [text_sensor] Fix infinite loop in substitute filter (#11989)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-19 14:17:03 -05:00
J. Nick Koston
13b875c763 [tests] Fix SNTP time ID conflicts in component tests for grouped testing (#11990) 2025-11-19 14:17:03 -05:00
Jesse Hills
b02b07ffaf [epaper_spi] Add basic 7.3in-Spectra-E6 model (#12001) 2025-11-19 14:11:45 -05:00
J. Nick Koston
8804bc2815 [web_server_idf] Fix pbuf_free crash by moving shutdown before close (#11995) 2025-11-20 07:58:33 +13:00
Jonathan Swoboda
61cef0a75c [api] Fix format warnings in dump (#11999) 2025-11-19 12:58:47 -05:00
J. Nick Koston
db8eb0ba89 Merge branch 'integration' into memory_api 2025-11-19 11:45:59 -06:00
J. Nick Koston
615cc8a9c0 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-19 11:45:51 -06:00
Jonathan Swoboda
73bc5252a1 [wifi] Fix positive RSSI values on 8266 (#11994) 2025-11-19 10:12:57 -05:00
Jonathan Swoboda
f2b10ad132 [text_sensor] Fix infinite loop in substitute filter (#11989)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-11-19 10:12:34 -05:00
J. Nick Koston
100ea46f03 [tests] Fix SNTP time ID conflicts in component tests for grouped testing (#11990) 2025-11-18 23:19:54 -06:00
J. Nick Koston
b3ef05e5e1 [ld24xx] Modernize namespace declarations to C++17 syntax (#11988) 2025-11-19 04:00:39 +00:00
J. Nick Koston
45c994e4de [light] Modernize namespace declarations to C++17 syntax (#11986) 2025-11-18 21:56:23 -06:00
J. Nick Koston
71fa81088e Merge branch 'integration' into memory_api 2025-11-18 21:47:57 -06:00
J. Nick Koston
4933a2fbe1 Merge branch 'ld_namespace' into integration 2025-11-18 21:47:50 -06:00
J. Nick Koston
2d7942e788 [ld24xx] Modernize namespace declarations to C++17 syntax 2025-11-18 21:46:54 -06:00
J. Nick Koston
c81978c7e9 Merge branch 'integration' into memory_api 2025-11-18 21:09:31 -06:00
J. Nick Koston
a3cd3757b3 Merge branch 'light_namespace' into integration 2025-11-18 21:09:14 -06:00
J. Nick Koston
ecaa3f9f71 [light] Modernize namespace declarations to C++17 syntax 2025-11-18 21:07:13 -06:00
J. Nick Koston
99366eca89 Merge branch 'integration' into memory_api 2025-11-18 18:57:27 -06:00
J. Nick Koston
ab84d2dbeb Merge branch 'frame_helper_socket_dupe' into integration 2025-11-18 18:57:22 -06:00
J. Nick Koston
88717ac1f5 [api] Remove redundant socket pointer from APIFrameHelper 2025-11-18 18:53:50 -06:00
Jesse Hills
a72545639d Merge branch 'beta' into dev 2025-11-19 13:43:25 +13:00
Jesse Hills
dfd614c00c Merge pull request #11980 from esphome/bump-2025.11.0b4
2025.11.0b4
2025-11-19 13:22:09 +13:00
J. Nick Koston
29374837c6 [wifi, captive_portal, web_server, wifi_info] Use stack allocation for MAC address formatting (#11963) 2025-11-18 17:06:34 -06:00
J. Nick Koston
32e0470629 Merge branch 'integration' into memory_api 2025-11-18 16:21:30 -06:00
J. Nick Koston
fa9cc3d338 Merge branch 'web_server_is_singleton' into integration 2025-11-18 16:21:20 -06:00
J. Nick Koston
5c2cf9f37c [web_server_base] Replace shared_ptr with unique_ptr for AsyncWebServer 2025-11-18 16:10:07 -06:00
J. Nick Koston
c8cde24607 Merge branch 'integration' into memory_api 2025-11-18 15:58:19 -06:00
J. Nick Koston
b2bece2914 Merge branch 'mdns_namespace' into integration 2025-11-18 15:58:02 -06:00
J. Nick Koston
9f2e6d97d3 Merge branch 'lock_ns' into integration 2025-11-18 15:57:50 -06:00
J. Nick Koston
65b5619555 Merge branch 'api_noise' into integration 2025-11-18 15:57:44 -06:00
J. Nick Koston
b5ebe91150 [api] Optimize APINoiseContext memory usage by removing shared_ptr overhead 2025-11-18 15:24:50 -06:00
J. Nick Koston
99acc62c3b [lock] Modernize to C++17 nested namespaces 2025-11-18 14:51:37 -06:00
J. Nick Koston
66e471cf2a [mdns] Modernize to C++17 nested namespace syntax 2025-11-18 14:33:07 -06:00
J. Nick Koston
7ffff03823 Merge branch 'integration' into memory_api 2025-11-18 14:28:20 -06:00
J. Nick Koston
4e58c334d4 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-18 14:28:07 -06:00
Jesse Hills
2681a14d05 Bump version to 2025.11.0b4 2025-11-19 09:17:33 +13:00
J. Nick Koston
f436f6ee2e [wifi] Fix captive portal unusable when WiFi credentials are wrong (#11965) 2025-11-19 09:17:33 +13:00
Jonathan Swoboda
f18bc62690 [sfa30] Fix negative temperature values (#11973) 2025-11-19 09:17:33 +13:00
J. Nick Koston
6db73df649 [scheduler] Add defensive nullptr checks and explicit locking requirements (#11974) 2025-11-19 09:17:33 +13:00
Jonathan Swoboda
93215f1737 [esp32] Fix Arduino build on some ESP32 S2 boards (#11972) 2025-11-19 09:17:33 +13:00
Clyde Stubbs
70aa94b8a4 [lvgl] Apply scale to spinbox value (#11946) 2025-11-19 09:17:33 +13:00
strange_v
e8998a79c7 [mipi_rgb] Fix GUITION-4848S040 colors (#11709) 2025-11-19 09:17:33 +13:00
Jonathan Swoboda
3b25fdbc5f [core] Add support for setting environment variables (#11953) 2025-11-19 09:17:33 +13:00
J. Nick Koston
6c8577678c [captive_portal] Warn when enabled without WiFi AP configured (#11856) 2025-11-19 09:17:33 +13:00
J. Nick Koston
70ed9c7c4d [wifi] Fix captive portal unusable when WiFi credentials are wrong (#11965) 2025-11-19 08:17:21 +13:00
dependabot[bot]
81fe5deaa9 Bump github/codeql-action from 4.31.3 to 4.31.4 (#11977)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-19 08:12:42 +13:00
Jonathan Swoboda
72e4b16a5b [sfa30] Fix negative temperature values (#11973) 2025-11-18 13:29:40 -05:00
Jonathan Swoboda
fe2befcec2 [bme68x] Print error when no sensors are configured (#11976) 2025-11-18 13:18:09 -05:00
J. Nick Koston
1888f5ffd5 [scheduler] Add defensive nullptr checks and explicit locking requirements (#11974) 2025-11-18 18:16:18 +00:00
Jonathan Swoboda
c59af22217 [esp32] Fix Arduino build on some ESP32 S2 boards (#11972) 2025-11-18 12:40:31 -05:00
J. Nick Koston
700e458352 Merge branch 'integration' into memory_api 2025-11-18 11:33:03 -06:00
J. Nick Koston
50982ced40 Merge branch 'scheduler_fix_nullptr' into integration 2025-11-18 11:32:58 -06:00
J. Nick Koston
d83a698398 [scheduler] Add defensive nullptr checks and explicit locking requirements 2025-11-18 11:31:01 -06:00
J. Nick Koston
33983b051b [ld24xx] Use stack allocation for MAC and version formatting (#11961) 2025-11-18 10:51:47 -06:00
J. Nick Koston
3ae68c0488 Merge branch 'integration' into memory_api 2025-11-18 10:13:31 -06:00
J. Nick Koston
0b8b5768b4 Merge branch 'captive_fix' into integration 2025-11-18 10:13:26 -06:00
J. Nick Koston
92e19c497e fixes 2025-11-18 10:13:03 -06:00
J. Nick Koston
62c9d83777 fixes 2025-11-18 10:09:14 -06:00
J. Nick Koston
53a3a5ddea fixes 2025-11-18 10:08:53 -06:00
J. Nick Koston
1f6aca5c17 fixes 2025-11-18 10:08:44 -06:00
J. Nick Koston
6253496192 Merge branch 'integration' into memory_api 2025-11-18 09:58:59 -06:00
J. Nick Koston
44d40804b2 Merge branch 'captive_fix' into integration 2025-11-18 09:58:50 -06:00
J. Nick Koston
303792bf8d make sure improv works if we are in connect loop 2025-11-18 09:58:34 -06:00
J. Nick Koston
9091285559 Merge branch 'integration' into memory_api 2025-11-18 09:37:39 -06:00
J. Nick Koston
8c028ce564 Merge branch 'captive_fix' into integration 2025-11-18 09:37:34 -06:00
J. Nick Koston
516f94671d fixes 2025-11-18 09:37:27 -06:00
J. Nick Koston
da70e4d9d0 Merge branch 'captive_fix' into integration 2025-11-18 09:35:20 -06:00
J. Nick Koston
19bd282274 fix tight loop 2025-11-18 09:35:14 -06:00
J. Nick Koston
61ca469a86 Merge branch 'integration' into memory_api 2025-11-18 09:33:37 -06:00
J. Nick Koston
46832306ad Merge branch 'captive_fix' into integration 2025-11-18 09:33:30 -06:00
J. Nick Koston
eaaaeecc92 there is a tight loop in improv 2025-11-18 09:32:50 -06:00
J. Nick Koston
bfea5c10d6 Merge branch 'integration' into memory_api 2025-11-18 09:28:23 -06:00
J. Nick Koston
3ac94fa6ab Merge branch 'captive_fix' into integration 2025-11-18 09:28:18 -06:00
J. Nick Koston
17b72061ad realign timeouts 2025-11-18 09:26:53 -06:00
J. Nick Koston
8025fc4a8b Merge branch 'integration' into memory_api 2025-11-18 09:26:00 -06:00
J. Nick Koston
05c2e31ef6 Merge branch 'captive_fix' into integration 2025-11-18 09:25:52 -06:00
J. Nick Koston
407f07a643 realign timeouts 2025-11-18 09:25:41 -06:00
J. Nick Koston
850978affe realign timeouts 2025-11-18 09:25:24 -06:00
J. Nick Koston
a8af45f60d Merge branch 'integration' into memory_api 2025-11-18 09:14:21 -06:00
J. Nick Koston
8708d4290c Merge branch 'captive_fix' into integration 2025-11-18 09:14:15 -06:00
J. Nick Koston
79b9e34f65 do not skip ssids in retry_hidden if we did not scan 2025-11-18 09:13:29 -06:00
J. Nick Koston
1457ef6e0b Merge branch 'integration' into memory_api 2025-11-18 00:15:41 -06:00
J. Nick Koston
9a2536a5f6 Merge branch 'captive_fix' into integration 2025-11-18 00:15:31 -06:00
J. Nick Koston
66fcf364a6 tweak 2025-11-18 00:09:51 -06:00
J. Nick Koston
048533a1fd no delay 2025-11-17 23:45:59 -06:00
J. Nick Koston
3f763b24c5 no delay 2025-11-17 23:45:32 -06:00
J. Nick Koston
efbf696f88 no delay 2025-11-17 23:45:25 -06:00
J. Nick Koston
29ef0a6740 no delay 2025-11-17 23:43:33 -06:00
J. Nick Koston
b9af06f5a4 no delay 2025-11-17 23:35:26 -06:00
J. Nick Koston
3f799a01a2 anotehr thread safety issue 2025-11-17 23:23:49 -06:00
J. Nick Koston
2ee5cc6f22 anotehr thread safety issue 2025-11-17 23:17:36 -06:00
J. Nick Koston
8d7090fcd6 fix thread safety issue 2025-11-17 23:11:55 -06:00
J. Nick Koston
3d83975d46 fix thread safety issue 2025-11-17 23:11:23 -06:00
J. Nick Koston
1815a7cf90 skip scan when ap mode 2025-11-17 23:03:38 -06:00
J. Nick Koston
bfe6fc0dd0 skip scan when ap mode 2025-11-17 23:00:22 -06:00
J. Nick Koston
87ccb777c6 esp32 2025-11-17 22:32:57 -06:00
J. Nick Koston
f0bae783cf cleanup 2025-11-17 22:31:53 -06:00
J. Nick Koston
6f96804a5d cleanup 2025-11-17 22:31:22 -06:00
Clyde Stubbs
11d0d4d128 [lvgl] Apply scale to spinbox value (#11946) 2025-11-18 17:27:50 +13:00
J. Nick Koston
a81f28a73b fixes 2025-11-17 22:14:56 -06:00
Clyde Stubbs
a4242dee64 [build] Don't clear pio cache unless requested (#11966) 2025-11-18 15:11:49 +11:00
J. Nick Koston
bbfff42f76 fixes 2025-11-17 22:11:27 -06:00
J. Nick Koston
11c8865248 fixes 2025-11-17 21:57:21 -06:00
J. Nick Koston
7f4205b82c reduce 2025-11-17 21:52:12 -06:00
J. Nick Koston
27a068e8b5 reduce 2025-11-17 21:44:18 -06:00
J. Nick Koston
15be275541 tweak 2025-11-17 21:03:35 -06:00
J. Nick Koston
0d6c9623ce [dashboard_import] Store package import URL in .rodata instead of RAM (#11951) 2025-11-17 20:02:16 -06:00
strange_v
0923bcd2ca [mipi_rgb] Fix GUITION-4848S040 colors (#11709) 2025-11-18 01:32:17 +00:00
J. Nick Koston
b0560894b7 [wifi] Fix captive portal unusable when WiFi credentials are wrong 2025-11-17 19:10:40 -06:00
J. Nick Koston
93e7db7b9c Merge branch 'integration' into memory_api 2025-11-17 18:02:31 -06:00
J. Nick Koston
1200e9c3ca Merge branch 'mac_address_buffer' into integration 2025-11-17 18:02:23 -06:00
J. Nick Koston
dc277e64f4 tweak 2025-11-17 18:00:15 -06:00
J. Nick Koston
6aa72f5449 Merge branch 'integration' into memory_api 2025-11-17 17:54:26 -06:00
J. Nick Koston
e312184a22 Merge branch 'mac_address_buffer' into integration 2025-11-17 17:54:18 -06:00
J. Nick Koston
6d67fd0b81 [wifi/captive_portal/web_server/wifi_info] Use stack allocation for MAC address formatting 2025-11-17 17:53:23 -06:00
J. Nick Koston
a08d67027d Merge branch 'integration' into memory_api 2025-11-17 17:34:09 -06:00
J. Nick Koston
0b1dd89fec Merge branch 'ld24xx_mac_version_format' into integration 2025-11-17 17:34:03 -06:00
J. Nick Koston
547f69011b tidy 2025-11-17 17:33:52 -06:00
J. Nick Koston
53bab00858 [ld24xx] Use stack allocation for MAC and version formatting 2025-11-17 17:27:08 -06:00
J. Nick Koston
fdc7ae7760 [wifi] Skip redundant setter calls for default values (#11943) 2025-11-17 17:20:32 -06:00
J. Nick Koston
1a73f49cd2 [number] Modernize to C++17 nested namespaces (#11945) 2025-11-17 17:20:18 -06:00
dependabot[bot]
23f85162d0 Bump actions/checkout from 5.0.0 to 5.0.1 (#11957)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 15:39:01 -06:00
dependabot[bot]
7a238028a7 Bump ruamel-yaml-clib from 0.2.14 to 0.2.15 (#11956)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-17 15:38:44 -06:00
J. Nick Koston
5b9d2e5e35 Merge branch 'dev' into timeout_filter_scheduler_churn_fix 2025-11-17 15:12:59 -06:00
Jonathan Swoboda
3d6c361037 [core] Add support for setting environment variables (#11953) 2025-11-17 12:32:08 -05:00
J. Nick Koston
f31a29272e Merge branch 'integration' into memory_api 2025-11-17 09:36:09 -06:00
J. Nick Koston
adf75630fe Merge branch 'device_info_less_alloc' into integration 2025-11-17 09:36:02 -06:00
J. Nick Koston
539597209f [api] Reduce heap allocations in DeviceInfoResponse 2025-11-17 09:35:05 -06:00
J. Nick Koston
44eb4c581c Merge branch 'integration' into memory_api 2025-11-17 09:21:02 -06:00
J. Nick Koston
8b1f3b2b08 Merge branch 'bh1750_loop' into integration 2025-11-17 09:20:55 -06:00
J. Nick Koston
70e44cd5a6 Merge branch 'integration' into memory_api 2025-11-17 09:13:38 -06:00
J. Nick Koston
499ad18475 Merge branch 'dashboard_import_url_store_rodata' into integration 2025-11-17 09:13:30 -06:00
J. Nick Koston
0afaf182da Merge branch 'dev' into dashboard_import_url_store_rodata 2025-11-17 09:12:57 -06:00
J. Nick Koston
43f2405dc3 [dashboard_import] Store package import URL in .rodata instead of RAM 2025-11-17 09:10:51 -06:00
J. Nick Koston
41ac12a0e1 Update esphome/components/bh1750/bh1750.cpp 2025-11-17 08:48:42 -06:00
J. Nick Koston
a6f416a09e Update esphome/components/bh1750/bh1750.cpp 2025-11-17 08:48:13 -06:00
J. Nick Koston
64b9e23728 Merge branch 'integration' into memory_api 2025-11-17 08:34:47 -06:00
J. Nick Koston
c155dbb4e6 Merge branch 'bh1750_loop' into integration 2025-11-17 08:34:37 -06:00
Javier Peletier
9e1f8d83f8 [config] Support !remove and !extend with LVGL-style configs (#11534) 2025-11-17 18:03:11 +11:00
Jesse Hills
fa0aa6defc Merge branch 'beta' into dev 2025-11-17 17:41:46 +13:00
Jesse Hills
70366d2124 Merge pull request #11944 from esphome/bump-2025.11.0b3
2025.11.0b3
2025-11-17 17:41:11 +13:00
J. Nick Koston
78a69cb744 tidy 2025-11-16 22:33:59 -06:00
J. Nick Koston
9b14444dad tidy 2025-11-16 22:30:59 -06:00
J. Nick Koston
8934d4b498 touch ups 2025-11-16 22:08:44 -06:00
J. Nick Koston
9b107e7f2a touch ups 2025-11-16 22:05:33 -06:00
J. Nick Koston
7edfdf9e65 Merge branch 'integration' into memory_api 2025-11-16 21:00:29 -06:00
J. Nick Koston
11b53800fb Merge branch 'number_namespaces' into integration 2025-11-16 21:00:21 -06:00
J. Nick Koston
bbd12609af Merge remote-tracking branch 'upstream/dev' into integration 2025-11-16 21:00:03 -06:00
J. Nick Koston
23be236133 [number] Modernize to C++17 nested namespaces 2025-11-16 20:54:43 -06:00
J. Nick Koston
10bdb47eae [cover] Modernize to C++17 nested namespaces (#11935) 2025-11-16 20:37:06 -06:00
Jesse Hills
a38c4e0c6e Bump version to 2025.11.0b3 2025-11-17 15:32:09 +13:00
Anton Sergunov
6c6b03bda0 [uart] Setup uart pins only if flags are set (#11914)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-17 15:32:09 +13:00
J. Nick Koston
9e02e31917 [web_server_idf] Fix lwIP assertion crash by shutting down sockets on connection close (#11937) 2025-11-17 15:32:09 +13:00
J. Nick Koston
3fd58f1a91 [web_server.ota] Merge multiple instances to prevent undefined behavior (#11905) 2025-11-17 15:32:09 +13:00
J. Nick Koston
9151489481 [sntp] Merge multiple instances to fix crash and undefined behavior (#11904) 2025-11-17 15:32:09 +13:00
J. Nick Koston
f19296ac7f [analyze-memory] Show all core symbols > 100 B instead of top 15 (#11909) 2025-11-17 15:32:09 +13:00
J. Nick Koston
36868ee7b1 [scheduler] Fix timing breakage after 49 days of uptime on ESP8266/RP2040 (#11924) 2025-11-17 15:32:09 +13:00
J. Nick Koston
d559f9f52e [ld2410] Add timeout filter to prevent stuck targets (#11920) 2025-11-17 15:32:09 +13:00
J. Nick Koston
6440b5fbf5 [ld2412] Fix stuck targets by adding timeout filter (#11919) 2025-11-17 15:32:09 +13:00
Jonathan Swoboda
97c4914573 [uart] Improve error handling and validate buffer size (#11895)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-17 15:32:09 +13:00
Edward Firmo
7ce94c27fe [wifi] Allow use_psram with Arduino (#11902) 2025-11-17 15:32:09 +13:00
Edward Firmo
eb54c0026d [light] Fix missing ColorMode::BRIGHTNESS case in logging (#11836) 2025-11-17 15:32:09 +13:00
Clyde Stubbs
fe00e209ff [esp32] Add sdkconfig flag to make OTA work for 32MB flash (#11883)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-17 15:32:08 +13:00
Clyde Stubbs
aed80732f9 [esp32] Make esp-idf default framework for P4 (#11884) 2025-11-17 15:32:08 +13:00
Anton Sergunov
aa097a2fe6 [uart] Setup uart pins only if flags are set (#11914)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-17 14:25:00 +13:00
J. Nick Koston
3b860e784c [web_server_idf] Fix lwIP assertion crash by shutting down sockets on connection close (#11937) 2025-11-17 13:39:01 +13:00
J. Nick Koston
96ee38759d [web_server.ota] Merge multiple instances to prevent undefined behavior (#11905) 2025-11-17 13:38:52 +13:00
J. Nick Koston
986d3c8f13 [sntp] Merge multiple instances to fix crash and undefined behavior (#11904) 2025-11-17 13:38:38 +13:00
J. Nick Koston
c4c1de915a Merge branch 'integration' into memory_api 2025-11-16 15:55:18 -06:00
J. Nick Koston
b8c216c646 Merge branch 'dev' into integration 2025-11-16 15:55:11 -06:00
Clyde Stubbs
320120883c [lvgl] Migrate lv_font creation into Font class and optimise (#11915) 2025-11-17 08:47:54 +11:00
J. Nick Koston
46ea962e4f Merge branch 'integration' into memory_api 2025-11-16 13:04:08 -06:00
J. Nick Koston
76546bade7 Merge branch 'combine_name_object_id' into integration 2025-11-16 13:04:00 -06:00
J. Nick Koston
8997fb3443 [core] Reduce flash size by combining set_name() and set_object_id() calls 2025-11-16 13:02:59 -06:00
J. Nick Koston
af58909bd7 Merge branch 'integration' into memory_api 2025-11-16 12:48:04 -06:00
J. Nick Koston
094ed59230 Merge branch 'de_dupe_lam' into integration 2025-11-16 12:47:44 -06:00
J. Nick Koston
5edcb62f6e Merge branch 'integration' into memory_api 2025-11-16 11:58:08 -06:00
J. Nick Koston
8512266068 Merge branch 'libretiny_no_strlen' into integration 2025-11-16 11:58:02 -06:00
J. Nick Koston
4c9d903773 [logger] Eliminate strlen overhead on LibreTiny 2025-11-16 11:56:52 -06:00
J. Nick Koston
fd0d1c41b7 Merge branch 'integration' into memory_api 2025-11-16 09:19:04 -06:00
J. Nick Koston
d878e9a8f2 Merge remote-tracking branch 'upstream/web_server_shutdown_race_fix' into integration 2025-11-16 09:18:58 -06:00
J. Nick Koston
02c5f18b5d [web_server_idf] Fix lwIP assertion crash by shutting down sockets on connection close 2025-11-16 09:18:07 -06:00
J. Nick Koston
a913e7df33 handles newlines, add test to prove it 2025-11-16 08:16:41 -06:00
J. Nick Koston
4fc4da6ed2 [analyze-memory] Show all core symbols > 100 B instead of top 15 (#11909) 2025-11-16 07:35:31 -06:00
J. Nick Koston
014bdd1ed0 Merge branch 'dev' into timeout_filter_scheduler_churn_fix 2025-11-15 22:21:57 -06:00
J. Nick Koston
6f4042f401 Add tests for sensor timeout filters (#11923) 2025-11-15 22:21:38 -06:00
J. Nick Koston
ea2b4c3e25 [binary_sensor] Modernize to C++17 nested namespaces and remove redundant qualifications (#11929) 2025-11-16 04:21:06 +00:00
J. Nick Koston
fc546ca3f6 [scheduler] Fix timing breakage after 49 days of uptime on ESP8266/RP2040 (#11924) 2025-11-15 22:20:57 -06:00
J. Nick Koston
6b158e760d [ld2410] Add timeout filter to prevent stuck targets (#11920) 2025-11-15 22:04:25 -06:00
J. Nick Koston
5710cab972 [ld2412] Fix stuck targets by adding timeout filter (#11919) 2025-11-15 22:03:43 -06:00
J. Nick Koston
bfea4220dc Merge branch 'integration' into memory_api 2025-11-15 21:34:05 -06:00
J. Nick Koston
027ede7ca2 Merge branch 'binary_sensor_namespace_cleanup' into integration 2025-11-15 21:33:54 -06:00
J. Nick Koston
6d03afecd0 [binary_sensor] Modernize to C++17 nested namespaces and remove redundant qualifications 2025-11-15 21:32:46 -06:00
Clyde Stubbs
eb759efb3d [font] Store glyph data in flash only (#11926) 2025-11-16 12:48:02 +11:00
J. Nick Koston
7aae4b4fce Merge branch 'integration' into memory_api 2025-11-15 18:43:54 -06:00
J. Nick Koston
3d9390498b Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:43:48 -06:00
J. Nick Koston
d60c358f48 preen 2025-11-15 18:43:39 -06:00
J. Nick Koston
1138495efa Merge branch 'integration' into memory_api 2025-11-15 18:36:56 -06:00
J. Nick Koston
f725877b0e Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:36:51 -06:00
J. Nick Koston
26b820272a optimize esp8266 as well 2025-11-15 18:36:39 -06:00
J. Nick Koston
d4648b51ab Merge branch 'integration' into memory_api 2025-11-15 18:31:34 -06:00
J. Nick Koston
e20d89d190 Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:31:25 -06:00
J. Nick Koston
9557c90c20 comment 2025-11-15 18:31:07 -06:00
J. Nick Koston
50faae2d3c Merge branch 'integration' into memory_api 2025-11-15 18:18:11 -06:00
J. Nick Koston
693b27a190 Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:18:04 -06:00
J. Nick Koston
d64bcf27b3 cleanup 2025-11-15 18:17:50 -06:00
J. Nick Koston
61520726ad Merge branch 'integration' into memory_api 2025-11-15 18:15:26 -06:00
J. Nick Koston
47d1081ebc Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:15:21 -06:00
J. Nick Koston
d5d61546e7 cleanup 2025-11-15 18:15:10 -06:00
J. Nick Koston
7289a4e2c6 Merge branch 'integration' into memory_api 2025-11-15 18:03:53 -06:00
J. Nick Koston
0b33ba606c Merge branch 'reduce_logger_locking' into integration 2025-11-15 18:03:44 -06:00
J. Nick Koston
554cdbd5a4 bot is right 2025-11-15 18:03:08 -06:00
J. Nick Koston
8ec14bd57c bot is right 2025-11-15 18:02:54 -06:00
J. Nick Koston
a8a3e4d157 Merge branch 'integration' into memory_api 2025-11-15 17:42:14 -06:00
J. Nick Koston
0b132f9569 Merge branch 'reduce_logger_locking' into integration 2025-11-15 17:42:10 -06:00
J. Nick Koston
0d147e5d10 missed one 2025-11-15 17:42:01 -06:00
J. Nick Koston
a552e1d328 Merge branch 'integration' into memory_api 2025-11-15 17:37:49 -06:00
J. Nick Koston
46ddd253bd Merge branch 'reduce_logger_locking' into integration 2025-11-15 17:37:45 -06:00
J. Nick Koston
730a70ee8b missed header 2025-11-15 17:37:37 -06:00
J. Nick Koston
0f6963de27 Merge branch 'integration' into memory_api 2025-11-15 17:36:44 -06:00
J. Nick Koston
1b19e4e8ad Merge branch 'reduce_logger_locking' into integration 2025-11-15 17:36:37 -06:00
J. Nick Koston
d096f1192d make bot happy 2025-11-15 17:35:41 -06:00
J. Nick Koston
b14bab1fce make bot happy 2025-11-15 17:35:32 -06:00
J. Nick Koston
d84976715b Merge branch 'integration' into memory_api 2025-11-15 17:20:01 -06:00
J. Nick Koston
ae985bfb07 Merge branch 'reduce_logger_locking' into integration 2025-11-15 17:19:55 -06:00
J. Nick Koston
88a23acc4b tweak 2025-11-15 17:19:37 -06:00
J. Nick Koston
950dff1a38 [logger] Reduce ESP32 UART mutex overhead by 50% 2025-11-15 16:54:18 -06:00
J. Nick Koston
61eddfdcda [logger] Reduce ESP32 UART mutex overhead by 50% 2025-11-15 16:47:35 -06:00
J. Nick Koston
13ac071482 Merge branch 'integration' into memory_api 2025-11-15 15:35:53 -06:00
J. Nick Koston
0f10b9d76f Merge branch 'single_model_rollover_fix' into integration 2025-11-15 15:35:43 -06:00
J. Nick Koston
c61411c620 [scheduler] Fix timing breakage after 49 days of uptime on ESP8266/RP2040 2025-11-15 14:42:06 -06:00
J. Nick Koston
6a05c64e2a Merge branch 'sensor_timeout_filter' into timeout_filter_scheduler_churn_fix 2025-11-15 13:11:37 -06:00
J. Nick Koston
af77dfeacc helper 2025-11-15 13:11:04 -06:00
J. Nick Koston
aca74e34b8 Add tests for sensor timeout filters
ahead of optimization effort in https://github.com/esphome/esphome/pull/11922
2025-11-15 13:07:56 -06:00
J. Nick Koston
6f5f45f1e9 cover 2025-11-15 13:06:54 -06:00
J. Nick Koston
6cca3617d8 cover 2025-11-15 13:06:06 -06:00
J. Nick Koston
894ba341ba [sensor] Replace timeout filter scheduler with loop-based implementation 2025-11-15 12:56:25 -06:00
J. Nick Koston
e8e06db260 Merge branch 'integration' into memory_api 2025-11-15 12:26:53 -06:00
J. Nick Koston
219206057f Merge branch 'de_dupe_lam' into integration 2025-11-15 12:26:47 -06:00
J. Nick Koston
f6378990cd add tests for crazy edge cases 2025-11-15 12:19:06 -06:00
J. Nick Koston
5090762d5a Merge branch 'integration' into memory_api 2025-11-15 12:12:36 -06:00
J. Nick Koston
e604ec267e Merge remote-tracking branch 'origin/switch_to_std_index_sequence' into integration 2025-11-15 12:12:21 -06:00
J. Nick Koston
ae343a94ca disable around old code 2025-11-15 12:11:50 -06:00
J. Nick Koston
2229996c22 Merge branch 'memory_api' of https://github.com/esphome/esphome into memory_api 2025-11-15 12:09:18 -06:00
J. Nick Koston
b7d4e01fa2 Merge branch 'integration' into memory_api 2025-11-15 12:07:02 -06:00
J. Nick Koston
25c7be3970 Merge branch 'de_dupe_lam' into integration 2025-11-15 12:06:57 -06:00
J. Nick Koston
849c9b1625 Merge branch 'memory_api' of https://github.com/esphome/esphome into memory_api 2025-11-15 12:06:34 -06:00
J. Nick Koston
1c10485cee Merge branch 'integration' into memory_api 2025-11-15 12:06:27 -06:00
J. Nick Koston
8e6747c00e Merge branch 'switch_to_std_index_sequence' into integration 2025-11-15 12:06:22 -06:00
J. Nick Koston
d7892f2289 [core] Replace seq<>/gens<> with std::index_sequence for code clarity 2025-11-15 12:04:49 -06:00
J. Nick Koston
b7f6013378 [core] Replace seq<>/gens<> with std::index_sequence for code clarity 2025-11-15 12:04:02 -06:00
J. Nick Koston
fb9e7028a0 [core] Replace seq<>/gens<> with std::index_sequence for code clarity 2025-11-15 11:58:24 -06:00
J. Nick Koston
e9ff4d3c4e handle static 2025-11-15 11:47:35 -06:00
J. Nick Koston
35b6395449 Merge branch 'integration' into memory_api 2025-11-15 11:03:05 -06:00
J. Nick Koston
f29b191804 Merge branch 'ld2410_missing_timeout' into integration 2025-11-15 11:02:51 -06:00
J. Nick Koston
734f96140f Merge branch 'ld2412_missing_timeout' into integration 2025-11-15 11:02:46 -06:00
J. Nick Koston
ed60d8668e [ld2410] Add timeout filter to prevent stuck targets 2025-11-15 10:56:17 -06:00
J. Nick Koston
7892adb948 [ld2412] Fix stuck targets by adding timeout filter 2025-11-15 10:52:49 -06:00
J. Nick Koston
96ea6e8059 Merge branch 'integration' into memory_api 2025-11-15 10:43:19 -06:00
J. Nick Koston
107a0a23b1 Merge branch 'de_dupe_lam' into integration 2025-11-15 10:43:08 -06:00
J. Nick Koston
4081345013 address bot review 2025-11-15 10:42:57 -06:00
J. Nick Koston
3dd570fdd0 address bot review 2025-11-15 10:42:44 -06:00
J. Nick Koston
04f445dfaf Merge branch 'integration' into memory_api 2025-11-15 10:27:05 -06:00
J. Nick Koston
82d04c1548 Merge branch 'de_dupe_lam' into integration 2025-11-15 10:26:48 -06:00
J. Nick Koston
5989b78e93 preen 2025-11-15 10:25:57 -06:00
J. Nick Koston
5727043cec preen 2025-11-15 10:24:38 -06:00
J. Nick Koston
1441c7fab2 preen 2025-11-15 10:21:58 -06:00
J. Nick Koston
62248b6bba rpeen 2025-11-15 10:20:53 -06:00
J. Nick Koston
86833cbc3c rpeen 2025-11-15 10:20:40 -06:00
J. Nick Koston
6067ca36f7 Merge branch 'integration' into memory_api 2025-11-15 10:15:47 -06:00
J. Nick Koston
a98d2fa266 Merge branch 'de_dupe_lam' into integration 2025-11-15 10:15:40 -06:00
J. Nick Koston
b7c105125e proper codegen 2025-11-15 10:13:43 -06:00
J. Nick Koston
11de948698 proper codegen 2025-11-15 10:12:36 -06:00
J. Nick Koston
6ade327cde update tests 2025-11-15 10:05:27 -06:00
J. Nick Koston
cc1b547ad2 der dupe lam 2025-11-14 22:27:23 -06:00
J. Nick Koston
d1f3979c7f Merge branch 'integration' into memory_api 2025-11-14 20:26:28 -06:00
J. Nick Koston
25408dc445 Merge branch 'delay_action_avoid_bind_no_args' into integration 2025-11-14 20:18:15 -06:00
J. Nick Koston
f1bc3c68dd [core] Optimize DelayAction for no-argument case using if constexpr 2025-11-14 20:09:38 -06:00
J. Nick Koston
f8191410e3 [core] Optimize DelayAction for no-argument case using if constexpr 2025-11-14 20:05:43 -06:00
J. Nick Koston
90ba8ecacd Merge branch 'integration' into memory_api 2025-11-14 19:22:10 -06:00
J. Nick Koston
2f354a9c32 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-14 19:21:57 -06:00
dependabot[bot]
1df996601d Bump ruff from 0.14.4 to 0.14.5 (#11910)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
2025-11-14 19:14:07 +00:00
J. Nick Koston
c25b87350d Merge branch 'integration' into memory_api 2025-11-14 13:13:47 -06:00
J. Nick Koston
db826b4a2b Merge branch 'dev' into integration 2025-11-14 13:13:36 -06:00
dependabot[bot]
c32891ec02 Bump github/codeql-action from 4.31.2 to 4.31.3 (#11911)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-14 13:09:59 -06:00
Jonathan Swoboda
2bf6d48fcf [uart] Improve error handling and validate buffer size (#11895)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-14 14:06:08 -05:00
J. Nick Koston
51eb15bf8c Merge branch 'integration' into memory_api 2025-11-14 11:31:00 -06:00
J. Nick Koston
e19a99dd7f Merge branch 'analyze_memory_missing_symbols' into integration 2025-11-14 11:30:54 -06:00
J. Nick Koston
6666911ebf [analyze-memory] Show all core symbols > 100 B instead of top 15 2025-11-14 11:29:36 -06:00
J. Nick Koston
b890f097cf Merge branch 'integration' into memory_api 2025-11-14 09:03:31 -06:00
J. Nick Koston
5af5a86970 Merge branch 'sntp_single_instance' into integration 2025-11-14 09:02:00 -06:00
J. Nick Koston
3de847014b Merge branch 'webserver_ota_single_instance' into integration 2025-11-14 09:01:56 -06:00
J. Nick Koston
5f10fbc4f6 [web_server.ota] Merge multiple instances to prevent undefined behavior 2025-11-14 08:59:05 -06:00
J. Nick Koston
e8f2e91db3 [sntp] Merge multiple instances to fix crash and undefined behavior 2025-11-14 08:47:15 -06:00
Edward Firmo
e49a943cf7 [wifi] Allow use_psram with Arduino (#11902) 2025-11-14 09:13:48 -05:00
dependabot[bot]
67524e14ee Bump pylint from 4.0.2 to 4.0.3 (#11894)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-13 19:05:02 +00:00
J. Nick Koston
6370132cbb Merge branch 'integration' into memory_api 2025-11-13 12:38:14 -06:00
J. Nick Koston
3c0969d8a4 Merge branch 'template_alarm_control_panel_only_iterates' into integration 2025-11-13 12:38:08 -06:00
J. Nick Koston
1f408ce41c [template.alarm_control_panel] Use FixedVector for iteration-only sensor storage 2025-11-13 12:35:43 -06:00
Edward Firmo
2290eb0dd2 [light] Fix missing ColorMode::BRIGHTNESS case in logging (#11836) 2025-11-13 12:08:06 -06:00
J. Nick Koston
e1ed7f7fd0 Merge branch 'integration' into memory_api 2025-11-13 11:55:47 -06:00
J. Nick Koston
79b97452b7 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-13 11:55:39 -06:00
Clyde Stubbs
0afcf67c32 [esp32] Add sdkconfig flag to make OTA work for 32MB flash (#11883)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
2025-11-13 10:52:08 -05:00
Clyde Stubbs
952bdfaac2 [esp32] Make esp-idf default framework for P4 (#11884) 2025-11-13 09:55:48 -05:00
Jesse Hills
ed7e5cd325 Bump version to 2025.12.0-dev 2025-11-13 17:00:47 +13:00
J. Nick Koston
eefda8ce16 Merge branch 'integration' into memory_api 2025-11-12 21:50:25 -06:00
J. Nick Koston
9f5a6017af Merge branch 'light_loop' into integration 2025-11-12 21:50:20 -06:00
J. Nick Koston
20649ce8ce safer 2025-11-12 21:49:58 -06:00
Jonathan Swoboda
a15f46e741 Merge branch 'beta' into dev 2025-11-12 22:46:34 -05:00
Jonathan Swoboda
050a27a409 Merge pull request #11880 from esphome/bump-2025.11.0b2
2025.11.0b2
2025-11-12 22:46:23 -05:00
J. Nick Koston
2592119138 Merge branch 'integration' into memory_api 2025-11-12 21:30:59 -06:00
J. Nick Koston
8c9d1cc392 Merge branch 'light_loop' into integration 2025-11-12 21:30:53 -06:00
J. Nick Koston
9b458d25ea light loop 2025-11-12 21:20:11 -06:00
J. Nick Koston
4e23a7a3e1 light loop 2025-11-12 21:11:45 -06:00
Jonathan Swoboda
382483b063 Bump version to 2025.11.0b2 2025-11-12 21:56:11 -05:00
J. Nick Koston
1675408161 [wifi] Fix slow reconnection after connection loss for all network types (#11873)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 21:56:11 -05:00
J. Nick Koston
1d8b08dcce [wifi][ethernet] Fix spurious warnings and unclear status after PR #9823 (#11871) 2025-11-12 21:56:11 -05:00
J. Nick Koston
afed581079 [light] Fix dangling reference in compute_color_mode causing memory corruption (#11868) 2025-11-12 21:56:11 -05:00
J. Nick Koston
ff107a0674 [mqtt] Fix crash with empty broker during upload/logs (#11866)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 21:56:11 -05:00
J. Nick Koston
72da3d0f1e [thermostat] Replace std::map with FixedVector, reduce flash usage (#11875) 2025-11-12 21:56:11 -05:00
J. Nick Koston
5a2e6697e0 [api][event] Send events immediately to prevent loss during rapid triggers (#11777) 2025-11-12 21:56:11 -05:00
J. Nick Koston
799cfe1de4 [esp32_ble_tracker] Use initializer_list to eliminate compiler warning and reduce flash usage (#11861) 2025-11-12 21:56:11 -05:00
J. Nick Koston
6df0264d51 [api] Eliminate heap allocations when transmitting Event types (#11773) 2025-11-12 21:56:11 -05:00
J. Nick Koston
a859ecaad1 [core] Fix wait_until hanging when used in on_boot automations (#11869) 2025-11-12 21:56:11 -05:00
Jonathan Swoboda
4f088c93c9 [esp32] Update the recommended platform to 55.03.31-2 (#11865) 2025-11-12 21:56:11 -05:00
J. Nick Koston
a1ab19d127 [ci] Reduce release time by removing 21 redundant ESP32-S3 IDF tests (#11850) 2025-11-12 21:56:11 -05:00
J. Nick Koston
47a3e5e78b Merge branch 'integration' into memory_api 2025-11-12 20:09:05 -06:00
J. Nick Koston
f196b1c867 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-12 20:08:51 -06:00
tomaszduda23
d869108416 [nrf52] add settings for dcdc converter (#11841) 2025-11-12 20:06:20 -06:00
J. Nick Koston
2d6618da3c [wifi] Fix slow reconnection after connection loss for all network types (#11873)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-13 13:44:22 +13:00
J. Nick Koston
47fe84e922 [wifi][ethernet] Fix spurious warnings and unclear status after PR #9823 (#11871) 2025-11-13 13:43:51 +13:00
J. Nick Koston
735bf9930a [light] Fix dangling reference in compute_color_mode causing memory corruption (#11868) 2025-11-13 13:41:28 +13:00
J. Nick Koston
769137fc09 [mqtt] Fix crash with empty broker during upload/logs (#11866)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-13 13:40:26 +13:00
J. Nick Koston
3a5b3ad77d [thermostat] Replace std::map with FixedVector, reduce flash usage (#11875) 2025-11-12 17:55:06 -06:00
J. Nick Koston
859101ddc9 [api][event] Send events immediately to prevent loss during rapid triggers (#11777) 2025-11-13 12:42:50 +13:00
J. Nick Koston
f19abab93f Merge branch 'thermostat_storage' into memory_api 2025-11-12 15:01:19 -06:00
J. Nick Koston
b8717fee4e Merge branch 'thermostat_storage' into integration 2025-11-12 15:01:13 -06:00
J. Nick Koston
4eb471b316 tweaks 2025-11-12 15:01:05 -06:00
J. Nick Koston
b017e034ee tweaks 2025-11-12 15:00:52 -06:00
J. Nick Koston
9a2574a2fe Merge branch 'integration' into memory_api 2025-11-12 14:56:02 -06:00
J. Nick Koston
72513897cc Merge branch 'thermostat_storage' into integration 2025-11-12 14:55:55 -06:00
J. Nick Koston
20388ce848 [thermostat] Replace std::map with FixedVector, reduce flash usage 2025-11-12 14:54:23 -06:00
J. Nick Koston
72185ac01f Merge branch 'integration' into memory_api 2025-11-12 14:32:28 -06:00
J. Nick Koston
9e8e5fd8aa Merge branch 'no_batch_events' into integration 2025-11-12 14:32:19 -06:00
J. Nick Koston
8a71a6bfdc Merge remote-tracking branch 'upstream/dev' into no_batch_events 2025-11-12 14:31:26 -06:00
J. Nick Koston
29a50da635 [wifi] Use stack allocation for BSSID formatting in logging (#11859) 2025-11-12 14:27:06 -06:00
J. Nick Koston
5f0fa68d73 [esp32_ble] Use stack allocation for MAC formatting in dump_config (#11860) 2025-11-12 14:26:57 -06:00
J. Nick Koston
2f39b10baa [esp32_ble_tracker] Use initializer_list to eliminate compiler warning and reduce flash usage (#11861) 2025-11-12 14:26:46 -06:00
J. Nick Koston
5a550cc579 [api] Eliminate heap allocations when transmitting Event types (#11773) 2025-11-12 14:26:36 -06:00
J. Nick Koston
4b58cb4ce6 [wifi] Pass ManualIP by const reference to reduce stack usage (#11858) 2025-11-12 14:01:19 -06:00
J. Nick Koston
3872a2fd91 [captive_portal] Warn when enabled without WiFi AP configured (#11856) 2025-11-12 14:01:07 -06:00
dependabot[bot]
5d613ada83 Bump pytest from 9.0.0 to 9.0.1 (#11874)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-11-12 14:00:50 -06:00
J. Nick Koston
53dacef4a6 Merge branch 'integration' into memory_api 2025-11-12 12:52:01 -06:00
J. Nick Koston
24701d95e5 Merge branch 'wifi_reconnect_fixes' into integration 2025-11-12 12:51:55 -06:00
J. Nick Koston
08127d0225 [wifi] Fix phase transition and error state on reconnection 2025-11-12 12:48:44 -06:00
J. Nick Koston
b28d8a7d22 Merge branch 'integration' into memory_api 2025-11-12 12:18:25 -06:00
J. Nick Koston
e7a5790276 Merge branch 'wifi_ethernet_now_connected_later_logconfig' into integration 2025-11-12 12:18:19 -06:00
J. Nick Koston
97d2f5ee25 [wifi][ethernet] Fix spurious warnings and unclear status after PR #9823 2025-11-12 12:17:47 -06:00
J. Nick Koston
9accb16b4a Merge branch 'integration' into memory_api 2025-11-12 12:02:04 -06:00
J. Nick Koston
8c0c38be21 Merge remote-tracking branch 'upstream/dev' into integration 2025-11-12 12:01:57 -06:00
J. Nick Koston
8037dbe2d3 Merge branch 'color_mode_dangling_ref_fix' into integration 2025-11-12 12:01:53 -06:00
J. Nick Koston
6395439d33 Merge branch 'mqtt_raise_early_invalid_host' into integration 2025-11-12 12:01:50 -06:00
J. Nick Koston
9de80b635a [core] Fix wait_until hanging when used in on_boot automations (#11869) 2025-11-12 17:56:19 +00:00
J. Nick Koston
c299361753 some basic tests 2025-11-12 11:51:56 -06:00
J. Nick Koston
4b3d3c4ca2 some basic tests 2025-11-12 11:51:35 -06:00
J. Nick Koston
8ce4d5cd4f by value 2025-11-12 10:39:18 -06:00
J. Nick Koston
c1fb8dae37 [light] Fix dangling reference in compute_color_mode causing memory corruption 2025-11-12 10:33:19 -06:00
Jonathan Swoboda
748aee584a [esp32] Update the recommended platform to 55.03.31-2 (#11865) 2025-11-12 10:41:22 -05:00
J. Nick Koston
d8454e7c0a Update esphome/mqtt.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-12 09:33:29 -06:00
J. Nick Koston
fb00f75192 [mqtt] Fix crash with empty broker during upload/logs 2025-11-12 09:30:46 -06:00
J. Nick Koston
1b487988c9 [mqtt] Fix crash with empty broker during upload/logs 2025-11-12 09:29:40 -06:00
Jonathan Swoboda
3cbfddcc83 Merge branch 'beta' into dev 2025-11-11 23:27:24 -05:00
Jonathan Swoboda
1d71b6b93e Merge pull request #11862 from esphome/bump-2025.11.0b1
2025.11.0b1
2025-11-11 23:27:12 -05:00
J. Nick Koston
398dba4fc8 [ci] Reduce release time by removing 21 redundant ESP32-S3 IDF tests (#11850) 2025-11-12 16:44:19 +13:00
Jonathan Swoboda
298813d4fa Bump version to 2025.11.0b1 2025-11-11 22:14:22 -05:00
J. Nick Koston
fd308a0687 Merge branch 'integration' into memory_api 2025-11-11 20:42:44 -06:00
J. Nick Koston
016de16181 Merge branch 'ble_mac_format' into integration 2025-11-11 20:42:39 -06:00
J. Nick Koston
0d46bc57d6 [esp32_ble] Use stack allocation for MAC formatting in dump_config 2025-11-11 20:42:14 -06:00
J. Nick Koston
0c506570a6 Merge branch 'integration' into memory_api 2025-11-11 20:38:55 -06:00
J. Nick Koston
c0507b2ad0 Merge branch 'bssid_logging_cleanup' into integration 2025-11-11 20:38:50 -06:00
J. Nick Koston
7cefb8d92c a few more 2025-11-11 20:38:19 -06:00
J. Nick Koston
089eb3bc95 Merge branch 'integration' into memory_api 2025-11-11 20:34:33 -06:00
J. Nick Koston
8de3bcd304 Merge branch 'bssid_logging_cleanup' into integration 2025-11-11 20:34:28 -06:00
J. Nick Koston
32456bee58 Merge remote-tracking branch 'origin/bssid_logging_cleanup' into bssid_logging_cleanup 2025-11-11 20:33:30 -06:00
J. Nick Koston
e104103366 two more 2025-11-11 20:33:20 -06:00
J. Nick Koston
304e0a2c65 Merge branch 'dev' into bssid_logging_cleanup 2025-11-11 20:27:30 -06:00
J. Nick Koston
9c871c39b5 Merge branch 'integration' into memory_api 2025-11-11 20:25:52 -06:00
J. Nick Koston
276ef4ee1d Merge branch 'bssid_logging_cleanup' into integration 2025-11-11 20:25:47 -06:00
J. Nick Koston
dd65e39d16 [wifi] Use stack allocation for BSSID formatting in start_connecting 2025-11-11 20:25:18 -06:00
Jonathan Swoboda
56d141c741 Merge branch 'release' into dev 2025-11-11 20:09:55 -05:00
Jonathan Swoboda
47a7f729dd Merge pull request #11857 from esphome/bump-2025.10.5
2025.10.5
2025-11-11 20:09:41 -05:00
J. Nick Koston
904bc11d5b Merge branch 'integration' into memory_api 2025-11-11 19:02:34 -06:00
J. Nick Koston
a6c8319ade Merge branch 'wifi_pass_manualip_by_const_ref' into integration 2025-11-11 19:01:44 -06:00
J. Nick Koston
7c6f6acf60 [wifi] Pass ManualIP by const reference to reduce stack usage 2025-11-11 19:01:11 -06:00
Jonathan Swoboda
7806eb980f Bump version to 2025.12.0-dev 2025-11-11 19:50:47 -05:00
Jonathan Swoboda
a59888224c Bump version to 2025.10.5 2025-11-11 19:44:37 -05:00
Clyde Stubbs
58ad4759f0 [lvgl] Fix rotation with unusual width (#11680) 2025-11-11 19:44:37 -05:00
Clyde Stubbs
87f79290ba [usb_uart] Fixes for transfer queue allocation (#11548) 2025-11-11 19:44:37 -05:00
Jonathan Swoboda
9326d78439 [core] Don't allow python 3.14 (#11527) 2025-11-11 19:44:37 -05:00
Stuart Parmenter
a93887a790 [const] Add CONF_ROWS (#11249) 2025-11-11 19:44:37 -05:00
Kevin Ahrendt
d7fa131a8a [network, psram, speaker wifi] Use CORE.data to enable high performance networking (#11812) 2025-11-11 18:43:06 -06:00
J. Nick Koston
7f40ef971d Merge branch 'integration' into memory_api 2025-11-11 18:39:11 -06:00
J. Nick Koston
0c127b6998 Merge remote-tracking branch 'origin/captive_portal_without_ap' into integration 2025-11-11 18:39:05 -06:00
J. Nick Koston
037620d75a [captive_portal] Warn when enabled without WiFi AP configured 2025-11-11 18:36:35 -06:00
J. Nick Koston
e0e308c396 Merge branch 'integration' into memory_api 2025-11-11 18:10:25 -06:00
J. Nick Koston
0ab3d3da4e Merge remote-tracking branch 'upstream/dev' into integration 2025-11-11 18:10:09 -06:00
J. Nick Koston
79a4444928 [wifi] Conditionally compile manual_ip to save 24-72 bytes RAM (#11833) 2025-11-11 23:27:08 +00:00
J. Nick Koston
572fae5c7d [wifi] Restore two-attempt BSSID filtering for mesh networks (#11844) 2025-11-12 12:12:53 +13:00
J. Nick Koston
5dafaaced4 [wifi] Fix scan and connection failures after adapter restart (#11851)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-11 23:12:10 +00:00
J. Nick Koston
65a303d48f [wifi] Add min_auth_mode configuration option (#11814) 2025-11-11 16:39:55 -06:00
J. Nick Koston
00c71b7236 [wifi] Fix all-hidden networks duplicate attempts and scan skipping (#11848)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-11 22:33:37 +00:00
J. Nick Koston
0ab0563b52 Merge branch 'integration' into memory_api 2025-11-11 16:23:09 -06:00
J. Nick Koston
ccf5591d14 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 16:23:01 -06:00
J. Nick Koston
1c7c559b69 touch ups 2025-11-11 16:22:24 -06:00
J. Nick Koston
6dbd961b3e Merge branch 'integration' into memory_api 2025-11-11 16:20:02 -06:00
J. Nick Koston
088964de4d Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 16:19:57 -06:00
J. Nick Koston
f0a9ee871b keep 2025-11-11 16:19:47 -06:00
J. Nick Koston
f3a3f2e4f7 Merge branch 'integration' into memory_api 2025-11-11 16:15:31 -06:00
J. Nick Koston
3280ce936a Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 16:15:22 -06:00
J. Nick Koston
efe6e58404 clear failure on restart 2025-11-11 16:15:12 -06:00
J. Nick Koston
ef04903a7a [wifi] Change priority type from float to int8_t (#11830) 2025-11-12 11:10:17 +13:00
J. Nick Koston
a2a05ba23a Merge branch 'integration' into memory_api 2025-11-11 16:09:58 -06:00
J. Nick Koston
08ea53633f Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 16:09:53 -06:00
J. Nick Koston
d54179fd12 Merge remote-tracking branch 'origin/fix_scan_failing_after_restart' into fix_scan_failing_after_restart 2025-11-11 16:09:42 -06:00
J. Nick Koston
fb5b37c17a avoid breaking change 2025-11-11 16:09:33 -06:00
J. Nick Koston
9c6d9badf2 Merge branch 'retry_hidden_no_stuck_last_networks_visible' into fix_scan_failing_after_restart 2025-11-11 16:05:01 -06:00
J. Nick Koston
55bdbf60c9 Merge branch 'dev' into retry_hidden_no_stuck_last_networks_visible 2025-11-11 16:04:55 -06:00
J. Nick Koston
a2ec7f622c [wifi] Fix infinite retry loop when no hidden networks and captive portal active (#11831) 2025-11-11 16:04:37 -06:00
J. Nick Koston
c3111b1dd3 Merge branch 'integration' into memory_api 2025-11-11 16:02:24 -06:00
J. Nick Koston
530fc8f030 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 16:02:19 -06:00
J. Nick Koston
a8f253eecf tweaks on failure paths 2025-11-11 16:02:01 -06:00
J. Nick Koston
e85eeb3d99 Merge branch 'integration' into memory_api 2025-11-11 15:58:13 -06:00
J. Nick Koston
64c79f6363 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 15:58:06 -06:00
J. Nick Koston
7b60a8a21a cleanup conflicting logic 2025-11-11 15:55:09 -06:00
J. Nick Koston
42fa0b61a7 cleanup conflicting logic 2025-11-11 15:52:51 -06:00
tomaszduda23
2f91e7bd47 [nrf52] fix boot loop (#11854) 2025-11-11 15:33:53 -06:00
J. Nick Koston
3aed5f5eae Merge branch 'integration' into memory_api 2025-11-11 15:22:11 -06:00
J. Nick Koston
ec79eb3065 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 15:22:05 -06:00
J. Nick Koston
e589542bd3 make message more sane 2025-11-11 15:21:51 -06:00
J. Nick Koston
c804467277 Merge branch 'integration' into memory_api 2025-11-11 15:16:05 -06:00
J. Nick Koston
8ce7f9dfe8 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 15:16:00 -06:00
J. Nick Koston
c3967df6ce tweak 2025-11-11 15:15:41 -06:00
J. Nick Koston
ecb3eecf88 Merge branch 'integration' into memory_api 2025-11-11 15:00:36 -06:00
J. Nick Koston
f0d1cde35c Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 15:00:31 -06:00
J. Nick Koston
191cf1b03c preen 2025-11-11 14:59:12 -06:00
tomaszduda23
80a7c6d3c3 [nrf52,debug] add partition dump (#11839)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-11-11 14:52:41 -06:00
J. Nick Koston
35ecaff089 Merge branch 'integration' into memory_api 2025-11-11 14:24:46 -06:00
J. Nick Koston
374d039f60 Merge branch 'fix_scan_failing_after_restart' into integration 2025-11-11 14:24:40 -06:00
J. Nick Koston
e19bdf63a5 Merge remote-tracking branch 'origin/retry_hidden_no_stuck_last_networks_visible' into fix_scan_failing_after_restart 2025-11-11 14:22:56 -06:00
J. Nick Koston
1bde521380 cleanups 2025-11-11 14:05:44 -06:00
J. Nick Koston
db9af4a862 cleanup 2025-11-11 14:00:39 -06:00
J. Nick Koston
d092e59a79 Merge branch 'dev' into retry_hidden_no_stuck_last_networks_visible 2025-11-11 13:56:26 -06:00
J. Nick Koston
5a77f63103 Merge remote-tracking branch 'upstream/dev' into fix_scan_failing_after_restart 2025-11-11 13:55:58 -06:00
J. Nick Koston
f6ac916bb2 cleanups 2025-11-11 13:55:43 -06:00
CzBiX
7a92565a0c [lvgl] Fix compile when using transform_zoom (#11845) 2025-11-12 06:24:52 +11:00
J. Nick Koston
93f8e40111 Fix scan failing after restart 2025-11-11 13:13:28 -06:00
J. Nick Koston
99bb6ead7e Merge branch 'dev' into no_batch_events 2025-11-09 22:04:58 -06:00
J. Nick Koston
d171406dff Merge branch 'dev' into no_batch_events 2025-11-09 17:35:33 -06:00
J. Nick Koston
65fd784fa7 tidy 2025-11-08 10:39:09 -06:00
J. Nick Koston
b9f208b63a [api][event] Send events immediately to prevent loss during rapid triggers 2025-11-08 10:16:18 -06:00
kbx81
ddef1f9ecd fix 2025-10-21 03:55:22 -05:00
kbx81
27714e052c fix 2025-10-21 03:30:41 -05:00
kbx81
17bba92111 Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-10-21 02:32:41 -05:00
kbx81
b58a1bfc6c Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-09-22 15:00:31 -05:00
kbx81
24649cd55c Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-09-21 23:32:09 -05:00
kbx81
1b6f3fd0ec Merge remote-tracking branch 'upstream/dev' into 20250915-wifi-info-use-callbacks 2025-09-19 22:11:23 -05:00
Keith Burzinski
5e5f766697 Merge branch 'dev' into 20250915-wifi-info-use-callbacks 2025-09-18 17:54:56 -05:00
Keith Burzinski
946eccb2ee Merge branch 'dev' into 20250915-wifi-info-use-callbacks 2025-09-17 02:21:15 -05:00
kbx81
38719aaef8 tidy 2025-09-16 17:31:30 -05:00
kbx81
eae9335894 [wifi_info] Use callbacks instead of polling 2025-09-15 18:35:25 -05:00
1242 changed files with 33092 additions and 9681 deletions

View File

@@ -276,12 +276,12 @@ This document provides essential context for AI models interacting with this pro
## 7. Specific Instructions for AI Collaboration
* **Contribution Workflow (Pull Request Process):**
1. **Fork & Branch:** Create a new branch in your fork.
1. **Fork & Branch:** Create a new branch based on the `dev` branch (always use `git checkout -b <branch-name> dev` to ensure you're branching from `dev`, not the currently checked out branch).
2. **Make Changes:** Adhere to all coding conventions and patterns.
3. **Test:** Create component tests for all supported platforms and run the full test suite locally.
4. **Lint:** Run `pre-commit` to ensure code is compliant.
5. **Commit:** Commit your changes. There is no strict format for commit messages.
6. **Pull Request:** Submit a PR against the `dev` branch. The Pull Request title should have a prefix of the component being worked on (e.g., `[display] Fix bug`, `[abc123] Add new component`). Update documentation, examples, and add `CODEOWNERS` entries as needed. Pull requests should always be made with the PULL_REQUEST_TEMPLATE.md template filled out correctly.
6. **Pull Request:** Submit a PR against the `dev` branch. The Pull Request title should have a prefix of the component being worked on (e.g., `[display] Fix bug`, `[abc123] Add new component`). Update documentation, examples, and add `CODEOWNERS` entries as needed. Pull requests should always be made using the `.github/PULL_REQUEST_TEMPLATE.md` template - fill out all sections completely without removing any parts of the template.
* **Documentation Contributions:**
* Documentation is hosted in the separate `esphome/esphome-docs` repository.
@@ -402,35 +402,45 @@ This document provides essential context for AI models interacting with this pro
_use_feature = True
```
**Good Pattern (CORE.data with Helpers):**
**Bad Pattern (Flat Keys):**
```python
# Don't do this - keys should be namespaced under component domain
MY_FEATURE_KEY = "my_component_feature"
CORE.data[MY_FEATURE_KEY] = True
```
**Good Pattern (dataclass):**
```python
from dataclasses import dataclass, field
from esphome.core import CORE
# Keys for CORE.data storage
COMPONENT_STATE_KEY = "my_component_state"
USE_FEATURE_KEY = "my_component_use_feature"
DOMAIN = "my_component"
def _get_component_state() -> list:
"""Get component state from CORE.data."""
return CORE.data.setdefault(COMPONENT_STATE_KEY, [])
@dataclass
class MyComponentData:
feature_enabled: bool = False
item_count: int = 0
items: list[str] = field(default_factory=list)
def _get_use_feature() -> bool | None:
"""Get feature flag from CORE.data."""
return CORE.data.get(USE_FEATURE_KEY)
def _get_data() -> MyComponentData:
if DOMAIN not in CORE.data:
CORE.data[DOMAIN] = MyComponentData()
return CORE.data[DOMAIN]
def _set_use_feature(value: bool) -> None:
"""Set feature flag in CORE.data."""
CORE.data[USE_FEATURE_KEY] = value
def request_feature() -> None:
_get_data().feature_enabled = True
def enable_feature():
_set_use_feature(True)
def add_item(item: str) -> None:
_get_data().items.append(item)
```
If you need a real-world example, search for components that use `@dataclass` with `CORE.data` in the codebase. Note: Some components may use `TypedDict` for dictionary-based storage; both patterns are acceptable depending on your needs.
**Why this matters:**
- Module-level globals persist between compilation runs if the dashboard doesn't fork/exec
- `CORE.data` automatically clears between runs
- Typed helper functions provide better IDE support and maintainability
- Encapsulation makes state management explicit and testable
- Namespacing under `DOMAIN` prevents key collisions between components
- `@dataclass` provides type safety and cleaner attribute access
* **Security:** Be mindful of security when making changes to the API, web server, or any other network-related code. Do not hardcode secrets or keys.

View File

@@ -1 +1 @@
3d46b63015d761c85ca9cb77ab79a389509e5776701fb22aed16e7b79d432c0c
94557f94be073390342833aff12ef8676a8b597db5fa770a5a1232e9425cb48f

View File

@@ -7,6 +7,7 @@
- [ ] Bugfix (non-breaking change which fixes an issue)
- [ ] 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

View File

@@ -17,12 +17,12 @@ runs:
steps:
- name: Set up Python ${{ inputs.python-version }}
id: python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: ${{ inputs.python-version }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
# yamllint disable-line rule:line-length

View File

@@ -22,11 +22,11 @@ jobs:
if: github.event.action != 'labeled' || github.event.sender.type != 'Bot'
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@67018539274d69449ef7c02e8e71183d1719ab42 # v2
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
@@ -68,6 +68,7 @@ jobs:
'bugfix',
'new-feature',
'breaking-change',
'developer-breaking-change',
'code-quality'
];
@@ -367,6 +368,7 @@ jobs:
{ pattern: /- \[x\] Bugfix \(non-breaking change which fixes an issue\)/i, label: 'bugfix' },
{ pattern: /- \[x\] New feature \(non-breaking change which adds functionality\)/i, label: 'new-feature' },
{ pattern: /- \[x\] Breaking change \(fix or feature that would cause existing functionality to not work as expected\)/i, label: 'breaking-change' },
{ pattern: /- \[x\] Developer breaking change \(an API change that could break external components\)/i, label: 'developer-breaking-change' },
{ pattern: /- \[x\] Code quality improvements to existing code or addition of tests/i, label: 'code-quality' }
];

View File

@@ -21,9 +21,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.11"
@@ -62,7 +62,7 @@ jobs:
run: git diff
- if: failure()
name: Archive artifacts
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: generated-proto-files
path: |

View File

@@ -21,10 +21,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.11"

View File

@@ -43,13 +43,13 @@ jobs:
- "docker"
# - "lint"
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.11"
- 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
run: |

View File

@@ -49,7 +49,7 @@ jobs:
- name: Check out code from base repository
if: steps.pr.outputs.skip != 'true'
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Always check out from the base repository (esphome/esphome), never from forks
# Use the PR's target branch to ensure we run trusted code from the main repo

View File

@@ -36,18 +36,18 @@ jobs:
cache-key: ${{ steps.cache-key.outputs.key }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Generate cache-key
id: cache-key
run: echo key="${{ hashFiles('requirements.txt', 'requirements_test.txt', '.pre-commit-config.yaml') }}" >> $GITHUB_OUTPUT
- name: Set up Python ${{ env.DEFAULT_PYTHON }}
id: python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: ${{ env.DEFAULT_PYTHON }}
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
# yamllint disable-line rule:line-length
@@ -70,7 +70,7 @@ jobs:
if: needs.determine-jobs.outputs.python-linters == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -91,7 +91,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -132,7 +132,7 @@ jobs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
id: restore-python
uses: ./.github/actions/restore-python
@@ -152,12 +152,12 @@ jobs:
. venv/bin/activate
pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/
- name: Upload coverage to Codecov
uses: codecov/codecov-action@5a1091511ad55cbe89839c7260b706298ca349f7 # v5.5.1
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
with:
token: ${{ secrets.CODECOV_TOKEN }}
- name: Save Python virtual environment cache
if: github.ref == 'refs/heads/dev'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
key: ${{ runner.os }}-${{ steps.restore-python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
@@ -183,7 +183,7 @@ jobs:
component-test-batches: ${{ steps.determine.outputs.component-test-batches }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Fetch enough history to find the merge base
fetch-depth: 2
@@ -193,7 +193,7 @@ jobs:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Restore components graph cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: .temp/components_graph.json
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
- name: Save components graph cache
if: github.ref == 'refs/heads/dev'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: .temp/components_graph.json
key: components-graph-${{ hashFiles('esphome/components/**/*.py') }}
@@ -237,15 +237,15 @@ jobs:
if: needs.determine-jobs.outputs.integration-tests == 'true'
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python 3.13
id: python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.13"
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
@@ -273,7 +273,7 @@ jobs:
if: github.event_name == 'pull_request' && (needs.determine-jobs.outputs.cpp-unit-tests-run-all == 'true' || needs.determine-jobs.outputs.cpp-unit-tests-components != '[]')
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
@@ -321,7 +321,7 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -334,14 +334,14 @@ jobs:
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-${{ matrix.pio_cache_key }}-${{ hashFiles('platformio.ini') }}
@@ -400,7 +400,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -413,14 +413,14 @@ jobs:
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
@@ -489,7 +489,7 @@ jobs:
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Need history for HEAD~1 to work for checking changed files
fetch-depth: 2
@@ -502,14 +502,14 @@ jobs:
- name: Cache platformio
if: github.ref == 'refs/heads/dev'
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
- name: Cache platformio
if: github.ref != 'refs/heads/dev'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-tidyesp32-${{ hashFiles('platformio.ini') }}
@@ -577,7 +577,7 @@ jobs:
version: 1.0
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
@@ -662,13 +662,13 @@ jobs:
if: github.event_name == 'pull_request' && !startsWith(github.base_ref, 'beta') && !startsWith(github.base_ref, 'release')
steps:
- name: Check out code from GitHub
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- uses: esphome/action@43cd1109c09c544d97196f7730ee5b2e0cc6d81e # v3.0.1 fork with pinned actions/cache
- uses: esphome/pre-commit-action@43cd1109c09c544d97196f7730ee5b2e0cc6d81e # v3.0.1 fork with pinned actions/cache
env:
SKIP: pylint,clang-tidy-hash
- uses: pre-commit-ci/lite-action@5d6cc0eb514c891a40562a58a8e71576c5c7fb43 # v1.1.0
@@ -688,7 +688,7 @@ jobs:
skip: ${{ steps.check-script.outputs.skip }}
steps:
- name: Check out target branch
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.base_ref }}
@@ -735,7 +735,7 @@ jobs:
- name: Restore cached memory analysis
id: cache-memory-analysis
if: steps.check-script.outputs.skip != 'true'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: memory-analysis-target.json
key: ${{ steps.cache-key.outputs.cache-key }}
@@ -759,7 +759,7 @@ jobs:
- name: Cache platformio
if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true'
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
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
if: steps.check-script.outputs.skip != 'true' && steps.cache-memory-analysis.outputs.cache-hit != 'true' && steps.build.outcome == 'success'
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/save@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: memory-analysis-target.json
key: ${{ steps.cache-key.outputs.cache-key }}
@@ -821,7 +821,7 @@ jobs:
fi
- name: Upload memory analysis JSON
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: memory-analysis-target
path: memory-analysis-target.json
@@ -840,14 +840,14 @@ jobs:
flash_usage: ${{ steps.extract.outputs.flash_usage }}
steps:
- name: Check out PR branch
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Cache platformio
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
uses: actions/cache/restore@9255dc7a253b0ccc959486e2bca901246202afeb # v5.0.1
with:
path: ~/.platformio
key: platformio-memory-${{ fromJSON(needs.determine-jobs.outputs.memory_impact).platform }}-${{ hashFiles('platformio.ini') }}
@@ -885,7 +885,7 @@ jobs:
--platform "$platform"
- name: Upload memory analysis JSON
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: memory-analysis-pr
path: memory-analysis-pr.json
@@ -908,20 +908,20 @@ jobs:
GH_TOKEN: ${{ github.token }}
steps:
- name: Check out code
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Restore Python
uses: ./.github/actions/restore-python
with:
python-version: ${{ env.DEFAULT_PYTHON }}
cache-key: ${{ needs.common.outputs.cache-key }}
- name: Download target analysis JSON
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: memory-analysis-target
path: ./memory-analysis
continue-on-error: true
- name: Download PR analysis JSON
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
name: memory-analysis-pr
path: ./memory-analysis
@@ -959,13 +959,13 @@ jobs:
- memory-impact-comment
if: always()
steps:
- name: Success
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failure
if: ${{ contains(needs.*.result, 'failure') }}
- name: Check job results
env:
JSON_DOC: ${{ toJSON(needs) }}
NEEDS_JSON: ${{ toJSON(needs) }}
run: |
echo $JSON_DOC | jq
exit 1
# memory-impact-target-branch is allowed to fail without blocking CI.
# This job builds the target branch (dev/beta/release) which may fail because:
# 1. The target branch has a build issue independent of this PR
# 2. This PR fixes a build issue on the target branch
# In either case, we only care that the PR branch builds successfully.
echo "$NEEDS_JSON" | jq -e 'del(.["memory-impact-target-branch"]) | all(.result != "failure")'

View File

@@ -54,11 +54,11 @@ jobs:
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@@ -86,6 +86,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
with:
category: "/language:${{matrix.language}}"

View File

@@ -20,7 +20,7 @@ jobs:
branch_build: ${{ steps.tag.outputs.branch_build }}
deploy_env: ${{ steps.tag.outputs.deploy_env }}
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Get tag
id: tag
# yamllint disable rule:line-length
@@ -60,9 +60,9 @@ jobs:
contents: read
id-token: write
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.x"
- name: Build
@@ -92,14 +92,14 @@ jobs:
os: "ubuntu-24.04-arm"
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Set up Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: "3.11"
- 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
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
@@ -138,7 +138,7 @@ jobs:
# version: ${{ needs.init.outputs.tag }}
- name: Upload digests
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: digests-${{ matrix.platform.arch }}
path: /tmp/digests
@@ -168,17 +168,17 @@ jobs:
- ghcr
- dockerhub
steps:
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Download digests
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
with:
pattern: digests-*
path: /tmp/digests
merge-multiple: true
- 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
if: matrix.registry == 'dockerhub'
@@ -219,10 +219,19 @@ jobs:
- init
- deploy-manifest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: home-assistant-addon
- name: Trigger Workflow
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ secrets.DEPLOY_HA_ADDON_REPO_TOKEN }}
github-token: ${{ steps.generate-token.outputs.token }}
script: |
let description = "ESPHome";
if (context.eventName == "release") {
@@ -245,10 +254,19 @@ jobs:
needs: [init]
environment: ${{ needs.init.outputs.deploy_env }}
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: esphome-schema
- name: Trigger Workflow
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ secrets.DEPLOY_ESPHOME_SCHEMA_REPO_TOKEN }}
github-token: ${{ steps.generate-token.outputs.token }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
@@ -259,3 +277,34 @@ jobs:
version: "${{ needs.init.outputs.tag }}",
}
})
version-notifier:
if: github.repository == 'esphome/esphome' && needs.init.outputs.branch_build == 'false'
runs-on: ubuntu-latest
needs:
- init
- deploy-manifest
steps:
- name: Generate a token
id: generate-token
uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
with:
app-id: ${{ secrets.ESPHOME_GITHUB_APP_ID }}
private-key: ${{ secrets.ESPHOME_GITHUB_APP_PRIVATE_KEY }}
owner: esphome
repositories: version-notifier
- name: Trigger Workflow
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
with:
github-token: ${{ steps.generate-token.outputs.token }}
script: |
github.rest.actions.createWorkflowDispatch({
owner: "esphome",
repo: "version-notifier",
workflow_id: "notify.yml",
ref: "main",
inputs: {
version: "${{ needs.init.outputs.tag }}",
}
})

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Stale
uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0
uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
with:
debug-only: ${{ github.ref != 'refs/heads/dev' }} # Dry-run when not run on dev branch
remove-stale-when-updated: true

View File

@@ -13,16 +13,16 @@ jobs:
if: github.repository == 'esphome/esphome'
steps:
- name: Checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Checkout Home Assistant
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: home-assistant/core
path: lib/home-assistant
- name: Setup Python
uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
with:
python-version: 3.13
@@ -41,7 +41,7 @@ jobs:
python script/run-in-env.py pre-commit run --all-files
- name: Commit changes
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # v8.0.0
with:
commit-message: "Synchronise Device Classes from Home Assistant"
committer: esphomebot <esphome@openhomefoundation.org>

4
.gitignore vendored
View File

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

View File

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

View File

@@ -21,6 +21,7 @@ esphome/components/adc128s102/* @DeerMaximum
esphome/components/addressable_light/* @justfalter
esphome/components/ade7880/* @kpfleming
esphome/components/ade7953/* @angelnu
esphome/components/ade7953_base/* @angelnu
esphome/components/ade7953_i2c/* @angelnu
esphome/components/ade7953_spi/* @angelnu
esphome/components/ads1118/* @solomondg1
@@ -41,6 +42,7 @@ esphome/components/animation/* @syndlex
esphome/components/anova/* @buxtronix
esphome/components/apds9306/* @aodrenah
esphome/components/api/* @esphome/core
esphome/components/aqi/* @freekode @jasstrong @ximex
esphome/components/as5600/* @ammmze
esphome/components/as5600/sensor/* @ammmze
esphome/components/as7341/* @mrgnr
@@ -72,6 +74,7 @@ esphome/components/bl0942/* @dbuezas @dwmw2
esphome/components/ble_client/* @buxtronix @clydebarrow
esphome/components/ble_nus/* @tomaszduda23
esphome/components/bluetooth_proxy/* @bdraco @jesserockz
esphome/components/bm8563/* @abmantis
esphome/components/bme280_base/* @esphome/core
esphome/components/bme280_spi/* @apbodrov
esphome/components/bme680_bsec/* @trvrnrth
@@ -95,6 +98,7 @@ esphome/components/camera_encoder/* @DT-art1
esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @mreditor97
esphome/components/captive_portal/* @esphome/core
esphome/components/cc1101/* @gabest11 @lygris
esphome/components/ccs811/* @habbie
esphome/components/cd74hc4067/* @asoehlke
esphome/components/ch422g/* @clydebarrow @jesterret
@@ -188,6 +192,7 @@ esphome/components/gps/* @coogle @ximex
esphome/components/graph/* @synco
esphome/components/graphical_display_menu/* @MrMDavidson
esphome/components/gree/* @orestismers
esphome/components/gree/switch/* @nagyrobi
esphome/components/grove_gas_mc_v2/* @YorkshireIoT
esphome/components/grove_tb6612fng/* @max246
esphome/components/growatt_solar/* @leeuwte
@@ -202,13 +207,16 @@ esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
esphome/components/hbridge/switch/* @dwmw2
esphome/components/hc8/* @omartijn
esphome/components/hdc2010/* @optimusprimespace @ssieb
esphome/components/he60r/* @clydebarrow
esphome/components/heatpumpir/* @rob-deutsch
esphome/components/hitachi_ac424/* @sourabhjaiswal
esphome/components/hlk_fm22x/* @OnFreund
esphome/components/hlw8032/* @rici4kubicek
esphome/components/hm3301/* @freekode
esphome/components/hmac_md5/* @dwmw2
esphome/components/hmac_sha256/* @dwmw2
esphome/components/homeassistant/* @esphome/core @OttoWinter
esphome/components/homeassistant/number/* @landonr
esphome/components/homeassistant/switch/* @Links2004
@@ -222,6 +230,7 @@ esphome/components/hte501/* @Stock-M
esphome/components/http_request/ota/* @oarcher
esphome/components/http_request/update/* @jesserockz
esphome/components/htu31d/* @betterengineering
esphome/components/hub75/* @stuartparmenter
esphome/components/hydreon_rgxx/* @functionpointer
esphome/components/hyt271/* @Philippe12
esphome/components/i2c/* @esphome/core
@@ -301,7 +310,7 @@ esphome/components/md5/* @esphome/core
esphome/components/mdns/* @esphome/core
esphome/components/media_player/* @jesserockz
esphome/components/micro_wake_word/* @jesserockz @kahrendt
esphome/components/micronova/* @jorre05
esphome/components/micronova/* @edenhaus @jorre05
esphome/components/microphone/* @jesserockz @kahrendt
esphome/components/mics_4514/* @jesserockz
esphome/components/midea/* @dudanov
@@ -460,6 +469,7 @@ esphome/components/st7735/* @SenexCrenshaw
esphome/components/st7789v/* @kbx81
esphome/components/st7920/* @marsjan155
esphome/components/statsd/* @Links2004
esphome/components/stts22h/* @B48D81EFCC
esphome/components/substitutions/* @esphome/core
esphome/components/sun/* @OttoWinter
esphome/components/sun_gtil2/* @Mat931
@@ -481,6 +491,7 @@ esphome/components/template/datetime/* @rfdarter
esphome/components/template/event/* @nohat
esphome/components/template/fan/* @ssieb
esphome/components/text/* @mauritskorse
esphome/components/thermopro_ble/* @sittner
esphome/components/thermostat/* @kbx81
esphome/components/time/* @esphome/core
esphome/components/tinyusb/* @kbx81
@@ -508,6 +519,7 @@ esphome/components/tuya/switch/* @jesserockz
esphome/components/tuya/text_sensor/* @dentra
esphome/components/uart/* @esphome/core
esphome/components/uart/button/* @ssieb
esphome/components/uart/event/* @eoasmxd
esphome/components/uart/packet_transport/* @clydebarrow
esphome/components/udp/* @clydebarrow
esphome/components/ufire_ec/* @pvizeli
@@ -515,6 +527,7 @@ esphome/components/ufire_ise/* @pvizeli
esphome/components/ultrasonic/* @OttoWinter
esphome/components/update/* @jesserockz
esphome/components/uponor_smatrix/* @kroimon
esphome/components/usb_cdc_acm/* @kbx81
esphome/components/usb_host/* @clydebarrow
esphome/components/usb_uart/* @clydebarrow
esphome/components/valve/* @esphome/core
@@ -525,6 +538,7 @@ esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz @kahrendt
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher
esphome/components/water_heater/* @dhoeben
esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server/ota/* @esphome/core
esphome/components/web_server_base/* @esphome/core

View File

@@ -2,7 +2,7 @@
We welcome contributions to the ESPHome suite of code and documentation!
Please read our [contributing guide](https://esphome.io/guides/contributing.html) if you wish to contribute to the
Please read our [contributing guide](https://developers.esphome.io/contributing/code/) if you wish to contribute to the
project and be sure to join us on [Discord](https://discord.gg/KhAMKrd).
**See also:**

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2025.11.0-dev
PROJECT_NUMBER = 2026.1.0-dev
# 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

View File

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

View File

@@ -2,8 +2,8 @@
<a href="https://esphome.io/">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://esphome.io/_static/logo-text-on-dark.svg", alt="ESPHome Logo">
<img src="https://esphome.io/_static/logo-text-on-light.svg" alt="ESPHome Logo">
<source media="(prefers-color-scheme: dark)" srcset="https://media.esphome.io/logo/logo-text-on-dark.svg">
<img src="https://media.esphome.io/logo/logo-text-on-light.svg" alt="ESPHome Logo">
</picture>
</a>

View File

@@ -11,6 +11,16 @@ FROM base-source-${BUILD_TYPE} AS base
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
RUN pip install --no-cache-dir -U pip uv==0.6.14

View File

@@ -431,25 +431,33 @@ def run_miniterm(config: ConfigType, port: str, args) -> int:
while tries < 5:
try:
with ser:
buffer = b""
ser.timeout = 0.1 # 100ms timeout for non-blocking reads
while True:
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()
nanoseconds = time_.microsecond // 1000
time_str = f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}.{nanoseconds:03}]"
# Add to buffer and process complete lines
buffer += chunk
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:
_LOGGER.error("Serial port closed!")
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:
tries += 1
time.sleep(1)
@@ -518,10 +526,49 @@ def compile_program(args: ArgsProtocol, config: ConfigType) -> int:
rc = platformio_api.run_compile(config, CORE.verbose)
if rc != 0:
return rc
# Check if firmware was rebuilt and emit build_info + create manifest
_check_and_emit_build_info()
idedata = platformio_api.get_idedata(config)
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(
config: ConfigType, port: str, file: str, speed: int
) -> str | int:
@@ -757,7 +804,13 @@ def command_compile(args: ArgsProtocol, config: ConfigType) -> int | None:
exit_code = compile_program(args, config)
if exit_code != 0:
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
@@ -807,10 +860,8 @@ def command_run(args: ArgsProtocol, config: ConfigType) -> int | None:
if CORE.is_host:
from esphome.platformio_api import get_idedata
idedata = get_idedata(config)
if idedata is None:
return 1
program_path = idedata.raw["prog_path"]
program_path = str(get_idedata(config).firmware_elf_path)
_LOGGER.info("Running program from path '%s'", program_path)
return run_external_process(program_path)
# Get devices, resolving special identifiers like OTA
@@ -951,6 +1002,7 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
"""
from esphome import platformio_api
from esphome.analyze_memory.cli import MemoryAnalyzerCLI
from esphome.analyze_memory.ram_strings import RamStringsAnalyzer
# Always compile to ensure fresh data (fast if no changes - just relinks)
exit_code = write_cpp(config)
@@ -973,7 +1025,7 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
external_components = detect_external_components(config)
_LOGGER.debug("Detected external components: %s", external_components)
# Perform memory analysis
# Perform component memory analysis
_LOGGER.info("Analyzing memory usage...")
analyzer = MemoryAnalyzerCLI(
str(firmware_elf),
@@ -983,11 +1035,28 @@ def command_analyze_memory(args: ArgsProtocol, config: ConfigType) -> int:
)
analyzer.analyze()
# Generate and display report
# Generate and display component report
report = analyzer.generate_report()
print()
print(report)
# Perform RAM strings analysis
_LOGGER.info("Analyzing RAM strings...")
try:
ram_analyzer = RamStringsAnalyzer(
str(firmware_elf),
objdump_path=idedata.objdump_path,
platform=CORE.target_platform,
)
ram_analyzer.analyze()
# Generate and display RAM strings report
ram_report = ram_analyzer.generate_report()
print()
print(ram_report)
except Exception as e: # pylint: disable=broad-except
_LOGGER.warning("RAM strings analysis failed: %s", e)
return 0
@@ -1337,7 +1406,7 @@ def parse_args(argv):
"clean-all", help="Clean all build and platform files."
)
parser_clean_all.add_argument(
"configuration", help="Your YAML configuration directory.", nargs="*"
"configuration", help="Your YAML file or configuration directory.", nargs="*"
)
parser_dashboard = subparsers.add_parser(

View File

@@ -15,6 +15,7 @@ from .const import (
SECTION_TO_ATTR,
SYMBOL_PATTERNS,
)
from .demangle import batch_demangle
from .helpers import (
get_component_class_patterns,
get_esphome_components,
@@ -27,15 +28,6 @@ if TYPE_CHECKING:
_LOGGER = logging.getLogger(__name__)
# GCC global constructor/destructor prefix annotations
_GCC_PREFIX_ANNOTATIONS = {
"_GLOBAL__sub_I_": "global constructor for",
"_GLOBAL__sub_D_": "global destructor for",
}
# GCC optimization suffix pattern (e.g., $isra$0, $part$1, $constprop$2)
_GCC_OPTIMIZATION_SUFFIX_PATTERN = re.compile(r"(\$(?:isra|part|constprop)\$\d+)")
# C++ runtime patterns for categorization
_CPP_RUNTIME_PATTERNS = frozenset(["vtable", "typeinfo", "thunk"])
@@ -312,168 +304,9 @@ class MemoryAnalyzer:
if not symbols:
return
# Try to find the appropriate c++filt for the platform
cppfilt_cmd = "c++filt"
_LOGGER.info("Demangling %d symbols", len(symbols))
_LOGGER.debug("objdump_path = %s", self.objdump_path)
# Check if we have a toolchain-specific c++filt
if self.objdump_path and self.objdump_path != "objdump":
# Replace objdump with c++filt in the path
potential_cppfilt = self.objdump_path.replace("objdump", "c++filt")
_LOGGER.info("Checking for toolchain c++filt at: %s", potential_cppfilt)
if Path(potential_cppfilt).exists():
cppfilt_cmd = potential_cppfilt
_LOGGER.info("✓ Using toolchain c++filt: %s", cppfilt_cmd)
else:
_LOGGER.info(
"✗ Toolchain c++filt not found at %s, using system c++filt",
potential_cppfilt,
)
else:
_LOGGER.info("✗ Using system c++filt (objdump_path=%s)", self.objdump_path)
# Strip GCC optimization suffixes and prefixes before demangling
# Suffixes like $isra$0, $part$0, $constprop$0 confuse c++filt
# Prefixes like _GLOBAL__sub_I_ need to be removed and tracked
symbols_stripped: list[str] = []
symbols_prefixes: list[str] = [] # Track removed prefixes
for symbol in symbols:
# Remove GCC optimization markers
stripped = _GCC_OPTIMIZATION_SUFFIX_PATTERN.sub("", symbol)
# Handle GCC global constructor/initializer prefixes
# _GLOBAL__sub_I_<mangled> -> extract <mangled> for demangling
prefix = ""
for gcc_prefix in _GCC_PREFIX_ANNOTATIONS:
if stripped.startswith(gcc_prefix):
prefix = gcc_prefix
stripped = stripped[len(prefix) :]
break
symbols_stripped.append(stripped)
symbols_prefixes.append(prefix)
try:
# Send all symbols to c++filt at once
result = subprocess.run(
[cppfilt_cmd],
input="\n".join(symbols_stripped),
capture_output=True,
text=True,
check=False,
)
except (subprocess.SubprocessError, OSError, UnicodeDecodeError) as e:
# On error, cache originals
_LOGGER.warning("Failed to batch demangle symbols: %s", e)
for symbol in symbols:
self._demangle_cache[symbol] = symbol
return
if result.returncode != 0:
_LOGGER.warning(
"c++filt exited with code %d: %s",
result.returncode,
result.stderr[:200] if result.stderr else "(no error output)",
)
# Cache originals on failure
for symbol in symbols:
self._demangle_cache[symbol] = symbol
return
# Process demangled output
self._process_demangled_output(
symbols, symbols_stripped, symbols_prefixes, result.stdout, cppfilt_cmd
)
def _process_demangled_output(
self,
symbols: list[str],
symbols_stripped: list[str],
symbols_prefixes: list[str],
demangled_output: str,
cppfilt_cmd: str,
) -> None:
"""Process demangled symbol output and populate cache.
Args:
symbols: Original symbol names
symbols_stripped: Stripped symbol names sent to c++filt
symbols_prefixes: Removed prefixes to restore
demangled_output: Output from c++filt
cppfilt_cmd: Path to c++filt command (for logging)
"""
demangled_lines = demangled_output.strip().split("\n")
failed_count = 0
for original, stripped, prefix, demangled in zip(
symbols, symbols_stripped, symbols_prefixes, demangled_lines
):
# Add back any prefix that was removed
demangled = self._restore_symbol_prefix(prefix, stripped, demangled)
# If we stripped a suffix, add it back to the demangled name for clarity
if original != stripped and not prefix:
demangled = self._restore_symbol_suffix(original, demangled)
self._demangle_cache[original] = demangled
# Log symbols that failed to demangle (stayed the same as stripped version)
if stripped == demangled and stripped.startswith("_Z"):
failed_count += 1
if failed_count <= 5: # Only log first 5 failures
_LOGGER.warning("Failed to demangle: %s", original)
if failed_count == 0:
_LOGGER.info("Successfully demangled all %d symbols", len(symbols))
return
_LOGGER.warning(
"Failed to demangle %d/%d symbols using %s",
failed_count,
len(symbols),
cppfilt_cmd,
)
@staticmethod
def _restore_symbol_prefix(prefix: str, stripped: str, demangled: str) -> str:
"""Restore prefix that was removed before demangling.
Args:
prefix: Prefix that was removed (e.g., "_GLOBAL__sub_I_")
stripped: Stripped symbol name
demangled: Demangled symbol name
Returns:
Demangled name with prefix restored/annotated
"""
if not prefix:
return demangled
# Successfully demangled - add descriptive prefix
if demangled != stripped and (
annotation := _GCC_PREFIX_ANNOTATIONS.get(prefix)
):
return f"[{annotation}: {demangled}]"
# Failed to demangle - restore original prefix
return prefix + demangled
@staticmethod
def _restore_symbol_suffix(original: str, demangled: str) -> str:
"""Restore GCC optimization suffix that was removed before demangling.
Args:
original: Original symbol name with suffix
demangled: Demangled symbol name without suffix
Returns:
Demangled name with suffix annotation
"""
if suffix_match := _GCC_OPTIMIZATION_SUFFIX_PATTERN.search(original):
return f"{demangled} [{suffix_match.group(1)}]"
return demangled
self._demangle_cache = batch_demangle(symbols, objdump_path=self.objdump_path)
_LOGGER.info("Successfully demangled %d symbols", len(self._demangle_cache))
def _demangle_symbol(self, symbol: str) -> str:
"""Get demangled C++ symbol name from cache."""

View File

@@ -16,6 +16,11 @@ from . import (
class MemoryAnalyzerCLI(MemoryAnalyzer):
"""Memory analyzer with CLI-specific report generation."""
# Symbol size threshold for detailed analysis
SYMBOL_SIZE_THRESHOLD: int = (
100 # Show symbols larger than this in detailed analysis
)
# Column width constants
COL_COMPONENT: int = 29
COL_FLASH_TEXT: int = 14
@@ -192,14 +197,21 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
f"{len(symbols):>{self.COL_CORE_COUNT}} | {percentage:>{self.COL_CORE_PERCENT - 1}.1f}%"
)
# Top 15 largest core symbols
# All core symbols above threshold
lines.append("")
lines.append(f"Top 15 Largest {_COMPONENT_CORE} Symbols:")
sorted_core_symbols = sorted(
self._esphome_core_symbols, key=lambda x: x[2], reverse=True
)
large_core_symbols = [
(symbol, demangled, size)
for symbol, demangled, size in sorted_core_symbols
if size > self.SYMBOL_SIZE_THRESHOLD
]
for i, (symbol, demangled, size) in enumerate(sorted_core_symbols[:15]):
lines.append(
f"{_COMPONENT_CORE} Symbols > {self.SYMBOL_SIZE_THRESHOLD} B ({len(large_core_symbols)} symbols):"
)
for i, (symbol, demangled, size) in enumerate(large_core_symbols):
lines.append(f"{i + 1}. {demangled} ({size:,} B)")
lines.append("=" * self.TABLE_WIDTH)
@@ -269,13 +281,15 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
lines.append(f"Total size: {comp_mem.flash_total:,} B")
lines.append("")
# Show all symbols > 100 bytes for better visibility
# Show all symbols above threshold for better visibility
large_symbols = [
(sym, dem, size) for sym, dem, size in sorted_symbols if size > 100
(sym, dem, size)
for sym, dem, size in sorted_symbols
if size > self.SYMBOL_SIZE_THRESHOLD
]
lines.append(
f"{comp_name} Symbols > 100 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):
lines.append(f"{i + 1}. {demangled} ({size:,} B)")

View File

@@ -0,0 +1,182 @@
"""Symbol demangling utilities for memory analysis.
This module provides functions for demangling C++ symbol names using c++filt.
"""
from __future__ import annotations
import logging
import re
import subprocess
from .toolchain import find_tool
_LOGGER = logging.getLogger(__name__)
# GCC global constructor/destructor prefix annotations
GCC_PREFIX_ANNOTATIONS = {
"_GLOBAL__sub_I_": "global constructor for",
"_GLOBAL__sub_D_": "global destructor for",
}
# GCC optimization suffix pattern (e.g., $isra$0, $part$1, $constprop$2)
GCC_OPTIMIZATION_SUFFIX_PATTERN = re.compile(r"(\$(?:isra|part|constprop)\$\d+)")
def _strip_gcc_annotations(symbol: str) -> tuple[str, str]:
"""Strip GCC optimization suffixes and prefixes from a symbol.
Args:
symbol: The mangled symbol name
Returns:
Tuple of (stripped_symbol, removed_prefix)
"""
# Remove GCC optimization markers
stripped = GCC_OPTIMIZATION_SUFFIX_PATTERN.sub("", symbol)
# Handle GCC global constructor/initializer prefixes
prefix = ""
for gcc_prefix in GCC_PREFIX_ANNOTATIONS:
if stripped.startswith(gcc_prefix):
prefix = gcc_prefix
stripped = stripped[len(prefix) :]
break
return stripped, prefix
def _restore_symbol_prefix(prefix: str, stripped: str, demangled: str) -> str:
"""Restore prefix that was removed before demangling.
Args:
prefix: Prefix that was removed (e.g., "_GLOBAL__sub_I_")
stripped: Stripped symbol name
demangled: Demangled symbol name
Returns:
Demangled name with prefix restored/annotated
"""
if not prefix:
return demangled
# Successfully demangled - add descriptive prefix
if demangled != stripped and (annotation := GCC_PREFIX_ANNOTATIONS.get(prefix)):
return f"[{annotation}: {demangled}]"
# Failed to demangle - restore original prefix
return prefix + demangled
def _restore_symbol_suffix(original: str, demangled: str) -> str:
"""Restore GCC optimization suffix that was removed before demangling.
Args:
original: Original symbol name with suffix
demangled: Demangled symbol name without suffix
Returns:
Demangled name with suffix annotation
"""
if suffix_match := GCC_OPTIMIZATION_SUFFIX_PATTERN.search(original):
return f"{demangled} [{suffix_match.group(1)}]"
return demangled
def batch_demangle(
symbols: list[str],
cppfilt_path: str | None = None,
objdump_path: str | None = None,
) -> dict[str, str]:
"""Batch demangle C++ symbol names.
Args:
symbols: List of symbol names to demangle
cppfilt_path: Path to c++filt binary (auto-detected if not provided)
objdump_path: Path to objdump binary to derive c++filt path from
Returns:
Dictionary mapping original symbol names to demangled names
"""
cache: dict[str, str] = {}
if not symbols:
return cache
# Find c++filt tool
cppfilt_cmd = cppfilt_path or find_tool("c++filt", objdump_path)
if not cppfilt_cmd:
_LOGGER.warning("Could not find c++filt, symbols will not be demangled")
return {s: s for s in symbols}
_LOGGER.debug("Demangling %d symbols using %s", len(symbols), cppfilt_cmd)
# Strip GCC optimization suffixes and prefixes before demangling
symbols_stripped: list[str] = []
symbols_prefixes: list[str] = []
for symbol in symbols:
stripped, prefix = _strip_gcc_annotations(symbol)
symbols_stripped.append(stripped)
symbols_prefixes.append(prefix)
try:
result = subprocess.run(
[cppfilt_cmd],
input="\n".join(symbols_stripped),
capture_output=True,
text=True,
check=False,
)
except (subprocess.SubprocessError, OSError, UnicodeDecodeError) as e:
_LOGGER.warning("Failed to batch demangle symbols: %s", e)
return {s: s for s in symbols}
if result.returncode != 0:
_LOGGER.warning(
"c++filt exited with code %d: %s",
result.returncode,
result.stderr[:200] if result.stderr else "(no error output)",
)
return {s: s for s in symbols}
# Process demangled output
demangled_lines = result.stdout.strip().split("\n")
# Check for output length mismatch
if len(demangled_lines) != len(symbols):
_LOGGER.warning(
"c++filt output mismatch: expected %d lines, got %d",
len(symbols),
len(demangled_lines),
)
return {s: s for s in symbols}
failed_count = 0
for original, stripped, prefix, demangled in zip(
symbols, symbols_stripped, symbols_prefixes, demangled_lines
):
# Add back any prefix that was removed
demangled = _restore_symbol_prefix(prefix, stripped, demangled)
# If we stripped a suffix, add it back to the demangled name for clarity
if original != stripped and not prefix:
demangled = _restore_symbol_suffix(original, demangled)
cache[original] = demangled
# Count symbols that failed to demangle
if stripped == demangled and stripped.startswith("_Z"):
failed_count += 1
if failed_count <= 5:
_LOGGER.debug("Failed to demangle: %s", original)
if failed_count > 0:
_LOGGER.debug(
"Failed to demangle %d/%d symbols using %s",
failed_count,
len(symbols),
cppfilt_cmd,
)
return cache

View File

@@ -0,0 +1,493 @@
"""Analyzer for RAM-stored strings in ESP8266/ESP32 firmware ELF files.
This module identifies strings that are stored in RAM sections (.data, .bss, .rodata)
rather than in flash sections (.irom0.text, .irom.text), which is important for
memory-constrained platforms like ESP8266.
"""
from __future__ import annotations
from collections import defaultdict
from dataclasses import dataclass
import logging
from pathlib import Path
import re
import subprocess
from .demangle import batch_demangle
from .toolchain import find_tool
_LOGGER = logging.getLogger(__name__)
# ESP8266: .rodata is in RAM (DRAM), not flash
# ESP32: .rodata is in flash, mapped to data bus
ESP8266_RAM_SECTIONS = frozenset([".data", ".rodata", ".bss"])
ESP8266_FLASH_SECTIONS = frozenset([".irom0.text", ".irom.text", ".text"])
# ESP32: .rodata is memory-mapped from flash
ESP32_RAM_SECTIONS = frozenset([".data", ".bss", ".dram0.data", ".dram0.bss"])
ESP32_FLASH_SECTIONS = frozenset([".text", ".rodata", ".flash.text", ".flash.rodata"])
# nm symbol types for data symbols (D=global data, d=local data, R=rodata, B=bss)
DATA_SYMBOL_TYPES = frozenset(["D", "d", "R", "r", "B", "b"])
@dataclass
class SectionInfo:
"""Information about an ELF section."""
name: str
address: int
size: int
@dataclass
class RamString:
"""A string found in RAM."""
section: str
address: int
content: str
@property
def size(self) -> int:
"""Size in bytes including null terminator."""
return len(self.content) + 1
@dataclass
class RamSymbol:
"""A symbol found in RAM."""
name: str
sym_type: str
address: int
size: int
section: str
demangled: str = "" # Demangled name, set after batch demangling
class RamStringsAnalyzer:
"""Analyzes ELF files to find strings stored in RAM."""
def __init__(
self,
elf_path: str,
objdump_path: str | None = None,
min_length: int = 8,
platform: str = "esp32",
) -> None:
"""Initialize the RAM strings analyzer.
Args:
elf_path: Path to the ELF file to analyze
objdump_path: Path to objdump binary (used to find other tools)
min_length: Minimum string length to report (default: 8)
platform: Platform name ("esp8266", "esp32", etc.) for section mapping
"""
self.elf_path = Path(elf_path)
if not self.elf_path.exists():
raise FileNotFoundError(f"ELF file not found: {elf_path}")
self.objdump_path = objdump_path
self.min_length = min_length
self.platform = platform
# Set RAM/flash sections based on platform
if self.platform == "esp8266":
self.ram_sections = ESP8266_RAM_SECTIONS
self.flash_sections = ESP8266_FLASH_SECTIONS
else:
# ESP32 and other platforms
self.ram_sections = ESP32_RAM_SECTIONS
self.flash_sections = ESP32_FLASH_SECTIONS
self.sections: dict[str, SectionInfo] = {}
self.ram_strings: list[RamString] = []
self.ram_symbols: list[RamSymbol] = []
def _run_command(self, cmd: list[str]) -> str:
"""Run a command and return its output."""
try:
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
return result.stdout
except subprocess.CalledProcessError as e:
_LOGGER.debug("Command failed: %s - %s", " ".join(cmd), e.stderr)
raise
except FileNotFoundError:
_LOGGER.warning("Command not found: %s", cmd[0])
raise
def analyze(self) -> None:
"""Perform the full RAM analysis."""
self._parse_sections()
self._extract_strings()
self._analyze_symbols()
self._demangle_symbols()
def _parse_sections(self) -> None:
"""Parse section headers from ELF file."""
objdump = find_tool("objdump", self.objdump_path)
if not objdump:
_LOGGER.error("Could not find objdump command")
return
try:
output = self._run_command([objdump, "-h", str(self.elf_path)])
except (subprocess.CalledProcessError, FileNotFoundError):
return
# Parse section headers
# Format: Idx Name Size VMA LMA File off Algn
section_pattern = re.compile(
r"^\s*\d+\s+(\S+)\s+([0-9a-fA-F]+)\s+([0-9a-fA-F]+)"
)
for line in output.split("\n"):
if match := section_pattern.match(line):
name = match.group(1)
size = int(match.group(2), 16)
vma = int(match.group(3), 16)
self.sections[name] = SectionInfo(name, vma, size)
def _extract_strings(self) -> None:
"""Extract strings from RAM sections."""
objdump = find_tool("objdump", self.objdump_path)
if not objdump:
return
for section_name in self.ram_sections:
if section_name not in self.sections:
continue
try:
output = self._run_command(
[objdump, "-s", "-j", section_name, str(self.elf_path)]
)
except subprocess.CalledProcessError:
# Section may exist but have no content (e.g., .bss)
continue
except FileNotFoundError:
continue
strings = self._parse_hex_dump(output, section_name)
self.ram_strings.extend(strings)
def _parse_hex_dump(self, output: str, section_name: str) -> list[RamString]:
"""Parse hex dump output to extract strings.
Args:
output: Output from objdump -s
section_name: Name of the section being parsed
Returns:
List of RamString objects
"""
strings: list[RamString] = []
current_string = bytearray()
string_start_addr = 0
for line in output.split("\n"):
# Lines look like: " 3ffef8a0 00000000 00000000 00000000 00000000 ................"
match = re.match(r"^\s+([0-9a-fA-F]+)\s+((?:[0-9a-fA-F]{2,8}\s*)+)", line)
if not match:
continue
addr = int(match.group(1), 16)
hex_data = match.group(2).strip()
# Convert hex to bytes
hex_bytes = hex_data.split()
byte_offset = 0
for hex_chunk in hex_bytes:
# Handle both byte-by-byte and word formats
for i in range(0, len(hex_chunk), 2):
byte_val = int(hex_chunk[i : i + 2], 16)
if 0x20 <= byte_val <= 0x7E: # Printable ASCII
if not current_string:
string_start_addr = addr + byte_offset
current_string.append(byte_val)
else:
if byte_val == 0 and len(current_string) >= self.min_length:
# Found null terminator
strings.append(
RamString(
section=section_name,
address=string_start_addr,
content=current_string.decode(
"ascii", errors="ignore"
),
)
)
current_string = bytearray()
byte_offset += 1
return strings
def _analyze_symbols(self) -> None:
"""Analyze symbols in RAM sections."""
nm = find_tool("nm", self.objdump_path)
if not nm:
return
try:
output = self._run_command([nm, "-S", "--size-sort", str(self.elf_path)])
except (subprocess.CalledProcessError, FileNotFoundError):
return
for line in output.split("\n"):
parts = line.split()
if len(parts) < 4:
continue
try:
addr = int(parts[0], 16)
size = int(parts[1], 16) if parts[1] != "?" else 0
except ValueError:
continue
sym_type = parts[2]
name = " ".join(parts[3:])
# Filter for data symbols
if sym_type not in DATA_SYMBOL_TYPES:
continue
# Check if symbol is in a RAM section
for section_name in self.ram_sections:
if section_name not in self.sections:
continue
section = self.sections[section_name]
if section.address <= addr < section.address + section.size:
self.ram_symbols.append(
RamSymbol(
name=name,
sym_type=sym_type,
address=addr,
size=size,
section=section_name,
)
)
break
def _demangle_symbols(self) -> None:
"""Batch demangle all RAM symbol names."""
if not self.ram_symbols:
return
# Collect all symbol names and demangle them
symbol_names = [s.name for s in self.ram_symbols]
demangle_cache = batch_demangle(symbol_names, objdump_path=self.objdump_path)
# Assign demangled names to symbols
for symbol in self.ram_symbols:
symbol.demangled = demangle_cache.get(symbol.name, symbol.name)
def _get_sections_size(self, section_names: frozenset[str]) -> int:
"""Get total size of specified sections."""
return sum(
section.size
for name, section in self.sections.items()
if name in section_names
)
def get_total_ram_usage(self) -> int:
"""Get total RAM usage from RAM sections."""
return self._get_sections_size(self.ram_sections)
def get_total_flash_usage(self) -> int:
"""Get total flash usage from flash sections."""
return self._get_sections_size(self.flash_sections)
def get_total_string_bytes(self) -> int:
"""Get total bytes used by strings in RAM."""
return sum(s.size for s in self.ram_strings)
def get_repeated_strings(self) -> list[tuple[str, int]]:
"""Find strings that appear multiple times.
Returns:
List of (string, count) tuples sorted by potential savings
"""
string_counts: dict[str, int] = defaultdict(int)
for ram_string in self.ram_strings:
string_counts[ram_string.content] += 1
return sorted(
[(s, c) for s, c in string_counts.items() if c > 1],
key=lambda x: x[1] * (len(x[0]) + 1),
reverse=True,
)
def get_long_strings(self, min_len: int = 20) -> list[RamString]:
"""Get strings longer than the specified length.
Args:
min_len: Minimum string length
Returns:
List of RamString objects sorted by length
"""
return sorted(
[s for s in self.ram_strings if len(s.content) >= min_len],
key=lambda x: len(x.content),
reverse=True,
)
def get_largest_symbols(self, min_size: int = 100) -> list[RamSymbol]:
"""Get RAM symbols larger than the specified size.
Args:
min_size: Minimum symbol size in bytes
Returns:
List of RamSymbol objects sorted by size
"""
return sorted(
[s for s in self.ram_symbols if s.size >= min_size],
key=lambda x: x.size,
reverse=True,
)
def generate_report(self, show_all_sections: bool = False) -> str:
"""Generate a formatted RAM strings analysis report.
Args:
show_all_sections: If True, show all sections, not just RAM
Returns:
Formatted report string
"""
lines: list[str] = []
table_width = 80
lines.append("=" * table_width)
lines.append(
f"RAM Strings Analysis ({self.platform.upper()})".center(table_width)
)
lines.append("=" * table_width)
lines.append("")
# Section Analysis
lines.append("SECTION ANALYSIS")
lines.append("-" * table_width)
lines.append(f"{'Section':<20} {'Address':<12} {'Size':<12} {'Location'}")
lines.append("-" * table_width)
total_ram_usage = 0
total_flash_usage = 0
for name, section in sorted(self.sections.items(), key=lambda x: x[1].address):
if name in self.ram_sections:
location = "RAM"
total_ram_usage += section.size
elif name in self.flash_sections:
location = "FLASH"
total_flash_usage += section.size
else:
location = "OTHER"
if show_all_sections or name in self.ram_sections:
lines.append(
f"{name:<20} 0x{section.address:08x} {section.size:>8} B {location}"
)
lines.append("-" * table_width)
lines.append(f"Total RAM sections size: {total_ram_usage:,} bytes")
lines.append(f"Total Flash sections size: {total_flash_usage:,} bytes")
# Strings in RAM
lines.append("")
lines.append("=" * table_width)
lines.append("STRINGS IN RAM SECTIONS")
lines.append("=" * table_width)
lines.append(
"Note: .bss sections contain uninitialized data (no strings to extract)"
)
# Group strings by section
strings_by_section: dict[str, list[RamString]] = defaultdict(list)
for ram_string in self.ram_strings:
strings_by_section[ram_string.section].append(ram_string)
for section_name in sorted(strings_by_section.keys()):
section_strings = strings_by_section[section_name]
lines.append(f"\nSection: {section_name}")
lines.append("-" * 40)
for ram_string in sorted(section_strings, key=lambda x: x.address):
clean_string = ram_string.content[:100] + (
"..." if len(ram_string.content) > 100 else ""
)
lines.append(
f' 0x{ram_string.address:08x}: "{clean_string}" (len={len(ram_string.content)})'
)
# Large RAM symbols
lines.append("")
lines.append("=" * table_width)
lines.append("LARGE DATA SYMBOLS IN RAM (>= 50 bytes)")
lines.append("=" * table_width)
largest_symbols = self.get_largest_symbols(50)
lines.append(f"\n{'Symbol':<50} {'Type':<6} {'Size':<10} {'Section'}")
lines.append("-" * table_width)
for symbol in largest_symbols:
# Use demangled name if available, otherwise raw name
display_name = symbol.demangled or symbol.name
name_display = display_name[:49] if len(display_name) > 49 else display_name
lines.append(
f"{name_display:<50} {symbol.sym_type:<6} {symbol.size:>8} B {symbol.section}"
)
# Summary
lines.append("")
lines.append("=" * table_width)
lines.append("SUMMARY")
lines.append("=" * table_width)
lines.append(f"Total strings found in RAM: {len(self.ram_strings)}")
total_string_bytes = self.get_total_string_bytes()
lines.append(f"Total bytes used by strings: {total_string_bytes:,}")
# Optimization targets
lines.append("")
lines.append("=" * table_width)
lines.append("POTENTIAL OPTIMIZATION TARGETS")
lines.append("=" * table_width)
# Repeated strings
repeated = self.get_repeated_strings()[:10]
if repeated:
lines.append("\nRepeated strings (could be deduplicated):")
for string, count in repeated:
savings = (count - 1) * (len(string) + 1)
clean_string = string[:50] + ("..." if len(string) > 50 else "")
lines.append(
f' "{clean_string}" - appears {count} times (potential savings: {savings} bytes)'
)
# Long strings - platform-specific advice
long_strings = self.get_long_strings(20)[:10]
if long_strings:
if self.platform == "esp8266":
lines.append(
"\nLong strings that could be moved to PROGMEM (>= 20 chars):"
)
else:
# ESP32: strings in DRAM are typically there for a reason
# (interrupt handlers, pre-flash-init code, etc.)
lines.append("\nLong strings in DRAM (>= 20 chars):")
lines.append(
"Note: ESP32 DRAM strings may be required for interrupt/early-boot contexts"
)
for ram_string in long_strings:
clean_string = ram_string.content[:60] + (
"..." if len(ram_string.content) > 60 else ""
)
lines.append(
f' {ram_string.section} @ 0x{ram_string.address:08x}: "{clean_string}" ({len(ram_string.content)} bytes)'
)
lines.append("")
return "\n".join(lines)

View File

@@ -0,0 +1,57 @@
"""Toolchain utilities for memory analysis."""
from __future__ import annotations
import logging
from pathlib import Path
import subprocess
_LOGGER = logging.getLogger(__name__)
# Platform-specific toolchain prefixes
TOOLCHAIN_PREFIXES = [
"xtensa-lx106-elf-", # ESP8266
"xtensa-esp32-elf-", # ESP32
"xtensa-esp-elf-", # ESP32 (newer IDF)
"", # System default (no prefix)
]
def find_tool(
tool_name: str,
objdump_path: str | None = None,
) -> str | None:
"""Find a toolchain tool by name.
First tries to derive the tool path from objdump_path (if provided),
then falls back to searching for platform-specific tools.
Args:
tool_name: Name of the tool (e.g., "objdump", "nm", "c++filt")
objdump_path: Path to objdump binary to derive other tool paths from
Returns:
Path to the tool or None if not found
"""
# Try to derive from objdump path first (most reliable)
if objdump_path and objdump_path != "objdump":
objdump_file = Path(objdump_path)
# Replace just the filename portion, preserving any prefix (e.g., xtensa-esp32-elf-)
new_name = objdump_file.name.replace("objdump", tool_name)
potential_path = str(objdump_file.with_name(new_name))
if Path(potential_path).exists():
_LOGGER.debug("Found %s at: %s", tool_name, potential_path)
return potential_path
# Try platform-specific tools
for prefix in TOOLCHAIN_PREFIXES:
cmd = f"{prefix}{tool_name}"
try:
subprocess.run([cmd, "--version"], capture_output=True, check=True)
_LOGGER.debug("Found %s: %s", tool_name, cmd)
return cmd
except (subprocess.CalledProcessError, FileNotFoundError):
continue
_LOGGER.warning("Could not find %s tool", tool_name)
return None

View File

@@ -30,7 +30,9 @@ void A01nyubComponent::check_buffer_() {
ESP_LOGV(TAG, "Distance from sensor: %f mm, %f m", distance, meters);
this->publish_state(meters);
} 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 {
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);
this->publish_state(distance);
} 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 {
ESP_LOGW(TAG, "checksum failed: %02x != %02x", checksum, this->buffer_[3]);

View File

@@ -87,7 +87,7 @@ void AbsoluteHumidityComponent::loop() {
break;
default:
this->publish_state(NAN);
this->status_set_error("Invalid saturation vapor pressure equation selection!");
this->status_set_error(LOG_STR("Invalid saturation vapor pressure equation selection!"));
return;
}
ESP_LOGD(TAG, "Saturation vapor pressure %f kPa", es);
@@ -163,7 +163,7 @@ float AbsoluteHumidityComponent::es_wobus(float t) {
}
// From https://www.environmentalbiophysics.org/chalk-talk-how-to-calculate-absolute-humidity/
// H/T to https://esphome.io/cookbook/bme280_environment.html
// H/T to https://esphome.io/cookbook/bme280_environment/
// H/T to https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
float AbsoluteHumidityComponent::vapor_density(float es, float hr, float ta) {
// es = saturated vapor pressure (kPa)

View File

@@ -1,15 +1,17 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components.esp32 import VARIANT_ESP32P4, get_esp32_variant
from esphome.components.esp32.const import (
from esphome.components.esp32 import (
VARIANT_ESP32,
VARIANT_ESP32C2,
VARIANT_ESP32C3,
VARIANT_ESP32C5,
VARIANT_ESP32C6,
VARIANT_ESP32C61,
VARIANT_ESP32H2,
VARIANT_ESP32P4,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
get_esp32_variant,
)
import esphome.config_validation as cv
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266
@@ -99,6 +101,13 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
5: adc_channel_t.ADC_CHANNEL_5,
6: adc_channel_t.ADC_CHANNEL_6,
},
# https://docs.espressif.com/projects/esp-idf/en/latest/esp32c61/api-reference/peripherals/gpio.html
VARIANT_ESP32C61: {
1: adc_channel_t.ADC_CHANNEL_0,
3: adc_channel_t.ADC_CHANNEL_1,
4: adc_channel_t.ADC_CHANNEL_2,
5: adc_channel_t.ADC_CHANNEL_3,
},
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
VARIANT_ESP32H2: {
1: adc_channel_t.ADC_CHANNEL_0,
@@ -107,6 +116,17 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
4: adc_channel_t.ADC_CHANNEL_3,
5: adc_channel_t.ADC_CHANNEL_4,
},
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32p4/include/soc/adc_channel.h
VARIANT_ESP32P4: {
16: adc_channel_t.ADC_CHANNEL_0,
17: adc_channel_t.ADC_CHANNEL_1,
18: adc_channel_t.ADC_CHANNEL_2,
19: adc_channel_t.ADC_CHANNEL_3,
20: adc_channel_t.ADC_CHANNEL_4,
21: adc_channel_t.ADC_CHANNEL_5,
22: adc_channel_t.ADC_CHANNEL_6,
23: adc_channel_t.ADC_CHANNEL_7,
},
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
VARIANT_ESP32S2: {
1: adc_channel_t.ADC_CHANNEL_0,
@@ -133,16 +153,6 @@ ESP32_VARIANT_ADC1_PIN_TO_CHANNEL = {
9: adc_channel_t.ADC_CHANNEL_8,
10: adc_channel_t.ADC_CHANNEL_9,
},
VARIANT_ESP32P4: {
16: adc_channel_t.ADC_CHANNEL_0,
17: adc_channel_t.ADC_CHANNEL_1,
18: adc_channel_t.ADC_CHANNEL_2,
19: adc_channel_t.ADC_CHANNEL_3,
20: adc_channel_t.ADC_CHANNEL_4,
21: adc_channel_t.ADC_CHANNEL_5,
22: adc_channel_t.ADC_CHANNEL_6,
23: adc_channel_t.ADC_CHANNEL_7,
},
}
# pin to adc2 channel mapping
@@ -173,8 +183,19 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
VARIANT_ESP32C5: {}, # no ADC2
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32c6/include/soc/adc_channel.h
VARIANT_ESP32C6: {}, # no ADC2
# ESP32-C61 has no ADC2
VARIANT_ESP32C61: {}, # no ADC2
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32h2/include/soc/adc_channel.h
VARIANT_ESP32H2: {}, # no ADC2
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32p4/include/soc/adc_channel.h
VARIANT_ESP32P4: {
49: adc_channel_t.ADC_CHANNEL_0,
50: adc_channel_t.ADC_CHANNEL_1,
51: adc_channel_t.ADC_CHANNEL_2,
52: adc_channel_t.ADC_CHANNEL_3,
53: adc_channel_t.ADC_CHANNEL_4,
54: adc_channel_t.ADC_CHANNEL_5,
},
# https://github.com/espressif/esp-idf/blob/master/components/soc/esp32s2/include/soc/adc_channel.h
VARIANT_ESP32S2: {
11: adc_channel_t.ADC_CHANNEL_0,
@@ -201,14 +222,6 @@ ESP32_VARIANT_ADC2_PIN_TO_CHANNEL = {
19: adc_channel_t.ADC_CHANNEL_8,
20: adc_channel_t.ADC_CHANNEL_9,
},
VARIANT_ESP32P4: {
49: adc_channel_t.ADC_CHANNEL_0,
50: adc_channel_t.ADC_CHANNEL_1,
51: adc_channel_t.ADC_CHANNEL_2,
52: adc_channel_t.ADC_CHANNEL_3,
53: adc_channel_t.ADC_CHANNEL_4,
54: adc_channel_t.ADC_CHANNEL_5,
},
}

View File

@@ -42,10 +42,11 @@ void ADCSensor::setup() {
adc_oneshot_unit_init_cfg_t init_config = {}; // Zero initialize
init_config.unit_id = this->adc_unit_;
init_config.ulp_mode = ADC_ULP_MODE_DISABLE;
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || USE_ESP32_VARIANT_ESP32H2
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2
init_config.clk_src = ADC_DIGI_CLK_SRC_DEFAULT;
#endif // USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 ||
// USE_ESP32_VARIANT_ESP32H2
// USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2
esp_err_t err = adc_oneshot_new_unit(&init_config, &ADCSensor::shared_adc_handles[this->adc_unit_]);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error initializing %s: %d", LOG_STR_ARG(adc_unit_to_str(this->adc_unit_)), err);
@@ -74,7 +75,7 @@ void ADCSensor::setup() {
adc_cali_handle_t handle = nullptr;
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
// RISC-V variants and S3 use curve fitting calibration
adc_cali_curve_fitting_config_t cali_config = {}; // Zero initialize first
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
@@ -111,7 +112,7 @@ void ADCSensor::setup() {
ESP_LOGW(TAG, "Line fitting calibration failed with error %d, will use uncalibrated readings", err);
this->setup_flags_.calibration_complete = false;
}
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32S3 || ESP32H2
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32C61 || ESP32H2 || ESP32P4 || ESP32S3
}
this->setup_flags_.init_complete = true;
@@ -186,11 +187,11 @@ float ADCSensor::sample_fixed_attenuation_() {
ESP_LOGW(TAG, "ADC calibration conversion failed with error %d, disabling calibration", err);
if (this->calibration_handle_ != nullptr) {
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
#else // Other ESP32 variants use line fitting calibration
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32S3 || ESP32H2
#endif // USE_ESP32_VARIANT_ESP32C3 || ESP32C5 || ESP32C6 || ESP32C61 || ESP32H2 || ESP32P4 || ESP32S3
this->calibration_handle_ = nullptr;
}
}
@@ -219,7 +220,7 @@ float ADCSensor::sample_autorange_() {
if (this->calibration_handle_ != nullptr) {
// Delete old calibration handle
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
adc_cali_delete_scheme_curve_fitting(this->calibration_handle_);
#else
adc_cali_delete_scheme_line_fitting(this->calibration_handle_);
@@ -231,7 +232,7 @@ float ADCSensor::sample_autorange_() {
adc_cali_handle_t handle = nullptr;
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
adc_cali_curve_fitting_config_t cali_config = {};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
cali_config.chan = this->channel_;
@@ -266,7 +267,7 @@ float ADCSensor::sample_autorange_() {
ESP_LOGW(TAG, "ADC read failed in autorange with error %d", err);
if (handle != nullptr) {
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
adc_cali_delete_scheme_curve_fitting(handle);
#else
adc_cali_delete_scheme_line_fitting(handle);
@@ -288,7 +289,7 @@ float ADCSensor::sample_autorange_() {
}
// Clean up calibration handle
#if USE_ESP32_VARIANT_ESP32C3 || USE_ESP32_VARIANT_ESP32C5 || USE_ESP32_VARIANT_ESP32C6 || \
USE_ESP32_VARIANT_ESP32S3 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4
USE_ESP32_VARIANT_ESP32C61 || USE_ESP32_VARIANT_ESP32H2 || USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S3
adc_cali_delete_scheme_curve_fitting(handle);
#else
adc_cali_delete_scheme_line_fitting(handle);

View File

@@ -25,11 +25,13 @@ class AddressableLightDisplay : public display::DisplayBuffer {
if (enabled_ && !enabled) { // enabled -> disabled
// - Tell the parent light to refresh, effectively wiping the display. Also
// 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
// - Save the current effect.
this->last_effect_ = light_state_->get_effect_name();
// - Save the current effect index.
this->last_effect_index_ = light_state_->get_current_effect_index();
// - Disable any current effect.
light_state_->make_call().set_effect(0).perform();
}
@@ -56,7 +58,7 @@ class AddressableLightDisplay : public display::DisplayBuffer {
int32_t width_;
int32_t height_;
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_;
};
} // namespace addressable_light

View File

@@ -227,7 +227,7 @@ CONFIG_SCHEMA = cv.All(
{
cv.GenerateID(): cv.declare_id(ADE7880),
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.Required(CONF_IRQ1_PIN): pins.internal_gpio_input_pin_schema,

View File

@@ -24,6 +24,8 @@ from esphome.const import (
UNIT_WATT,
)
CODEOWNERS = ["@angelnu"]
CONF_CURRENT_A = "current_a"
CONF_CURRENT_B = "current_b"
CONF_ACTIVE_POWER_A = "active_power_a"

View File

@@ -25,7 +25,8 @@ void ADE7953::setup() {
this->ade_write_8(PGA_V_8, pga_v_);
this->ade_write_8(PGA_IA_8, pga_ia_);
this->ade_write_8(PGA_IB_8, pga_ib_);
this->ade_write_32(AVGAIN_32, vgain_);
this->ade_write_32(AVGAIN_32, avgain_);
this->ade_write_32(BVGAIN_32, bvgain_);
this->ade_write_32(AIGAIN_32, aigain_);
this->ade_write_32(BIGAIN_32, bigain_);
this->ade_write_32(AWGAIN_32, awgain_);
@@ -34,7 +35,8 @@ void ADE7953::setup() {
this->ade_read_8(PGA_V_8, &pga_v_);
this->ade_read_8(PGA_IA_8, &pga_ia_);
this->ade_read_8(PGA_IB_8, &pga_ib_);
this->ade_read_32(AVGAIN_32, &vgain_);
this->ade_read_32(AVGAIN_32, &avgain_);
this->ade_read_32(BVGAIN_32, &bvgain_);
this->ade_read_32(AIGAIN_32, &aigain_);
this->ade_read_32(BIGAIN_32, &bigain_);
this->ade_read_32(AWGAIN_32, &awgain_);
@@ -63,13 +65,14 @@ void ADE7953::dump_config() {
" PGA_V_8: 0x%X\n"
" PGA_IA_8: 0x%X\n"
" PGA_IB_8: 0x%X\n"
" VGAIN_32: 0x%08jX\n"
" AVGAIN_32: 0x%08jX\n"
" BVGAIN_32: 0x%08jX\n"
" AIGAIN_32: 0x%08jX\n"
" BIGAIN_32: 0x%08jX\n"
" AWGAIN_32: 0x%08jX\n"
" BWGAIN_32: 0x%08jX",
this->use_acc_energy_regs_, pga_v_, pga_ia_, pga_ib_, (uintmax_t) vgain_, (uintmax_t) aigain_,
(uintmax_t) bigain_, (uintmax_t) awgain_, (uintmax_t) bwgain_);
this->use_acc_energy_regs_, pga_v_, pga_ia_, pga_ib_, (uintmax_t) avgain_, (uintmax_t) bvgain_,
(uintmax_t) aigain_, (uintmax_t) bigain_, (uintmax_t) awgain_, (uintmax_t) bwgain_);
}
#define ADE_PUBLISH_(name, val, factor) \

View File

@@ -46,7 +46,12 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
void set_pga_ib(uint8_t pga_ib) { pga_ib_ = pga_ib; }
// Set input gains
void set_vgain(uint32_t vgain) { vgain_ = vgain; }
void set_vgain(uint32_t vgain) {
// Datasheet says: "to avoid discrepancies in other registers,
// if AVGAIN is set then BVGAIN should be set to the same value."
avgain_ = vgain;
bvgain_ = vgain;
}
void set_aigain(uint32_t aigain) { aigain_ = aigain; }
void set_bigain(uint32_t bigain) { bigain_ = bigain; }
void set_awgain(uint32_t awgain) { awgain_ = awgain; }
@@ -100,7 +105,8 @@ class ADE7953 : public PollingComponent, public sensor::Sensor {
uint8_t pga_v_;
uint8_t pga_ia_;
uint8_t pga_ib_;
uint32_t vgain_;
uint32_t avgain_;
uint32_t bvgain_;
uint32_t aigain_;
uint32_t bigain_;
uint32_t awgain_;

View File

@@ -83,7 +83,7 @@ void AHT10Component::setup() {
void AHT10Component::restart_read_() {
if (this->read_count_ == AHT10_ATTEMPTS) {
this->read_count_ = 0;
this->status_set_error("Reading timed out");
this->status_set_error(LOG_STR("Reading timed out"));
return;
}
this->read_count_++;

View File

@@ -8,8 +8,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace alarm_control_panel {
namespace esphome::alarm_control_panel {
static const char *const TAG = "alarm_control_panel";
@@ -35,26 +34,12 @@ void AlarmControlPanel::publish_state(AlarmControlPanelState state) {
ESP_LOGD(TAG, "Set state to: %s, previous: %s", LOG_STR_ARG(alarm_control_panel_state_to_string(state)),
LOG_STR_ARG(alarm_control_panel_state_to_string(prev_state)));
this->current_state_ = state;
// Single state callback - triggers check get_state() for specific states
this->state_callback_.call();
#if defined(USE_ALARM_CONTROL_PANEL) && defined(USE_CONTROLLER_REGISTRY)
ControllerRegistry::notify_alarm_control_panel_update(this);
#endif
if (state == ACP_STATE_TRIGGERED) {
this->triggered_callback_.call();
} else if (state == ACP_STATE_ARMING) {
this->arming_callback_.call();
} else if (state == ACP_STATE_PENDING) {
this->pending_callback_.call();
} else if (state == ACP_STATE_ARMED_HOME) {
this->armed_home_callback_.call();
} else if (state == ACP_STATE_ARMED_NIGHT) {
this->armed_night_callback_.call();
} else if (state == ACP_STATE_ARMED_AWAY) {
this->armed_away_callback_.call();
} else if (state == ACP_STATE_DISARMED) {
this->disarmed_callback_.call();
}
// Cleared fires when leaving TRIGGERED state
if (prev_state == ACP_STATE_TRIGGERED) {
this->cleared_callback_.call();
}
@@ -69,34 +54,6 @@ void AlarmControlPanel::add_on_state_callback(std::function<void()> &&callback)
this->state_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_triggered_callback(std::function<void()> &&callback) {
this->triggered_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_arming_callback(std::function<void()> &&callback) {
this->arming_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_armed_home_callback(std::function<void()> &&callback) {
this->armed_home_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_armed_night_callback(std::function<void()> &&callback) {
this->armed_night_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_armed_away_callback(std::function<void()> &&callback) {
this->armed_away_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_pending_callback(std::function<void()> &&callback) {
this->pending_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_disarmed_callback(std::function<void()> &&callback) {
this->disarmed_callback_.add(std::move(callback));
}
void AlarmControlPanel::add_on_cleared_callback(std::function<void()> &&callback) {
this->cleared_callback_.add(std::move(callback));
}
@@ -157,5 +114,4 @@ void AlarmControlPanel::disarm(optional<std::string> code) {
call.perform();
}
} // namespace alarm_control_panel
} // namespace esphome
} // namespace esphome::alarm_control_panel

View File

@@ -1,7 +1,5 @@
#pragma once
#include <map>
#include "alarm_control_panel_call.h"
#include "alarm_control_panel_state.h"
@@ -9,8 +7,7 @@
#include "esphome/core/entity_base.h"
#include "esphome/core/log.h"
namespace esphome {
namespace alarm_control_panel {
namespace esphome::alarm_control_panel {
enum AlarmControlPanelFeature : uint8_t {
// Matches Home Assistant values
@@ -35,54 +32,13 @@ class AlarmControlPanel : public EntityBase {
*/
void publish_state(AlarmControlPanelState state);
/** Add a callback for when the state of the alarm_control_panel changes
/** Add a callback for when the state of the alarm_control_panel changes.
* Triggers can check get_state() to determine the new state.
*
* @param callback The callback function
*/
void add_on_state_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel chanes to triggered
*
* @param callback The callback function
*/
void add_on_triggered_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel chanes to arming
*
* @param callback The callback function
*/
void add_on_arming_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel changes to pending
*
* @param callback The callback function
*/
void add_on_pending_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel changes to armed_home
*
* @param callback The callback function
*/
void add_on_armed_home_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel changes to armed_night
*
* @param callback The callback function
*/
void add_on_armed_night_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel changes to armed_away
*
* @param callback The callback function
*/
void add_on_armed_away_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel changes to disarmed
*
* @param callback The callback function
*/
void add_on_disarmed_callback(std::function<void()> &&callback);
/** Add a callback for when the state of the alarm_control_panel clears from triggered
*
* @param callback The callback function
@@ -172,29 +128,14 @@ class AlarmControlPanel : public EntityBase {
uint32_t last_update_;
// the call control function
virtual void control(const AlarmControlPanelCall &call) = 0;
// state callback
CallbackManager<void()> state_callback_{};
// trigger callback
CallbackManager<void()> triggered_callback_{};
// arming callback
CallbackManager<void()> arming_callback_{};
// pending callback
CallbackManager<void()> pending_callback_{};
// armed_home callback
CallbackManager<void()> armed_home_callback_{};
// armed_night callback
CallbackManager<void()> armed_night_callback_{};
// armed_away callback
CallbackManager<void()> armed_away_callback_{};
// disarmed callback
CallbackManager<void()> disarmed_callback_{};
// clear callback
CallbackManager<void()> cleared_callback_{};
// state callback - triggers check get_state() for specific state
LazyCallbackManager<void()> state_callback_{};
// clear callback - fires when leaving TRIGGERED state
LazyCallbackManager<void()> cleared_callback_{};
// chime callback
CallbackManager<void()> chime_callback_{};
LazyCallbackManager<void()> chime_callback_{};
// ready callback
CallbackManager<void()> ready_callback_{};
LazyCallbackManager<void()> ready_callback_{};
};
} // namespace alarm_control_panel
} // namespace esphome
} // namespace esphome::alarm_control_panel

View File

@@ -4,8 +4,7 @@
#include "esphome/core/log.h"
namespace esphome {
namespace alarm_control_panel {
namespace esphome::alarm_control_panel {
static const char *const TAG = "alarm_control_panel";
@@ -99,5 +98,4 @@ void AlarmControlPanelCall::perform() {
}
}
} // namespace alarm_control_panel
} // namespace esphome
} // namespace esphome::alarm_control_panel

View File

@@ -6,8 +6,7 @@
#include "esphome/core/helpers.h"
namespace esphome {
namespace alarm_control_panel {
namespace esphome::alarm_control_panel {
class AlarmControlPanel;
@@ -36,5 +35,4 @@ class AlarmControlPanelCall {
void validate_();
};
} // namespace alarm_control_panel
} // namespace esphome
} // namespace esphome::alarm_control_panel

View File

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

View File

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

View File

@@ -3,9 +3,9 @@
#include "esphome/core/automation.h"
#include "alarm_control_panel.h"
namespace esphome {
namespace alarm_control_panel {
namespace esphome::alarm_control_panel {
/// Trigger on any state change
class StateTrigger : public Trigger<> {
public:
explicit StateTrigger(AlarmControlPanel *alarm_control_panel) {
@@ -13,55 +13,30 @@ class StateTrigger : public Trigger<> {
}
};
class TriggeredTrigger : public Trigger<> {
/// Template trigger that fires when entering a specific state
template<AlarmControlPanelState State> class StateEnterTrigger : public Trigger<> {
public:
explicit TriggeredTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_triggered_callback([this]() { this->trigger(); });
explicit StateEnterTrigger(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {
alarm_control_panel->add_on_state_callback([this]() {
if (this->alarm_control_panel_->get_state() == State)
this->trigger();
});
}
protected:
AlarmControlPanel *alarm_control_panel_;
};
class ArmingTrigger : public Trigger<> {
public:
explicit ArmingTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_arming_callback([this]() { this->trigger(); });
}
};
class PendingTrigger : public Trigger<> {
public:
explicit PendingTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_pending_callback([this]() { this->trigger(); });
}
};
class ArmedHomeTrigger : public Trigger<> {
public:
explicit ArmedHomeTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_armed_home_callback([this]() { this->trigger(); });
}
};
class ArmedNightTrigger : public Trigger<> {
public:
explicit ArmedNightTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_armed_night_callback([this]() { this->trigger(); });
}
};
class ArmedAwayTrigger : public Trigger<> {
public:
explicit ArmedAwayTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_armed_away_callback([this]() { this->trigger(); });
}
};
class DisarmedTrigger : public Trigger<> {
public:
explicit DisarmedTrigger(AlarmControlPanel *alarm_control_panel) {
alarm_control_panel->add_on_disarmed_callback([this]() { this->trigger(); });
}
};
// Type aliases for state-specific triggers
using TriggeredTrigger = StateEnterTrigger<ACP_STATE_TRIGGERED>;
using ArmingTrigger = StateEnterTrigger<ACP_STATE_ARMING>;
using PendingTrigger = StateEnterTrigger<ACP_STATE_PENDING>;
using ArmedHomeTrigger = StateEnterTrigger<ACP_STATE_ARMED_HOME>;
using ArmedNightTrigger = StateEnterTrigger<ACP_STATE_ARMED_NIGHT>;
using ArmedAwayTrigger = StateEnterTrigger<ACP_STATE_ARMED_AWAY>;
using DisarmedTrigger = StateEnterTrigger<ACP_STATE_DISARMED>;
/// Trigger when leaving TRIGGERED state (alarm cleared)
class ClearedTrigger : public Trigger<> {
public:
explicit ClearedTrigger(AlarmControlPanel *alarm_control_panel) {
@@ -69,6 +44,7 @@ class ClearedTrigger : public Trigger<> {
}
};
/// Trigger on chime event (zone opened while disarmed)
class ChimeTrigger : public Trigger<> {
public:
explicit ChimeTrigger(AlarmControlPanel *alarm_control_panel) {
@@ -76,6 +52,7 @@ class ChimeTrigger : public Trigger<> {
}
};
/// Trigger on ready state change
class ReadyTrigger : public Trigger<> {
public:
explicit ReadyTrigger(AlarmControlPanel *alarm_control_panel) {
@@ -187,5 +164,4 @@ template<typename... Ts> class AlarmControlPanelCondition : public Condition<Ts.
AlarmControlPanel *parent_;
};
} // namespace alarm_control_panel
} // namespace esphome
} // namespace esphome::alarm_control_panel

View File

@@ -56,13 +56,13 @@ bool Alpha3::is_current_response_type_(const uint8_t *response_type) {
void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) {
if (this->response_offset_ >= this->response_length_) {
ESP_LOGD(TAG, "[%s] GENI response begin", this->parent_->address_str().c_str());
ESP_LOGD(TAG, "[%s] GENI response begin", this->parent_->address_str());
if (length < GENI_RESPONSE_HEADER_LENGTH) {
ESP_LOGW(TAG, "[%s] response to short", this->parent_->address_str().c_str());
ESP_LOGW(TAG, "[%s] response too short", this->parent_->address_str());
return;
}
if (response[0] != 36 || response[2] != 248 || response[3] != 231 || response[4] != 10) {
ESP_LOGW(TAG, "[%s] response bytes %d %d %d %d %d don't match GENI HEADER", this->parent_->address_str().c_str(),
ESP_LOGW(TAG, "[%s] response bytes %d %d %d %d %d don't match GENI HEADER", this->parent_->address_str(),
response[0], response[1], response[2], response[3], response[4]);
return;
}
@@ -77,11 +77,11 @@ void Alpha3::handle_geni_response_(const uint8_t *response, uint16_t length) {
};
if (this->is_current_response_type_(GENI_RESPONSE_TYPE_FLOW_HEAD)) {
ESP_LOGD(TAG, "[%s] FLOW HEAD Response", this->parent_->address_str().c_str());
ESP_LOGD(TAG, "[%s] FLOW HEAD Response", this->parent_->address_str());
extract_publish_sensor_value(GENI_RESPONSE_FLOW_OFFSET, this->flow_sensor_, 3600.0F);
extract_publish_sensor_value(GENI_RESPONSE_HEAD_OFFSET, this->head_sensor_, .0001F);
} else if (this->is_current_response_type_(GENI_RESPONSE_TYPE_POWER)) {
ESP_LOGD(TAG, "[%s] POWER Response", this->parent_->address_str().c_str());
ESP_LOGD(TAG, "[%s] POWER Response", this->parent_->address_str());
extract_publish_sensor_value(GENI_RESPONSE_POWER_OFFSET, this->power_sensor_, 1.0F);
extract_publish_sensor_value(GENI_RESPONSE_CURRENT_OFFSET, this->current_sensor_, 1.0F);
extract_publish_sensor_value(GENI_RESPONSE_MOTOR_SPEED_OFFSET, this->speed_sensor_, 1.0F);
@@ -100,7 +100,7 @@ void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc
if (param->open.status == ESP_GATT_OK) {
this->response_offset_ = 0;
this->response_length_ = 0;
ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str().c_str());
ESP_LOGI(TAG, "[%s] connection open", this->parent_->address_str());
}
break;
}
@@ -132,7 +132,7 @@ void Alpha3::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc
case ESP_GATTC_SEARCH_CMPL_EVT: {
auto *chr = this->parent_->get_characteristic(ALPHA3_GENI_SERVICE_UUID, ALPHA3_GENI_CHARACTERISTIC_UUID);
if (chr == nullptr) {
ESP_LOGE(TAG, "[%s] No GENI service found at device, not an Alpha3..?", this->parent_->address_str().c_str());
ESP_LOGE(TAG, "[%s] No GENI service found at device, not an Alpha3..?", this->parent_->address_str());
break;
}
auto status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
@@ -164,12 +164,12 @@ void Alpha3::send_request_(uint8_t *request, size_t len) {
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->geni_handle_, len,
request, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status)
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
void Alpha3::update() {
if (this->node_state != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str().c_str());
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str());
return;
}

View File

@@ -44,11 +44,9 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
auto *chr = this->parent_->get_characteristic(AM43_SERVICE_UUID, AM43_CHARACTERISTIC_UUID);
if (chr == nullptr) {
if (this->parent_->get_characteristic(AM43_TUYA_SERVICE_UUID, AM43_TUYA_CHARACTERISTIC_UUID) != nullptr) {
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.",
this->parent_->address_str().c_str());
ESP_LOGE(TAG, "[%s] Detected a Tuya AM43 which is not supported, sorry.", this->parent_->address_str());
} else {
ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?",
this->parent_->address_str().c_str());
ESP_LOGE(TAG, "[%s] No control service found at device, not an AM43..?", this->parent_->address_str());
}
break;
}
@@ -82,8 +80,7 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
this->char_handle_, packet->length, packet->data,
ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
this->current_sensor_ = 0;
@@ -97,7 +94,7 @@ void Am43::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_i
void Am43::update() {
if (this->node_state != espbt::ClientState::ESTABLISHED) {
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str().c_str());
ESP_LOGW(TAG, "[%s] Cannot poll, not connected", this->parent_->address_str());
return;
}
if (this->current_sensor_ == 0) {
@@ -107,7 +104,7 @@ void Am43::update() {
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
packet->length, packet->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
this->current_sensor_++;

View File

@@ -12,10 +12,11 @@ void AnalogThresholdBinarySensor::setup() {
// TRUE state is defined to be when sensor is >= threshold
// so when undefined sensor value initialize to FALSE
if (std::isnan(sensor_value)) {
this->raw_state_ = false;
this->publish_initial_state(false);
} else {
this->publish_initial_state(sensor_value >=
(this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f);
this->raw_state_ = sensor_value >= (this->lower_threshold_.value() + this->upper_threshold_.value()) / 2.0f;
this->publish_initial_state(this->raw_state_);
}
}
@@ -25,8 +26,10 @@ void AnalogThresholdBinarySensor::set_sensor(sensor::Sensor *analog_sensor) {
this->sensor_->add_on_state_callback([this](float sensor_value) {
// if there is an invalid sensor reading, ignore the change and keep the current state
if (!std::isnan(sensor_value)) {
this->publish_state(sensor_value >=
(this->state ? this->lower_threshold_.value() : this->upper_threshold_.value()));
// Use raw_state_ for hysteresis logic, not this->state which is post-filter
this->raw_state_ =
sensor_value >= (this->raw_state_ ? this->lower_threshold_.value() : this->upper_threshold_.value());
this->publish_state(this->raw_state_);
}
});
}

View File

@@ -20,6 +20,7 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
sensor::Sensor *sensor_{nullptr};
TemplatableValue<float> upper_threshold_{};
TemplatableValue<float> lower_threshold_{};
bool raw_state_{false}; // Pre-filter state for hysteresis logic
};
} // namespace analog_threshold

View File

@@ -42,7 +42,7 @@ void Anova::control(const ClimateCall &call) {
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
if (call.get_target_temperature().has_value()) {
@@ -51,7 +51,7 @@ void Anova::control(const ClimateCall &call) {
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
}
@@ -124,8 +124,7 @@ void Anova::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(),
status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
}
}
@@ -150,7 +149,7 @@ void Anova::update() {
esp_ble_gattc_write_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(), this->char_handle_,
pkt->length, pkt->data, ESP_GATT_WRITE_TYPE_NO_RSP, ESP_GATT_AUTH_REQ_NONE);
if (status) {
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str().c_str(), status);
ESP_LOGW(TAG, "[%s] esp_ble_gattc_write_char failed, status=%d", this->parent_->address_str(), status);
}
this->current_request_++;
}

View File

@@ -27,12 +27,13 @@ from esphome.const import (
CONF_SERVICE,
CONF_SERVICES,
CONF_TAG,
CONF_THEN,
CONF_TRIGGER_ID,
CONF_VARIABLES,
)
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import TemplateArgsType
from esphome.types import ConfigType
from esphome.core import CORE, ID, CoroPriority, EsphomeError, coroutine_with_priority
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigFragmentType, ConfigType
_LOGGER = logging.getLogger(__name__)
@@ -63,17 +64,21 @@ HomeAssistantActionResponseTrigger = api_ns.class_(
"HomeAssistantActionResponseTrigger", automation.Trigger
)
APIConnectedCondition = api_ns.class_("APIConnectedCondition", Condition)
APIRespondAction = api_ns.class_("APIRespondAction", automation.Action)
APIUnregisterServiceCallAction = api_ns.class_(
"APIUnregisterServiceCallAction", automation.Action
)
UserServiceTrigger = api_ns.class_("UserServiceTrigger", automation.Trigger)
ListEntitiesServicesArgument = api_ns.class_("ListEntitiesServicesArgument")
SERVICE_ARG_NATIVE_TYPES = {
"bool": bool,
SERVICE_ARG_NATIVE_TYPES: dict[str, MockObj] = {
"bool": cg.bool_,
"int": cg.int32,
"float": float,
"float": cg.float_,
"string": cg.std_string,
"bool[]": cg.FixedVector.template(bool).operator("const").operator("ref"),
"bool[]": cg.FixedVector.template(cg.bool_).operator("const").operator("ref"),
"int[]": cg.FixedVector.template(cg.int32).operator("const").operator("ref"),
"float[]": cg.FixedVector.template(float).operator("const").operator("ref"),
"float[]": cg.FixedVector.template(cg.float_).operator("const").operator("ref"),
"string[]": cg.FixedVector.template(cg.std_string)
.operator("const")
.operator("ref"),
@@ -85,6 +90,7 @@ CONF_HOMEASSISTANT_SERVICES = "homeassistant_services"
CONF_HOMEASSISTANT_STATES = "homeassistant_states"
CONF_LISTEN_BACKLOG = "listen_backlog"
CONF_MAX_SEND_QUEUE = "max_send_queue"
CONF_STATE_SUBSCRIPTION_ONLY = "state_subscription_only"
def validate_encryption_key(value):
@@ -101,6 +107,85 @@ def validate_encryption_key(value):
return value
CONF_SUPPORTS_RESPONSE = "supports_response"
# Enum values in api::enums namespace
enums_ns = api_ns.namespace("enums")
SUPPORTS_RESPONSE_OPTIONS = {
"none": enums_ns.SUPPORTS_RESPONSE_NONE,
"optional": enums_ns.SUPPORTS_RESPONSE_OPTIONAL,
"only": enums_ns.SUPPORTS_RESPONSE_ONLY,
"status": enums_ns.SUPPORTS_RESPONSE_STATUS,
}
def _auto_detect_supports_response(config: ConfigType) -> ConfigType:
"""Auto-detect supports_response based on api.respond usage in the action's then block.
- If api.respond with data found: set to "optional" (unless user explicitly set)
- If api.respond without data found: set to "status" (unless user explicitly set)
- If no api.respond found: set to "none" (unless user explicitly set)
"""
def scan_actions(items: ConfigFragmentType) -> tuple[bool, bool]:
"""Recursively scan actions for api.respond.
Returns: (found, has_data) tuple - has_data is True if ANY api.respond has data
"""
found_any = False
has_data_any = False
if isinstance(items, list):
for item in items:
found, has_data = scan_actions(item)
if found:
found_any = True
has_data_any = has_data_any or has_data
elif isinstance(items, dict):
# Check if this is an api.respond action
if "api.respond" in items:
respond_config = items["api.respond"]
has_data = isinstance(respond_config, dict) and "data" in respond_config
return True, has_data
# Recursively check all values
for value in items.values():
found, has_data = scan_actions(value)
if found:
found_any = True
has_data_any = has_data_any or has_data
return found_any, has_data_any
then = config.get(CONF_THEN, [])
action_name = config.get(CONF_ACTION)
found, has_data = scan_actions(then)
# If user explicitly set supports_response, validate and use that
if CONF_SUPPORTS_RESPONSE in config:
user_value = config[CONF_SUPPORTS_RESPONSE]
# Validate: "only" requires api.respond with data
if user_value == "only" and not has_data:
raise cv.Invalid(
f"Action '{action_name}' has supports_response=only but no api.respond "
"action with 'data:' was found. Use 'status' for responses without data, "
"or add 'data:' to your api.respond action."
)
return config
# Auto-detect based on api.respond usage
if found:
config[CONF_SUPPORTS_RESPONSE] = "optional" if has_data else "status"
else:
config[CONF_SUPPORTS_RESPONSE] = "none"
return config
def _validate_supports_response(value):
"""Validate supports_response after auto-detection has set the value."""
return cv.enum(SUPPORTS_RESPONSE_OPTIONS, lower=True)(value)
ACTIONS_SCHEMA = automation.validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(UserServiceTrigger),
@@ -111,10 +196,20 @@ ACTIONS_SCHEMA = automation.validate_automation(
cv.validate_id_name: cv.one_of(*SERVICE_ARG_NATIVE_TYPES, lower=True),
}
),
# No default - auto-detected by _auto_detect_supports_response
cv.Optional(CONF_SUPPORTS_RESPONSE): cv.enum(
SUPPORTS_RESPONSE_OPTIONS, lower=True
),
},
cv.All(
cv.has_exactly_one_key(CONF_SERVICE, CONF_ACTION),
cv.rename_key(CONF_SERVICE, CONF_ACTION),
_auto_detect_supports_response,
# Re-validate supports_response after auto-detection sets it
cv.Schema(
{cv.Required(CONF_SUPPORTS_RESPONSE): _validate_supports_response},
extra=cv.ALLOW_EXTRA,
),
),
)
@@ -151,7 +246,7 @@ def _validate_api_config(config: ConfigType) -> ConfigType:
_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.html#configuration-variables"
"See https://esphome.io/components/api/#configuration-variables"
)
return config
@@ -241,7 +336,7 @@ CONFIG_SCHEMA = cv.All(
@coroutine_with_priority(CoroPriority.WEB)
async def to_code(config):
async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
@@ -260,9 +355,9 @@ async def to_code(config):
cg.add(var.set_max_connections(config[CONF_MAX_CONNECTIONS]))
cg.add_define("API_MAX_SEND_QUEUE", config[CONF_MAX_SEND_QUEUE])
# Set USE_API_SERVICES if any services are enabled
# Set USE_API_USER_DEFINED_ACTIONS if any services are enabled
if config.get(CONF_ACTIONS) or config[CONF_CUSTOM_SERVICES]:
cg.add_define("USE_API_SERVICES")
cg.add_define("USE_API_USER_DEFINED_ACTIONS")
# Set USE_API_CUSTOM_SERVICES if external components need dynamic service registration
if config[CONF_CUSTOM_SERVICES]:
@@ -278,20 +373,61 @@ async def to_code(config):
# Collect all triggers first, then register all at once with initializer_list
triggers: list[cg.Pvariable] = []
for conf in actions:
template_args = []
func_args = []
service_arg_names = []
func_args: list[tuple[MockObj, str]] = []
service_template_args: list[MockObj] = [] # User service argument types
# Determine supports_response mode
# cv.enum returns the key with enum_value attribute containing the MockObj
supports_response_key = conf[CONF_SUPPORTS_RESPONSE]
supports_response = supports_response_key.enum_value
is_none = supports_response_key == "none"
is_optional = supports_response_key == "optional"
# Add call_id and return_response based on supports_response mode
# These must match the C++ Trigger template arguments
# - none: no extra args
# - status: call_id only (for reporting success/error without data)
# - only: call_id only (response always expected with data)
# - optional: call_id + return_response (client decides)
if not is_none:
# call_id is present for "optional", "only", and "status"
func_args.append((cg.uint32, "call_id"))
# return_response only present for "optional"
if is_optional:
func_args.append((cg.bool_, "return_response"))
service_arg_names: list[str] = []
for name, var_ in conf[CONF_VARIABLES].items():
native = SERVICE_ARG_NATIVE_TYPES[var_]
template_args.append(native)
service_template_args.append(native)
func_args.append((native, name))
service_arg_names.append(name)
templ = cg.TemplateArguments(*template_args)
# Template args: supports_response mode, then user service arg types
templ = cg.TemplateArguments(supports_response, *service_template_args)
trigger = cg.new_Pvariable(
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
conf[CONF_TRIGGER_ID],
templ,
conf[CONF_ACTION],
service_arg_names,
)
triggers.append(trigger)
await automation.build_automation(trigger, func_args, conf)
auto = await automation.build_automation(trigger, func_args, conf)
# For non-none response modes, automatically append unregister action
# This ensures the call is unregistered after all actions complete (including async ones)
if not is_none:
arg_types = [arg[0] for arg in func_args]
action_templ = cg.TemplateArguments(*arg_types)
unregister_id = ID(
f"{conf[CONF_TRIGGER_ID]}__unregister",
is_declaration=True,
type=APIUnregisterServiceCallAction.template(action_templ),
)
unregister_action = cg.new_Pvariable(
unregister_id,
var,
)
cg.add(auto.add_actions([unregister_action]))
# Register all services at once - single allocation, no reallocations
cg.add(var.initialize_user_services(triggers))
@@ -537,9 +673,98 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg
return var
@automation.register_condition("api.connected", APIConnectedCondition, {})
CONF_SUCCESS = "success"
CONF_ERROR_MESSAGE = "error_message"
def _validate_api_respond_data(config):
"""Set flag during validation so AUTO_LOAD can include json component."""
if CONF_DATA in config:
CORE.data.setdefault(DOMAIN, {})[CONF_CAPTURE_RESPONSE] = True
return config
API_RESPOND_ACTION_SCHEMA = cv.All(
cv.Schema(
{
cv.GenerateID(): cv.use_id(APIServer),
cv.Optional(CONF_SUCCESS, default=True): cv.templatable(cv.boolean),
cv.Optional(CONF_ERROR_MESSAGE, default=""): cv.templatable(cv.string),
cv.Optional(CONF_DATA): cv.lambda_,
}
),
_validate_api_respond_data,
)
@automation.register_action(
"api.respond",
APIRespondAction,
API_RESPOND_ACTION_SCHEMA,
)
async def api_respond_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
# Validate that api.respond is used inside an API action context.
# We can't easily validate this at config time since the schema validation
# doesn't have access to the parent action context. Validating here in to_code
# is still much better than a cryptic C++ compile error.
has_call_id = any(name == "call_id" for _, name in args)
if not has_call_id:
raise EsphomeError(
"api.respond can only be used inside an API action's 'then:' block. "
"The 'call_id' variable is required to send a response."
)
cg.add_define("USE_API_USER_DEFINED_ACTION_RESPONSES")
serv = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, serv)
# Check if we're in optional mode (has return_response arg)
is_optional = any(name == "return_response" for _, name in args)
if is_optional:
cg.add(var.set_is_optional_mode(True))
templ = await cg.templatable(config[CONF_SUCCESS], args, cg.bool_)
cg.add(var.set_success(templ))
templ = await cg.templatable(config[CONF_ERROR_MESSAGE], args, cg.std_string)
cg.add(var.set_error_message(templ))
if CONF_DATA in config:
cg.add_define("USE_API_USER_DEFINED_ACTION_RESPONSES_JSON")
# Lambda populates the JsonObject root - no return value needed
lambda_ = await cg.process_lambda(
config[CONF_DATA],
args + [(cg.JsonObject, "root")],
return_type=cg.void,
)
cg.add(var.set_data(lambda_))
return var
API_CONNECTED_CONDITION_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.use_id(APIServer),
cv.Optional(CONF_STATE_SUBSCRIPTION_ONLY, default=False): cv.templatable(
cv.boolean
),
}
)
@automation.register_condition(
"api.connected", APIConnectedCondition, API_CONNECTED_CONDITION_SCHEMA
)
async def api_connected_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg)
var = cg.new_Pvariable(condition_id, template_arg)
templ = await cg.templatable(config[CONF_STATE_SUBSCRIPTION_ONLY], args, cg.bool_)
cg.add(var.set_state_subscription_only(templ))
return var
def FILTER_SOURCE_FILES() -> list[str]:

View File

@@ -102,7 +102,7 @@ message HelloRequest {
// For example "Home Assistant"
// Not strictly necessary to send but nice for debugging
// purposes.
string client_info = 1 [(pointer_to_buffer) = true];
string client_info = 1;
uint32 api_version_major = 2;
uint32 api_version_minor = 3;
}
@@ -139,7 +139,7 @@ message AuthenticationRequest {
option (ifdef) = "USE_API_PASSWORD";
// The password to log in with
string password = 1 [(pointer_to_buffer) = true];
string password = 1;
}
// Confirmation of successful connection. After this the connection is available for all traffic.
@@ -518,7 +518,7 @@ message ListEntitiesLightResponse {
bool legacy_supports_color_temperature = 8 [deprecated=true];
float min_mireds = 9;
float max_mireds = 10;
repeated string effects = 11;
repeated string effects = 11 [(container_pointer_no_template) = "FixedVector<const char *>"];
bool disabled_by_default = 13;
string icon = 14 [(field_ifdef) = "USE_ENTITY_ICON"];
EntityCategory entity_category = 15;
@@ -589,6 +589,7 @@ enum SensorStateClass {
STATE_CLASS_MEASUREMENT = 1;
STATE_CLASS_TOTAL_INCREASING = 2;
STATE_CLASS_TOTAL = 3;
STATE_CLASS_MEASUREMENT_ANGLE = 4;
}
// Deprecated in API version 1.5
@@ -795,7 +796,7 @@ message HomeassistantActionResponse {
uint32 call_id = 1; // Matches the call_id from HomeassistantActionRequest
bool success = 2; // Whether the service call succeeded
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 ====================
@@ -840,7 +841,7 @@ message GetTimeResponse {
option (no_delay) = true;
fixed32 epoch_seconds = 1;
string timezone = 2 [(pointer_to_buffer) = true];
string timezone = 2;
}
// ==================== USER-DEFINES SERVICES ====================
@@ -854,22 +855,31 @@ enum ServiceArgType {
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6;
SERVICE_ARG_TYPE_STRING_ARRAY = 7;
}
enum SupportsResponseType {
SUPPORTS_RESPONSE_NONE = 0;
SUPPORTS_RESPONSE_OPTIONAL = 1;
SUPPORTS_RESPONSE_ONLY = 2;
// Status-only response - reports success/error without data payload
// Value is higher to avoid conflicts with future Home Assistant values
SUPPORTS_RESPONSE_STATUS = 100;
}
message ListEntitiesServicesArgument {
option (ifdef) = "USE_API_SERVICES";
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
string name = 1;
ServiceArgType type = 2;
}
message ListEntitiesServicesResponse {
option (id) = 41;
option (source) = SOURCE_SERVER;
option (ifdef) = "USE_API_SERVICES";
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
string name = 1;
fixed32 key = 2;
repeated ListEntitiesServicesArgument args = 3 [(fixed_vector) = true];
SupportsResponseType supports_response = 4;
}
message ExecuteServiceArgument {
option (ifdef) = "USE_API_SERVICES";
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
bool bool_ = 1;
int32 legacy_int = 2;
float float_ = 3;
@@ -885,10 +895,25 @@ message ExecuteServiceRequest {
option (id) = 42;
option (source) = SOURCE_CLIENT;
option (no_delay) = true;
option (ifdef) = "USE_API_SERVICES";
option (ifdef) = "USE_API_USER_DEFINED_ACTIONS";
fixed32 key = 1;
repeated ExecuteServiceArgument args = 2 [(fixed_vector) = true];
uint32 call_id = 3 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES"];
bool return_response = 4 [(field_ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES"];
}
// Message sent by ESPHome to Home Assistant with service execution response data
message ExecuteServiceResponse {
option (id) = 131;
option (source) = SOURCE_SERVER;
option (no_delay) = true;
option (ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES";
uint32 call_id = 1; // Matches the call_id from ExecuteServiceRequest
bool success = 2; // Whether the service execution succeeded
string error_message = 3; // Error message if success = false
bytes response_data = 4 [(pointer_to_buffer) = true, (field_ifdef) = "USE_API_USER_DEFINED_ACTION_RESPONSES_JSON"];
}
// ==================== CAMERA ====================
@@ -1076,6 +1101,85 @@ message ClimateCommandRequest {
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 ====================
enum NumberMode {
NUMBER_MODE_AUTO = 0;
@@ -1188,7 +1292,7 @@ message ListEntitiesSirenResponse {
string icon = 5 [(field_ifdef) = "USE_ENTITY_ICON"];
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_volume = 9;
EntityCategory entity_category = 10;
@@ -1588,7 +1692,7 @@ message BluetoothGATTWriteRequest {
uint32 handle = 2;
bool response = 3;
bytes data = 4 [(pointer_to_buffer) = true];
bytes data = 4;
}
message BluetoothGATTReadDescriptorRequest {
@@ -1608,7 +1712,7 @@ message BluetoothGATTWriteDescriptorRequest {
uint64 address = 1;
uint32 handle = 2;
bytes data = 3 [(pointer_to_buffer) = true];
bytes data = 3;
}
message BluetoothGATTNotifyRequest {
@@ -1833,7 +1937,7 @@ message VoiceAssistantAudio {
option (source) = SOURCE_BOTH;
option (ifdef) = "USE_VOICE_ASSISTANT";
bytes data = 1;
bytes data = 1 [(pointer_to_buffer) = true];
bool end = 2;
}

View File

@@ -6,11 +6,18 @@
#ifdef USE_API_PLAINTEXT
#include "api_frame_helper_plaintext.h"
#endif
#ifdef USE_API_USER_DEFINED_ACTIONS
#include "user_services.h"
#endif
#include <cerrno>
#include <cinttypes>
#include <functional>
#include <limits>
#include <new>
#include <utility>
#ifdef USE_ESP8266
#include <pgmspace.h>
#endif
#include "esphome/components/network/util.h"
#include "esphome/core/application.h"
#include "esphome/core/entity_base.h"
@@ -36,6 +43,9 @@
#ifdef USE_ZWAVE_PROXY
#include "esphome/components/zwave_proxy/zwave_proxy.h"
#endif
#ifdef USE_WATER_HEATER
#include "esphome/components/water_heater/water_heater.h"
#endif
namespace esphome::api {
@@ -87,21 +97,18 @@ static const int CAMERA_STOP_STREAM = 5000;
return;
#endif // USE_DEVICES
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent) : parent_(parent) {
#if defined(USE_API_PLAINTEXT) && defined(USE_API_NOISE)
auto noise_ctx = parent->get_noise_ctx();
if (noise_ctx->has_psk()) {
this->helper_ =
std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx, &this->client_info_)};
auto &noise_ctx = parent->get_noise_ctx();
if (noise_ctx.has_psk()) {
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), noise_ctx)};
} else {
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
}
#elif defined(USE_API_PLAINTEXT)
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APIPlaintextFrameHelper(std::move(sock))};
#elif defined(USE_API_NOISE)
this->helper_ = std::unique_ptr<APIFrameHelper>{
new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx(), &this->client_info_)};
this->helper_ = std::unique_ptr<APIFrameHelper>{new APINoiseFrameHelper(std::move(sock), parent->get_noise_ctx())};
#else
#error "No frame helper defined"
#endif
@@ -122,11 +129,14 @@ void APIConnection::start() {
this->fatal_error_with_log_(LOG_STR("Helper init failed"), err);
return;
}
this->client_info_.peername = helper_->getpeername();
this->client_info_.name = this->client_info_.peername;
// Initialize client name with peername (IP address) until Hello message provides actual name
char peername[socket::PEERNAME_MAX_LEN];
size_t len = this->helper_->getpeername_to(peername);
this->helper_->set_client_name(peername, len);
}
APIConnection::~APIConnection() {
this->destroy_active_iterator_();
#ifdef USE_BLUETOOTH_PROXY
if (bluetooth_proxy::global_bluetooth_proxy->get_api_connection() == this) {
bluetooth_proxy::global_bluetooth_proxy->unsubscribe_api_connection(this);
@@ -139,6 +149,32 @@ APIConnection::~APIConnection() {
#endif
}
void APIConnection::destroy_active_iterator_() {
switch (this->active_iterator_) {
case ActiveIterator::LIST_ENTITIES:
this->iterator_storage_.list_entities.~ListEntitiesIterator();
break;
case ActiveIterator::INITIAL_STATE:
this->iterator_storage_.initial_state.~InitialStateIterator();
break;
case ActiveIterator::NONE:
break;
}
this->active_iterator_ = ActiveIterator::NONE;
}
void APIConnection::begin_iterator_(ActiveIterator type) {
this->destroy_active_iterator_();
this->active_iterator_ = type;
if (type == ActiveIterator::LIST_ENTITIES) {
new (&this->iterator_storage_.list_entities) ListEntitiesIterator(this);
this->iterator_storage_.list_entities.begin();
} else {
new (&this->iterator_storage_.initial_state) InitialStateIterator(this);
this->iterator_storage_.initial_state.begin();
}
}
void APIConnection::loop() {
if (this->flags_.next_close) {
// requested a disconnect
@@ -169,8 +205,7 @@ void APIConnection::loop() {
} else {
this->last_traffic_ = now;
// read a packet
this->read_message(buffer.data_len, buffer.type,
buffer.data_len > 0 ? &buffer.container[buffer.data_offset] : nullptr);
this->read_message(buffer.data_len, buffer.type, buffer.data);
if (this->flags_.remove)
return;
}
@@ -182,28 +217,42 @@ void APIConnection::loop() {
this->process_batch_();
}
if (!this->list_entities_iterator_.completed()) {
this->process_iterator_batch_(this->list_entities_iterator_);
} else if (!this->initial_state_iterator_.completed()) {
this->process_iterator_batch_(this->initial_state_iterator_);
// If we've completed initial states, process any remaining and clear the flag
if (this->initial_state_iterator_.completed()) {
// Process any remaining batched messages immediately
if (!this->deferred_batch_.empty()) {
this->process_batch_();
switch (this->active_iterator_) {
case ActiveIterator::LIST_ENTITIES:
if (this->iterator_storage_.list_entities.completed()) {
this->destroy_active_iterator_();
if (this->flags_.state_subscription) {
this->begin_iterator_(ActiveIterator::INITIAL_STATE);
}
} else {
this->process_iterator_batch_(this->iterator_storage_.list_entities);
}
// Now that everything is sent, enable immediate sending for future state changes
this->flags_.should_try_send_immediately = true;
}
break;
case ActiveIterator::INITIAL_STATE:
if (this->iterator_storage_.initial_state.completed()) {
this->destroy_active_iterator_();
// Process any remaining batched messages immediately
if (!this->deferred_batch_.empty()) {
this->process_batch_();
}
// Now that everything is sent, enable immediate sending for future state changes
this->flags_.should_try_send_immediately = true;
// Release excess memory from buffers that grew during initial sync
this->deferred_batch_.release_buffer();
this->helper_->release_buffers();
} else {
this->process_iterator_batch_(this->iterator_storage_.initial_state);
}
break;
case ActiveIterator::NONE:
break;
}
if (this->flags_.sent_ping) {
// Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
on_fatal_error();
ESP_LOGW(TAG, "%s (%s) is unresponsive; disconnecting", this->client_info_.name.c_str(),
this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("is unresponsive; disconnecting"));
}
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && !this->flags_.remove) {
// Only send ping if we're not disconnecting
@@ -220,40 +269,24 @@ void APIConnection::loop() {
}
}
#ifdef USE_CAMERA
if (this->image_reader_ && this->image_reader_->available() && this->helper_->can_write_without_blocking()) {
uint32_t to_send = std::min((size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available());
bool done = this->image_reader_->available() == to_send;
CameraImageResponse msg;
msg.key = camera::Camera::instance()->get_object_id_hash();
msg.set_data(this->image_reader_->peek_data_buffer(), to_send);
msg.done = done;
#ifdef USE_DEVICES
msg.device_id = camera::Camera::instance()->get_device_id();
#endif
if (this->send_message_(msg, CameraImageResponse::MESSAGE_TYPE)) {
this->image_reader_->consume_data(to_send);
if (done) {
this->image_reader_->return_image();
}
}
}
#endif
#ifdef USE_API_HOMEASSISTANT_STATES
if (state_subs_at_ >= 0) {
this->process_state_subscriptions_();
}
#endif
#ifdef USE_CAMERA
// Process camera last - state updates are higher priority
// (missing a frame is fine, missing a state update is not)
this->try_send_camera_image_();
#endif
}
bool APIConnection::send_disconnect_response(const DisconnectRequest &msg) {
// remote initiated disconnect_client
// don't close yet, we still need to send the disconnect response
// close will happen on next loop
ESP_LOGD(TAG, "%s (%s) disconnected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("disconnected"));
this->flags_.next_close = true;
DisconnectResponse resp;
return this->send_message(resp, DisconnectResponse::MESSAGE_TYPE);
@@ -439,7 +472,7 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
if (msg.has_direction)
call.set_direction(static_cast<fan::FanDirection>(msg.direction));
if (msg.has_preset_mode)
call.set_preset_mode(msg.preset_mode);
call.set_preset_mode(msg.preset_mode.c_str(), msg.preset_mode.size());
call.perform();
}
#endif
@@ -476,19 +509,24 @@ uint16_t APIConnection::try_send_light_info(EntityBase *entity, APIConnection *c
auto *light = static_cast<light::LightState *>(entity);
ListEntitiesLightResponse msg;
auto traits = light->get_traits();
auto supported_modes = traits.get_supported_color_modes();
// Pass pointer to ColorModeMask so the iterator can encode actual ColorMode enum values
msg.supported_color_modes = &traits.get_supported_color_modes();
msg.supported_color_modes = &supported_modes;
if (traits.supports_color_capability(light::ColorCapability::COLOR_TEMPERATURE) ||
traits.supports_color_capability(light::ColorCapability::COLD_WARM_WHITE)) {
msg.min_mireds = traits.get_min_mireds();
msg.max_mireds = traits.get_max_mireds();
}
FixedVector<const char *> effects_list;
if (light->supports_effects()) {
msg.effects.emplace_back("None");
for (auto *effect : light->get_effects()) {
msg.effects.emplace_back(effect->get_name());
auto &light_effects = light->get_effects();
effects_list.init(light_effects.size() + 1);
effects_list.push_back("None");
for (auto *effect : light_effects) {
effects_list.push_back(effect->get_name());
}
}
msg.effects = &effects_list;
return fill_and_encode_entity_info(light, msg, ListEntitiesLightResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
@@ -520,7 +558,7 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
if (msg.has_flash_length)
call.set_flash_length(msg.flash_length);
if (msg.has_effect)
call.set_effect(msg.effect);
call.set_effect(msg.effect.c_str(), msg.effect.size());
call.perform();
}
#endif
@@ -699,11 +737,11 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
if (msg.has_fan_mode)
call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
if (msg.has_custom_fan_mode)
call.set_fan_mode(msg.custom_fan_mode);
call.set_fan_mode(msg.custom_fan_mode.c_str(), msg.custom_fan_mode.size());
if (msg.has_preset)
call.set_preset(static_cast<climate::ClimatePreset>(msg.preset));
if (msg.has_custom_preset)
call.set_preset(msg.custom_preset);
call.set_preset(msg.custom_preset.c_str(), msg.custom_preset.size());
if (msg.has_swing_mode)
call.set_swing_mode(static_cast<climate::ClimateSwingMode>(msg.swing_mode));
call.perform();
@@ -892,7 +930,7 @@ uint16_t APIConnection::try_send_select_info(EntityBase *entity, APIConnection *
}
void APIConnection::select_command(const SelectCommandRequest &msg) {
ENTITY_COMMAND_MAKE_CALL(select::Select, select, select)
call.set_option(msg.state);
call.set_option(msg.state.c_str(), msg.state.size());
call.perform();
}
#endif
@@ -1044,6 +1082,36 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
#endif
#ifdef USE_CAMERA
void APIConnection::try_send_camera_image_() {
if (!this->image_reader_)
return;
// Send as many chunks as possible without blocking
while (this->image_reader_->available()) {
if (!this->helper_->can_write_without_blocking())
return;
uint32_t to_send = std::min((size_t) MAX_BATCH_PACKET_SIZE, this->image_reader_->available());
bool done = this->image_reader_->available() == to_send;
CameraImageResponse msg;
msg.key = camera::Camera::instance()->get_object_id_hash();
msg.set_data(this->image_reader_->peek_data_buffer(), to_send);
msg.done = done;
#ifdef USE_DEVICES
msg.device_id = camera::Camera::instance()->get_device_id();
#endif
if (!this->send_message_(msg, CameraImageResponse::MESSAGE_TYPE)) {
return; // Send failed, try again later
}
this->image_reader_->consume_data(to_send);
if (done) {
this->image_reader_->return_image();
return;
}
}
}
void APIConnection::set_camera_state(std::shared_ptr<camera::CameraImage> image) {
if (!this->flags_.state_subscription)
return;
@@ -1051,8 +1119,11 @@ void APIConnection::set_camera_state(std::shared_ptr<camera::CameraImage> image)
return;
if (this->image_reader_->available())
return;
if (image->was_requested_by(esphome::camera::API_REQUESTER) || image->was_requested_by(esphome::camera::IDLE))
if (image->was_requested_by(esphome::camera::API_REQUESTER) || image->was_requested_by(esphome::camera::IDLE)) {
this->image_reader_->set_image(std::move(image));
// Try to send immediately to reduce latency
this->try_send_camera_image_();
}
}
uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -1081,9 +1152,8 @@ void APIConnection::on_get_time_response(const GetTimeResponse &value) {
if (homeassistant::global_homeassistant_time != nullptr) {
homeassistant::global_homeassistant_time->set_epoch_time(value.epoch_seconds);
#ifdef USE_TIME_TIMEZONE
if (value.timezone_len > 0) {
homeassistant::global_homeassistant_time->set_timezone(reinterpret_cast<const char *>(value.timezone),
value.timezone_len);
if (!value.timezone.empty()) {
homeassistant::global_homeassistant_time->set_timezone(value.timezone.c_str(), value.timezone.size());
}
#endif
}
@@ -1293,10 +1363,61 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
}
#endif
#ifdef USE_WATER_HEATER
bool APIConnection::send_water_heater_state(water_heater::WaterHeater *water_heater) {
return this->send_message_smart_(water_heater, &APIConnection::try_send_water_heater_state,
WaterHeaterStateResponse::MESSAGE_TYPE, WaterHeaterStateResponse::ESTIMATED_SIZE);
}
uint16_t APIConnection::try_send_water_heater_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *wh = static_cast<water_heater::WaterHeater *>(entity);
WaterHeaterStateResponse resp;
resp.mode = static_cast<enums::WaterHeaterMode>(wh->get_mode());
resp.current_temperature = wh->get_current_temperature();
resp.target_temperature = wh->get_target_temperature();
resp.target_temperature_low = wh->get_target_temperature_low();
resp.target_temperature_high = wh->get_target_temperature_high();
resp.state = wh->get_state();
resp.key = wh->get_object_id_hash();
return encode_message_to_buffer(resp, WaterHeaterStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
uint16_t APIConnection::try_send_water_heater_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *wh = static_cast<water_heater::WaterHeater *>(entity);
ListEntitiesWaterHeaterResponse msg;
auto traits = wh->get_traits();
msg.min_temperature = traits.get_min_temperature();
msg.max_temperature = traits.get_max_temperature();
msg.target_temperature_step = traits.get_target_temperature_step();
msg.supported_modes = &traits.get_supported_modes();
msg.supported_features = traits.get_feature_flags();
return fill_and_encode_entity_info(wh, msg, ListEntitiesWaterHeaterResponse::MESSAGE_TYPE, conn, remaining_size,
is_single);
}
void APIConnection::on_water_heater_command_request(const WaterHeaterCommandRequest &msg) {
ENTITY_COMMAND_MAKE_CALL(water_heater::WaterHeater, water_heater, water_heater)
if (msg.has_fields & enums::WATER_HEATER_COMMAND_HAS_MODE)
call.set_mode(static_cast<water_heater::WaterHeaterMode>(msg.mode));
if (msg.has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE)
call.set_target_temperature(msg.target_temperature);
if (msg.has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW)
call.set_target_temperature_low(msg.target_temperature_low);
if (msg.has_fields & enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH)
call.set_target_temperature_high(msg.target_temperature_high);
if (msg.has_fields & enums::WATER_HEATER_COMMAND_HAS_STATE) {
call.set_away((msg.state & water_heater::WATER_HEATER_STATE_AWAY) != 0);
call.set_on((msg.state & water_heater::WATER_HEATER_STATE_ON) != 0);
}
call.perform();
}
#endif
#ifdef USE_EVENT
void APIConnection::send_event(event::Event *event, const char *event_type) {
this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
EventResponse::ESTIMATED_SIZE);
this->send_message_smart_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE,
EventResponse::ESTIMATED_SIZE);
}
uint16_t APIConnection::try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
uint32_t remaining_size, bool is_single) {
@@ -1382,9 +1503,12 @@ void APIConnection::complete_authentication_() {
}
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
ESP_LOGD(TAG, "%s (%s) connected", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("connected"));
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
this->parent_->get_client_connected_trigger()->trigger(this->client_info_.name, this->client_info_.peername);
char peername_buf[socket::PEERNAME_MAX_LEN];
this->helper_->getpeername_to(peername_buf);
this->parent_->get_client_connected_trigger()->trigger(std::string(this->helper_->get_client_name()),
std::string(peername_buf));
#endif
#ifdef USE_HOMEASSISTANT_TIME
if (homeassistant::global_homeassistant_time != nullptr) {
@@ -1399,16 +1523,18 @@ void APIConnection::complete_authentication_() {
}
bool APIConnection::send_hello_response(const HelloRequest &msg) {
this->client_info_.name.assign(reinterpret_cast<const char *>(msg.client_info), msg.client_info_len);
this->client_info_.peername = this->helper_->getpeername();
// Copy client name with truncation if needed (set_client_name handles truncation)
this->helper_->set_client_name(msg.client_info.c_str(), msg.client_info.size());
this->client_api_version_major_ = msg.api_version_major;
this->client_api_version_minor_ = msg.api_version_minor;
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->client_info_.name.c_str(),
this->client_info_.peername.c_str(), this->client_api_version_major_, this->client_api_version_minor_);
char peername[socket::PEERNAME_MAX_LEN];
this->helper_->getpeername_to(peername);
ESP_LOGV(TAG, "Hello from client: '%s' | %s | API Version %" PRIu32 ".%" PRIu32, this->helper_->get_client_name(),
peername, this->client_api_version_major_, this->client_api_version_minor_);
HelloResponse resp;
resp.api_version_major = 1;
resp.api_version_minor = 13;
resp.api_version_minor = 14;
// Send only the version string - the client only logs this for debugging and doesn't use it otherwise
resp.set_server_info(ESPHOME_VERSION_REF);
resp.set_name(StringRef(App.get_name()));
@@ -1427,7 +1553,7 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) {
bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) {
AuthenticationResponse resp;
// bool invalid_password = 1;
resp.invalid_password = !this->parent_->check_password(msg.password, msg.password_len);
resp.invalid_password = !this->parent_->check_password(msg.password.byte(), msg.password.size());
if (!resp.invalid_password) {
this->complete_authentication_();
}
@@ -1450,50 +1576,86 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
#ifdef USE_AREAS
resp.set_suggested_area(StringRef(App.get_area()));
#endif
// mac_address must store temporary string - will be valid during send_message call
std::string mac_address = get_mac_address_pretty();
// Stack buffer for MAC address (XX:XX:XX:XX:XX:XX\0 = 18 bytes)
char mac_address[18];
uint8_t mac[6];
get_mac_address_raw(mac);
format_mac_addr_upper(mac, mac_address);
resp.set_mac_address(StringRef(mac_address));
resp.set_esphome_version(ESPHOME_VERSION_REF);
resp.set_compilation_time(App.get_compilation_time_ref());
// Stack buffer for build time string
char build_time_str[Application::BUILD_TIME_STR_SIZE];
App.get_build_time_string(build_time_str);
resp.set_compilation_time(StringRef(build_time_str));
// Compile-time StringRef constants for manufacturers
// Manufacturer string - define once, handle ESP8266 PROGMEM separately
#if defined(USE_ESP8266) || defined(USE_ESP32)
static constexpr auto MANUFACTURER = StringRef::from_lit("Espressif");
#define ESPHOME_MANUFACTURER "Espressif"
#elif defined(USE_RP2040)
static constexpr auto MANUFACTURER = StringRef::from_lit("Raspberry Pi");
#define ESPHOME_MANUFACTURER "Raspberry Pi"
#elif defined(USE_BK72XX)
static constexpr auto MANUFACTURER = StringRef::from_lit("Beken");
#define ESPHOME_MANUFACTURER "Beken"
#elif defined(USE_LN882X)
static constexpr auto MANUFACTURER = StringRef::from_lit("Lightning");
#define ESPHOME_MANUFACTURER "Lightning"
#elif defined(USE_NRF52)
static constexpr auto MANUFACTURER = StringRef::from_lit("Nordic Semiconductor");
#define ESPHOME_MANUFACTURER "Nordic Semiconductor"
#elif defined(USE_RTL87XX)
static constexpr auto MANUFACTURER = StringRef::from_lit("Realtek");
#define ESPHOME_MANUFACTURER "Realtek"
#elif defined(USE_HOST)
static constexpr auto MANUFACTURER = StringRef::from_lit("Host");
#define ESPHOME_MANUFACTURER "Host"
#endif
resp.set_manufacturer(MANUFACTURER);
#ifdef USE_ESP8266
// ESP8266 requires PROGMEM for flash storage, copy to stack for memcpy compatibility
static const char MANUFACTURER_PROGMEM[] PROGMEM = ESPHOME_MANUFACTURER;
char manufacturer_buf[sizeof(MANUFACTURER_PROGMEM)];
memcpy_P(manufacturer_buf, MANUFACTURER_PROGMEM, sizeof(MANUFACTURER_PROGMEM));
resp.set_manufacturer(StringRef(manufacturer_buf, sizeof(MANUFACTURER_PROGMEM) - 1));
#else
static constexpr auto MANUFACTURER = StringRef::from_lit(ESPHOME_MANUFACTURER);
resp.set_manufacturer(MANUFACTURER);
#endif
#undef ESPHOME_MANUFACTURER
#ifdef USE_ESP8266
static const char MODEL_PROGMEM[] PROGMEM = ESPHOME_BOARD;
char model_buf[sizeof(MODEL_PROGMEM)];
memcpy_P(model_buf, MODEL_PROGMEM, sizeof(MODEL_PROGMEM));
resp.set_model(StringRef(model_buf, sizeof(MODEL_PROGMEM) - 1));
#else
static constexpr auto MODEL = StringRef::from_lit(ESPHOME_BOARD);
resp.set_model(MODEL);
#endif
#ifdef USE_DEEP_SLEEP
resp.has_deep_sleep = deep_sleep::global_has_deep_sleep;
#endif
#ifdef ESPHOME_PROJECT_NAME
#ifdef USE_ESP8266
static const char PROJECT_NAME_PROGMEM[] PROGMEM = ESPHOME_PROJECT_NAME;
static const char PROJECT_VERSION_PROGMEM[] PROGMEM = ESPHOME_PROJECT_VERSION;
char project_name_buf[sizeof(PROJECT_NAME_PROGMEM)];
char project_version_buf[sizeof(PROJECT_VERSION_PROGMEM)];
memcpy_P(project_name_buf, PROJECT_NAME_PROGMEM, sizeof(PROJECT_NAME_PROGMEM));
memcpy_P(project_version_buf, PROJECT_VERSION_PROGMEM, sizeof(PROJECT_VERSION_PROGMEM));
resp.set_project_name(StringRef(project_name_buf, sizeof(PROJECT_NAME_PROGMEM) - 1));
resp.set_project_version(StringRef(project_version_buf, sizeof(PROJECT_VERSION_PROGMEM) - 1));
#else
static constexpr auto PROJECT_NAME = StringRef::from_lit(ESPHOME_PROJECT_NAME);
static constexpr auto PROJECT_VERSION = StringRef::from_lit(ESPHOME_PROJECT_VERSION);
resp.set_project_name(PROJECT_NAME);
resp.set_project_version(PROJECT_VERSION);
#endif
#endif
#ifdef USE_WEBSERVER
resp.webserver_port = USE_WEBSERVER_PORT;
#endif
#ifdef USE_BLUETOOTH_PROXY
resp.bluetooth_proxy_feature_flags = bluetooth_proxy::global_bluetooth_proxy->get_feature_flags();
// bt_mac must store temporary string - will be valid during send_message call
std::string bluetooth_mac = bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty();
// Stack buffer for Bluetooth MAC address (XX:XX:XX:XX:XX:XX\0 = 18 bytes)
char bluetooth_mac[18];
bluetooth_proxy::global_bluetooth_proxy->get_bluetooth_mac_address_pretty(bluetooth_mac);
resp.set_bluetooth_mac_address(StringRef(bluetooth_mac));
#endif
#ifdef USE_VOICE_ASSISTANT
@@ -1533,25 +1695,92 @@ bool APIConnection::send_device_info_response(const DeviceInfoRequest &msg) {
#ifdef USE_API_HOMEASSISTANT_STATES
void APIConnection::on_home_assistant_state_response(const HomeAssistantStateResponse &msg) {
// Skip if entity_id is empty (invalid message)
if (msg.entity_id.empty()) {
return;
}
for (auto &it : this->parent_->get_state_subs()) {
if (it.entity_id == msg.entity_id && it.attribute.value() == msg.attribute) {
it.callback(msg.state);
// Compare entity_id: check length matches and content matches
size_t entity_id_len = strlen(it.entity_id);
if (entity_id_len != msg.entity_id.size() ||
memcmp(it.entity_id, msg.entity_id.c_str(), msg.entity_id.size()) != 0) {
continue;
}
// Compare attribute: either both have matching attribute, or both have none
size_t sub_attr_len = it.attribute != nullptr ? strlen(it.attribute) : 0;
if (sub_attr_len != msg.attribute.size() ||
(sub_attr_len > 0 && memcmp(it.attribute, msg.attribute.c_str(), sub_attr_len) != 0)) {
continue;
}
// Create null-terminated state for callback (parse_number needs null-termination)
// HA state max length is 255, so 256 byte buffer covers all cases
char state_buf[256];
size_t copy_len = msg.state_len;
if (copy_len >= sizeof(state_buf)) {
copy_len = sizeof(state_buf) - 1; // Truncate to leave space for null terminator
}
if (copy_len > 0) {
memcpy(state_buf, msg.state, copy_len);
}
state_buf[copy_len] = '\0';
it.callback(StringRef(state_buf, copy_len));
}
}
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void APIConnection::execute_service(const ExecuteServiceRequest &msg) {
bool found = false;
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Register the call and get a unique server-generated action_call_id
// This avoids collisions when multiple clients use the same call_id
uint32_t action_call_id = 0;
if (msg.call_id != 0) {
action_call_id = this->parent_->register_active_action_call(msg.call_id, this);
}
// Use the overload that passes action_call_id separately (avoids copying msg)
for (auto *service : this->parent_->get_user_services()) {
if (service->execute_service(msg, action_call_id)) {
found = true;
}
}
#else
for (auto *service : this->parent_->get_user_services()) {
if (service->execute_service(msg)) {
found = true;
}
}
#endif
if (!found) {
ESP_LOGV(TAG, "Could not find service");
}
// Note: For services with supports_response != none, the call is unregistered
// by an automatically appended APIUnregisterServiceCallAction at the end of
// the action list. This ensures async actions (delays, waits) complete first.
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, StringRef error_message) {
ExecuteServiceResponse resp;
resp.call_id = call_id;
resp.success = success;
resp.set_error_message(error_message);
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void APIConnection::send_execute_service_response(uint32_t call_id, bool success, StringRef error_message,
const uint8_t *response_data, size_t response_data_len) {
ExecuteServiceResponse resp;
resp.call_id = call_id;
resp.success = success;
resp.set_error_message(error_message);
resp.response_data = response_data;
resp.response_data_len = response_data_len;
this->send_message(resp, ExecuteServiceResponse::MESSAGE_TYPE);
}
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
#endif
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
@@ -1573,13 +1802,13 @@ bool APIConnection::send_noise_encryption_set_key_response(const NoiseEncryption
resp.success = false;
psk_t psk{};
if (msg.key.empty()) {
if (msg.key_len == 0) {
if (this->parent_->clear_noise_psk(true)) {
resp.success = true;
} else {
ESP_LOGW(TAG, "Failed to clear encryption key");
}
} else if (base64_decode(msg.key, psk.data(), msg.key.size()) != psk.size()) {
} else if (base64_decode(msg.key, msg.key_len, psk.data(), psk.size()) != psk.size()) {
ESP_LOGW(TAG, "Invalid encryption key length");
} else if (!this->parent_->save_noise_psk(psk, true)) {
ESP_LOGW(TAG, "Failed to save encryption key");
@@ -1631,12 +1860,12 @@ bool APIConnection::send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) {
#ifdef USE_API_PASSWORD
void APIConnection::on_unauthenticated_access() {
this->on_fatal_error();
ESP_LOGD(TAG, "%s (%s) no authentication", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("no authentication"));
}
#endif
void APIConnection::on_no_setup_connection() {
this->on_fatal_error();
ESP_LOGD(TAG, "%s (%s) no connection setup", this->client_info_.name.c_str(), this->client_info_.peername.c_str());
this->log_client_(ESPHOME_LOG_LEVEL_DEBUG, LOG_STR("no connection setup"));
}
void APIConnection::on_fatal_error() {
this->helper_->close();
@@ -1651,13 +1880,13 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
for (auto &item : items) {
if (item.entity == entity && item.message_type == message_type) {
// Replace with new creator
item.creator = std::move(creator);
item.creator = creator;
return;
}
}
// No existing item found, add new one
items.emplace_back(entity, std::move(creator), message_type, estimated_size);
items.emplace_back(entity, creator, message_type, estimated_size);
}
void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCreator creator, uint8_t message_type,
@@ -1666,7 +1895,7 @@ void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCre
// This avoids expensive vector::insert which shifts all elements
// Note: We only ever have one high-priority message at a time (ping OR disconnect)
// If we're disconnecting, pings are blocked, so this simple swap is sufficient
items.emplace_back(entity, std::move(creator), message_type, estimated_size);
items.emplace_back(entity, creator, message_type, estimated_size);
if (items.size() > 1) {
// Swap the new high-priority item to the front
std::swap(items.front(), items.back());
@@ -1874,8 +2103,8 @@ void APIConnection::process_state_subscriptions_() {
SubscribeHomeAssistantStateResponse resp;
resp.set_entity_id(StringRef(it.entity_id));
// Avoid string copy by directly using the optional's value if it exists
resp.set_attribute(it.attribute.has_value() ? StringRef(it.attribute.value()) : StringRef(""));
// Avoid string copy by using the const char* pointer if it exists
resp.set_attribute(it.attribute != nullptr ? StringRef(it.attribute) : StringRef(""));
resp.once = it.once;
if (this->send_message(resp, SubscribeHomeAssistantStateResponse::MESSAGE_TYPE)) {
@@ -1884,9 +2113,18 @@ void APIConnection::process_state_subscriptions_() {
}
#endif // USE_API_HOMEASSISTANT_STATES
void APIConnection::log_client_(int level, const LogString *message) {
char peername[socket::PEERNAME_MAX_LEN];
this->helper_->getpeername_to(peername);
esp_log_printf_(level, TAG, __LINE__, ESPHOME_LOG_FORMAT("%s (%s): %s"), this->helper_->get_client_name(), peername,
LOG_STR_ARG(message));
}
void APIConnection::log_warning_(const LogString *message, APIError err) {
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->client_info_.name.c_str(), this->client_info_.peername.c_str(),
LOG_STR_ARG(message), LOG_STR_ARG(api_error_to_logstr(err)), errno);
char peername[socket::PEERNAME_MAX_LEN];
this->helper_->getpeername_to(peername);
ESP_LOGW(TAG, "%s (%s): %s %s errno=%d", this->helper_->get_client_name(), peername, LOG_STR_ARG(message),
LOG_STR_ARG(api_error_to_logstr(err)), errno);
}
} // namespace esphome::api

View File

@@ -9,24 +9,20 @@
#include "esphome/core/application.h"
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/string_ref.h"
#include <functional>
#include <vector>
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
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
// 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,
// which reduced message sizes allowing more entities per batch without exceeding packet limits
static constexpr size_t MAX_INITIAL_PER_BATCH = 24;
// API 1.14+ clients compute object_id client-side, so messages are smaller and we can fit more per batch
// 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_LEGACY = 24; // For clients < API 1.14 (includes object_id)
static constexpr size_t MAX_INITIAL_PER_BATCH = 34; // For clients >= API 1.14 (no object_id)
// Maximum number of packets to process in a single batch (platform-dependent)
// This limit exists to prevent stack overflow from the PacketInfo array in process_batch_
// Each PacketInfo is 8 bytes, so 64 * 8 = 512 bytes, 32 * 8 = 256 bytes
@@ -176,6 +172,11 @@ class APIConnection final : public APIServerConnection {
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#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_EVENT
void send_event(event::Event *event, const char *event_type);
#endif
@@ -203,10 +204,14 @@ class APIConnection final : public APIServerConnection {
bool send_disconnect_response(const DisconnectRequest &msg) override;
bool send_ping_response(const PingRequest &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 {
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 {
this->flags_.log_subscription = msg.level;
@@ -221,8 +226,15 @@ class APIConnection final : public APIServerConnection {
#ifdef USE_API_HOMEASSISTANT_STATES
void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void execute_service(const ExecuteServiceRequest &msg) override;
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void send_execute_service_response(uint32_t call_id, bool success, StringRef error_message,
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
#endif
#ifdef USE_API_NOISE
bool send_noise_encryption_set_key_response(const NoiseEncryptionSetKeyRequest &msg) override;
@@ -273,13 +285,20 @@ class APIConnection final : public APIServerConnection {
bool try_to_clear_buffer(bool log_out_of_space);
bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) override;
const std::string &get_name() const { return this->client_info_.name; }
const std::string &get_peername() const { return this->client_info_.peername; }
const char *get_name() const { return this->helper_->get_client_name(); }
/// Get peer name (IP address) into a stack buffer - avoids heap allocation
size_t get_peername_to(std::span<char, socket::PEERNAME_MAX_LEN> buf) const {
return this->helper_->getpeername_to(buf);
}
protected:
// Helper function to handle authentication completion
void complete_authentication_();
#ifdef USE_CAMERA
void try_send_camera_image_();
#endif
#ifdef USE_API_HOMEASSISTANT_STATES
void process_state_subscriptions_();
#endif
@@ -303,16 +322,15 @@ class APIConnection final : public APIServerConnection {
APIConnection *conn, uint32_t remaining_size, bool is_single) {
// Set common fields that are shared by all entity types
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_();
// Store dynamic string outside the if-else to maintain lifetime
std::string object_id;
if (!static_ref.empty()) {
msg.set_object_id(static_ref);
} else {
// Dynamic case - need to allocate
object_id = entity->get_object_id();
msg.set_object_id(StringRef(object_id));
// API 1.14+ clients compute object_id client-side from the entity name
// For older clients, we must send object_id for backward compatibility
// See: https://github.com/esphome/backlog/issues/76
// TODO: Remove this backward compat code before 2026.7.0 - all clients should support API 1.14 by then
// Buffer must remain in scope until encode_message_to_buffer is called
char object_id_buf[OBJECT_ID_MAX_LEN];
if (!conn->client_supports_api_version(1, 14)) {
msg.set_object_id(entity->get_object_id_to(object_id_buf));
}
if (entity->has_own_name()) {
@@ -336,16 +354,24 @@ class APIConnection final : public APIServerConnection {
inline bool check_voice_assistant_api_connection_() const;
#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
template<typename Iterator> void process_iterator_batch_(Iterator &iterator) {
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();
}
// If the batch is full, process it immediately
// 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_();
}
}
@@ -449,6 +475,12 @@ class APIConnection final : public APIServerConnection {
static uint16_t try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
#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_EVENT
static uint16_t try_send_event_response(event::Event *event, const char *event_type, APIConnection *conn,
uint32_t remaining_size, bool is_single);
@@ -483,18 +515,27 @@ class APIConnection final : public APIServerConnection {
std::unique_ptr<APIFrameHelper> helper_;
APIServer *parent_;
// Group 2: Larger objects (must be 4-byte aligned)
// These contain vectors/pointers internally, so putting them early ensures good alignment
InitialStateIterator initial_state_iterator_;
ListEntitiesIterator list_entities_iterator_;
// Group 2: Iterator union (saves ~16 bytes vs separate iterators)
// These iterators are never active simultaneously - list_entities runs to completion
// before initial_state begins, so we use a union with explicit construction/destruction.
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
std::unique_ptr<camera::CameraImageReader> image_reader_;
#endif
// Group 3: Client info struct (24 bytes on 32-bit: 2 strings × 12 bytes each)
ClientInfo client_info_;
// Group 4: 4-byte types
// Group 3: 4-byte types
uint32_t last_traffic_;
#ifdef USE_API_HOMEASSISTANT_STATES
int state_subs_at_ = -1;
@@ -505,28 +546,9 @@ class APIConnection final : public APIServerConnection {
class MessageCreator {
public:
// Constructor for function pointer
MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; }
// Constructor for const char * (Event types - no allocation needed)
explicit MessageCreator(const char *str_value) { data_.const_char_ptr = str_value; }
// Delete copy operations - MessageCreator should only be moved
MessageCreator(const MessageCreator &other) = delete;
MessageCreator &operator=(const MessageCreator &other) = delete;
// Move constructor
MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.function_ptr = nullptr; }
// Move assignment
MessageCreator &operator=(MessageCreator &&other) noexcept {
if (this != &other) {
data_ = other.data_;
other.data_.function_ptr = nullptr;
}
return *this;
}
// 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;
@@ -535,7 +557,7 @@ class APIConnection final : public APIServerConnection {
union Data {
MessageCreatorPtr function_ptr;
const char *const_char_ptr;
} data_; // 4 bytes on 32-bit, 8 bytes on 64-bit - same as before
} data_; // 4 bytes on 32-bit, 8 bytes on 64-bit
};
// Generic batching mechanism for both state updates and entity info
@@ -548,16 +570,14 @@ class APIConnection final : public APIServerConnection {
// Constructor for creating BatchItem
BatchItem(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size)
: entity(entity), creator(std::move(creator)), message_type(message_type), estimated_size(estimated_size) {}
: entity(entity), creator(creator), message_type(message_type), estimated_size(estimated_size) {}
};
std::vector<BatchItem> items;
uint32_t batch_start_time{0};
DeferredBatch() {
// Pre-allocate capacity for typical batch sizes to avoid reallocation
items.reserve(8);
}
// No pre-allocation - log connections never use batching, and for
// connections that do, buffers are released after initial sync anyway
// Add item to the batch
void add_item(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size);
@@ -576,6 +596,15 @@ class APIConnection final : public APIServerConnection {
bool empty() const { return items.empty(); }
size_t size() const { return items.size(); }
const BatchItem &operator[](size_t index) const { return items[index]; }
// Release excess capacity - only releases if items already empty
void release_buffer() {
// Safe to call: batch is processed before release_buffer is called,
// and if any items remain (partial processing), we must not clear them.
// Use swap trick since shrink_to_fit() is non-binding and may be ignored.
if (items.empty()) {
std::vector<BatchItem>().swap(items);
}
}
};
// DeferredBatch here (16 bytes, 4-byte aligned)
@@ -613,7 +642,9 @@ class APIConnection final : public APIServerConnection {
// 2-byte types immediately after flags_ (no padding between them)
uint16_t client_api_version_major_{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;
// Message will use 8 more bytes than the minimum size, and typical
@@ -650,21 +681,30 @@ class APIConnection final : public APIServerConnection {
}
#endif
// Helper to check if a message type should bypass batching
// Returns true if:
// 1. It's an UpdateStateResponse (always send immediately to handle cases where
// the main loop is blocked, e.g., during OTA updates)
// 2. It's an EventResponse (events are edge-triggered - every occurrence matters)
// 3. OR: User has opted into immediate sending (should_try_send_immediately = true
// AND batch_delay = 0)
inline bool should_send_immediately_(uint8_t message_type) const {
return (
#ifdef USE_UPDATE
message_type == UpdateStateResponse::MESSAGE_TYPE ||
#endif
#ifdef USE_EVENT
message_type == EventResponse::MESSAGE_TYPE ||
#endif
(this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0));
}
// Helper method to send a message either immediately or via batching
// 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
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint8_t message_type,
uint8_t estimated_size) {
// Try to send immediately if:
// 1. It's an UpdateStateResponse (always send immediately to handle cases where
// the main loop is blocked, e.g., during OTA updates)
// 2. OR: We should try to send immediately (should_try_send_immediately = true)
// AND Batch delay is 0 (user has opted in to immediate sending)
// 3. AND: Buffer has space available
if ((
#ifdef USE_UPDATE
message_type == UpdateStateResponse::MESSAGE_TYPE ||
#endif
(this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0)) &&
this->helper_->can_write_without_blocking()) {
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) &&
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
@@ -682,9 +722,30 @@ class APIConnection final : public APIServerConnection {
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
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint8_t message_type, uint8_t estimated_size) {
this->deferred_batch_.add_item(entity, std::move(creator), message_type, estimated_size);
this->deferred_batch_.add_item(entity, creator, message_type, estimated_size);
return this->schedule_batch_();
}
@@ -701,6 +762,8 @@ class APIConnection final : public APIServerConnection {
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
void log_warning_(const LogString *message, APIError err);
// Helper to handle fatal errors with logging

View File

@@ -1,6 +1,5 @@
#include "api_frame_helper.h"
#ifdef USE_API
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
@@ -13,12 +12,34 @@ namespace esphome::api {
static const char *const TAG = "api.frame_helper";
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
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_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
do { \
char peername__[socket::PEERNAME_MAX_LEN]; \
this->socket_->getpeername_to(peername__); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \
} while (0)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
#define LOG_PACKET_RECEIVED(buffer) \
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
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0)

View File

@@ -29,16 +29,15 @@ 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
#endif
// Forward declaration
struct ClientInfo;
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 {
std::vector<uint8_t> container;
uint16_t type;
uint16_t data_offset;
const uint8_t *data; // Points directly into frame helper's rx_buf_ (valid until next read_packet call)
uint16_t data_len;
uint16_t type;
};
// Packed packet info structure to minimize memory usage
@@ -83,17 +82,23 @@ const LogString *api_error_to_logstr(APIError err);
class APIFrameHelper {
public:
APIFrameHelper() = default;
explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info)
: socket_owned_(std::move(socket)), client_info_(client_info) {
socket_ = socket_owned_.get();
explicit APIFrameHelper(std::unique_ptr<socket::Socket> socket) : socket_(std::move(socket)) {}
// Get client name (null-terminated)
const char *get_client_name() const { return this->client_name_; }
// 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 APIError init() = 0;
virtual APIError loop();
virtual APIError read_packet(ReadPacketBuffer *buffer) = 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); }
size_t getpeername_to(std::span<char, socket::PEERNAME_MAX_LEN> buf) { return socket_->getpeername_to(buf); }
APIError close() {
state_ = State::CLOSED;
int err = this->socket_->close();
@@ -121,6 +126,22 @@ class APIFrameHelper {
uint8_t frame_footer_size() const { return frame_footer_size_; }
// Check if socket has data ready to read
bool is_socket_ready() const { return socket_ != nullptr && socket_->ready(); }
// Release excess memory from internal buffers after initial sync
void release_buffers() {
// rx_buf_: Safe to clear only if no partial read in progress.
// rx_buf_len_ tracks bytes read so far; if non-zero, we're mid-frame
// and clearing would lose partially received data.
if (this->rx_buf_len_ == 0) {
// Use swap trick since shrink_to_fit() is non-binding and may be ignored
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:
// Buffer containing data to be sent
@@ -149,9 +170,8 @@ class APIFrameHelper {
APIError write_raw_(const struct iovec *iov, int iovcnt, socket::Socket *socket, std::vector<uint8_t> &tx_buf,
const std::string &info, StateEnum &state, StateEnum failed_state);
// Pointers first (4 bytes each)
socket::Socket *socket_{nullptr};
std::unique_ptr<socket::Socket> socket_owned_;
// Socket ownership (4 bytes on 32-bit, 8 bytes on 64-bit)
std::unique_ptr<socket::Socket> socket_;
// Common state enum for all frame helpers
// Note: Not all states are used by all implementations
@@ -177,9 +197,8 @@ class APIFrameHelper {
std::vector<struct iovec> reusable_iovs_;
std::vector<uint8_t> rx_buf_;
// Pointer to client info (4 bytes on 32-bit)
// Note: The pointed-to ClientInfo object must outlive this APIFrameHelper instance.
const ClientInfo *client_info_{nullptr};
// Client name buffer - stores name from Hello message or initial peername
char client_name_[CLIENT_INFO_NAME_MAX_LEN]{};
// Group smaller types together
uint16_t rx_buf_len_ = 0;

View File

@@ -24,12 +24,34 @@ static const char *const PROLOGUE_INIT = "NoiseAPIInit";
#endif
static constexpr size_t PROLOGUE_INIT_LEN = 12; // strlen("NoiseAPIInit")
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
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_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
do { \
char peername__[socket::PEERNAME_MAX_LEN]; \
this->socket_->getpeername_to(peername__); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \
} while (0)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
#define LOG_PACKET_RECEIVED(buffer) \
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
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0)
@@ -239,12 +261,13 @@ APIError APINoiseFrameHelper::state_action_() {
}
if (state_ == State::SERVER_HELLO) {
// send server hello
constexpr size_t mac_len = 13; // 12 hex chars + null terminator
const std::string &name = App.get_name();
const std::string &mac = get_mac_address();
char mac[mac_len];
get_mac_address_into_buffer(mac);
// Calculate positions and sizes
size_t name_len = name.size() + 1; // including null terminator
size_t mac_len = mac.size() + 1; // including null terminator
size_t name_offset = 1;
size_t mac_offset = name_offset + name_len;
size_t total_size = 1 + name_len + mac_len;
@@ -257,7 +280,7 @@ APIError APINoiseFrameHelper::state_action_() {
// node name, terminated by null byte
std::memcpy(msg.get() + name_offset, name.c_str(), name_len);
// node mac, terminated by null byte
std::memcpy(msg.get() + mac_offset, mac.c_str(), mac_len);
std::memcpy(msg.get() + mac_offset, mac, mac_len);
aerr = write_frame_(msg.get(), total_size);
if (aerr != APIError::OK)
@@ -406,8 +429,7 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return APIError::BAD_DATA_PACKET;
}
buffer->container = std::move(this->rx_buf_);
buffer->data_offset = 4;
buffer->data = msg_data + 4; // Skip 4-byte header (type + length)
buffer->data_len = data_len;
buffer->type = type;
return APIError::OK;
@@ -527,7 +549,7 @@ APIError APINoiseFrameHelper::init_handshake_() {
if (aerr != APIError::OK)
return aerr;
const auto &psk = ctx_->get_psk();
const auto &psk = this->ctx_.get_psk();
err = noise_handshakestate_set_pre_shared_key(handshake_, psk.data(), psk.size());
aerr = handle_noise_error_(err, LOG_STR("noise_handshakestate_set_pre_shared_key"),
APIError::HANDSHAKESTATE_SETUP_FAILED);
@@ -539,7 +561,8 @@ APIError APINoiseFrameHelper::init_handshake_() {
if (aerr != APIError::OK)
return aerr;
// set_prologue copies it into handshakestate, so we can get rid of it now
prologue_ = {};
// Use swap idiom to actually release memory (= {} only clears size, not capacity)
std::vector<uint8_t>().swap(prologue_);
err = noise_handshakestate_start(handshake_);
aerr = handle_noise_error_(err, LOG_STR("noise_handshakestate_start"), APIError::HANDSHAKESTATE_SETUP_FAILED);

View File

@@ -9,9 +9,8 @@ namespace esphome::api {
class APINoiseFrameHelper final : public APIFrameHelper {
public:
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, std::shared_ptr<APINoiseContext> ctx,
const ClientInfo *client_info)
: APIFrameHelper(std::move(socket), client_info), ctx_(std::move(ctx)) {
APINoiseFrameHelper(std::unique_ptr<socket::Socket> socket, APINoiseContext &ctx)
: APIFrameHelper(std::move(socket)), ctx_(ctx) {
// Noise header structure:
// Pos 0: indicator (0x01)
// Pos 1-2: encrypted payload size (16-bit big-endian)
@@ -41,8 +40,8 @@ class APINoiseFrameHelper final : public APIFrameHelper {
NoiseCipherState *send_cipher_{nullptr};
NoiseCipherState *recv_cipher_{nullptr};
// Shared pointer (8 bytes on 32-bit = 4 bytes control block pointer + 4 bytes object pointer)
std::shared_ptr<APINoiseContext> ctx_;
// Reference to noise context (4 bytes on 32-bit)
APINoiseContext &ctx_;
// Vector (12 bytes on 32-bit)
std::vector<uint8_t> prologue_;

View File

@@ -1,7 +1,6 @@
#include "api_frame_helper_plaintext.h"
#ifdef USE_API
#ifdef USE_API_PLAINTEXT
#include "api_connection.h" // For ClientInfo struct
#include "esphome/core/application.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
@@ -18,12 +17,34 @@ namespace esphome::api {
static const char *const TAG = "api.plaintext";
// Maximum bytes to log in hex format (168 * 3 = 504, under TX buffer size of 512)
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_info_->name.c_str(), this->client_info_->peername.c_str(), ##__VA_ARGS__)
do { \
char peername__[socket::PEERNAME_MAX_LEN]; \
this->socket_->getpeername_to(peername__); \
ESP_LOGVV(TAG, "%s (%s): " msg, this->client_name_, peername__, ##__VA_ARGS__); \
} while (0)
#else
#define HELPER_LOG(msg, ...) ((void) 0)
#endif
#ifdef HELPER_LOG_PACKETS
#define LOG_PACKET_RECEIVED(buffer) ESP_LOGVV(TAG, "Received frame: %s", format_hex_pretty(buffer).c_str())
#define LOG_PACKET_SENDING(data, len) ESP_LOGVV(TAG, "Sending raw: %s", format_hex_pretty(data, len).c_str())
#define LOG_PACKET_RECEIVED(buffer) \
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
#define LOG_PACKET_RECEIVED(buffer) ((void) 0)
#define LOG_PACKET_SENDING(data, len) ((void) 0)
@@ -210,8 +231,7 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return aerr;
}
buffer->container = std::move(this->rx_buf_);
buffer->data_offset = 0;
buffer->data = this->rx_buf_.data();
buffer->data_len = this->rx_header_parsed_len_;
buffer->type = this->rx_header_parsed_type_;
return APIError::OK;

View File

@@ -7,8 +7,7 @@ namespace esphome::api {
class APIPlaintextFrameHelper final : public APIFrameHelper {
public:
APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket, const ClientInfo *client_info)
: APIFrameHelper(std::move(socket), client_info) {
explicit APIPlaintextFrameHelper(std::unique_ptr<socket::Socket> socket) : APIFrameHelper(std::move(socket)) {
// Plaintext header structure (worst case):
// Pos 0: indicator (0x00)
// Pos 1-3: payload size varint (up to 3 bytes)

View File

@@ -23,9 +23,7 @@ bool HelloRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
// Use raw data directly to avoid allocation
this->client_info = value.data();
this->client_info_len = value.size();
this->client_info = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
@@ -49,9 +47,7 @@ void HelloResponse::calculate_size(ProtoSize &size) const {
bool AuthenticationRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
// Use raw data directly to avoid allocation
this->password = value.data();
this->password_len = value.size();
this->password = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
@@ -124,12 +120,12 @@ void DeviceInfoResponse::encode(ProtoWriteBuffer buffer) const {
#endif
#ifdef USE_DEVICES
for (const auto &it : this->devices) {
buffer.encode_message(20, it, true);
buffer.encode_message(20, it);
}
#endif
#ifdef USE_AREAS
for (const auto &it : this->areas) {
buffer.encode_message(21, it, true);
buffer.encode_message(21, it);
}
#endif
#ifdef USE_AREAS
@@ -447,9 +443,10 @@ bool FanCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool FanCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 13:
this->preset_mode = value.as_string();
case 13: {
this->preset_mode = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -476,8 +473,8 @@ void ListEntitiesLightResponse::encode(ProtoWriteBuffer buffer) const {
}
buffer.encode_float(9, this->min_mireds);
buffer.encode_float(10, this->max_mireds);
for (auto &it : this->effects) {
buffer.encode_string(11, it, true);
for (const char *it : *this->effects) {
buffer.encode_string(11, it, strlen(it), true);
}
buffer.encode_bool(13, this->disabled_by_default);
#ifdef USE_ENTITY_ICON
@@ -499,9 +496,9 @@ void ListEntitiesLightResponse::calculate_size(ProtoSize &size) const {
}
size.add_float(1, this->min_mireds);
size.add_float(1, this->max_mireds);
if (!this->effects.empty()) {
for (const auto &it : this->effects) {
size.add_length_force(1, it.size());
if (!this->effects->empty()) {
for (const char *it : *this->effects) {
size.add_length_force(1, strlen(it));
}
}
size.add_bool(1, this->disabled_by_default);
@@ -611,9 +608,10 @@ bool LightCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool LightCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 19:
this->effect = value.as_string();
case 19: {
this->effect = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -852,9 +850,11 @@ void SubscribeLogsResponse::calculate_size(ProtoSize &size) const {
#ifdef USE_API_NOISE
bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->key = value.as_string();
case 1: {
this->key = value.data();
this->key_len = value.size();
break;
}
default:
return false;
}
@@ -875,13 +875,13 @@ void HomeassistantServiceMap::calculate_size(ProtoSize &size) const {
void HomeassistantActionRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->service_ref_);
for (auto &it : this->data) {
buffer.encode_message(2, it, true);
buffer.encode_message(2, it);
}
for (auto &it : this->data_template) {
buffer.encode_message(3, it, true);
buffer.encode_message(3, it);
}
for (auto &it : this->variables) {
buffer.encode_message(4, it, true);
buffer.encode_message(4, it);
}
buffer.encode_bool(5, this->is_event);
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
@@ -927,12 +927,12 @@ bool HomeassistantActionResponse::decode_varint(uint32_t field_id, ProtoVarInt v
}
bool HomeassistantActionResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3:
this->error_message = value.as_string();
case 3: {
this->error_message = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
case 4: {
// Use raw data directly to avoid allocation
this->response_data = value.data();
this->response_data_len = value.size();
break;
@@ -957,15 +957,18 @@ void SubscribeHomeAssistantStateResponse::calculate_size(ProtoSize &size) const
}
bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->entity_id = value.as_string();
case 1: {
this->entity_id = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 2:
this->state = value.as_string();
}
case 2: {
this->state = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 3:
this->attribute = value.as_string();
}
case 3: {
this->attribute = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -975,9 +978,7 @@ bool HomeAssistantStateResponse::decode_length(uint32_t field_id, ProtoLengthDel
bool GetTimeResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
// Use raw data directly to avoid allocation
this->timezone = value.data();
this->timezone_len = value.size();
this->timezone = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
@@ -995,7 +996,7 @@ bool GetTimeResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
}
return true;
}
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void ListEntitiesServicesArgument::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->name_ref_);
buffer.encode_uint32(2, static_cast<uint32_t>(this->type));
@@ -1008,13 +1009,15 @@ void ListEntitiesServicesResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->name_ref_);
buffer.encode_fixed32(2, this->key);
for (auto &it : this->args) {
buffer.encode_message(3, it, true);
buffer.encode_message(3, it);
}
buffer.encode_uint32(4, static_cast<uint32_t>(this->supports_response));
}
void ListEntitiesServicesResponse::calculate_size(ProtoSize &size) const {
size.add_length(1, this->name_ref_.size());
size.add_fixed32(1, this->key);
size.add_repeated_message(1, this->args);
size.add_uint32(1, static_cast<uint32_t>(this->supports_response));
}
bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
@@ -1040,9 +1043,10 @@ bool ExecuteServiceArgument::decode_varint(uint32_t field_id, ProtoVarInt value)
}
bool ExecuteServiceArgument::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4:
this->string_ = value.as_string();
case 4: {
this->string_ = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
case 9:
this->string_array.push_back(value.as_string());
break;
@@ -1075,6 +1079,23 @@ void ExecuteServiceArgument::decode(const uint8_t *buffer, size_t length) {
this->string_array.init(count_string_array);
ProtoDecodableMessage::decode(buffer, length);
}
bool ExecuteServiceRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
case 3:
this->call_id = value.as_uint32();
break;
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
case 4:
this->return_response = value.as_bool();
break;
#endif
default:
return false;
}
return true;
}
bool ExecuteServiceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2:
@@ -1102,6 +1123,24 @@ void ExecuteServiceRequest::decode(const uint8_t *buffer, size_t length) {
ProtoDecodableMessage::decode(buffer, length);
}
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
void ExecuteServiceResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(1, this->call_id);
buffer.encode_bool(2, this->success);
buffer.encode_string(3, this->error_message_ref_);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
buffer.encode_bytes(4, this->response_data, this->response_data_len);
#endif
}
void ExecuteServiceResponse::calculate_size(ProtoSize &size) const {
size.add_uint32(1, this->call_id);
size.add_bool(1, this->success);
size.add_length(1, this->error_message_ref_.size());
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
size.add_length(1, this->response_data_len);
#endif
}
#endif
#ifdef USE_CAMERA
void ListEntitiesCameraResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id_ref_);
@@ -1352,12 +1391,14 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
}
bool ClimateCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 17:
this->custom_fan_mode = value.as_string();
case 17: {
this->custom_fan_mode = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 21:
this->custom_preset = value.as_string();
}
case 21: {
this->custom_preset = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -1386,6 +1427,114 @@ bool ClimateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
return true;
}
#endif
#ifdef USE_WATER_HEATER
void ListEntitiesWaterHeaterResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id_ref_);
buffer.encode_fixed32(2, this->key);
buffer.encode_string(3, this->name_ref_);
#ifdef USE_ENTITY_ICON
buffer.encode_string(4, this->icon_ref_);
#endif
buffer.encode_bool(5, this->disabled_by_default);
buffer.encode_uint32(6, static_cast<uint32_t>(this->entity_category));
#ifdef USE_DEVICES
buffer.encode_uint32(7, this->device_id);
#endif
buffer.encode_float(8, this->min_temperature);
buffer.encode_float(9, this->max_temperature);
buffer.encode_float(10, this->target_temperature_step);
for (const auto &it : *this->supported_modes) {
buffer.encode_uint32(11, static_cast<uint32_t>(it), true);
}
buffer.encode_uint32(12, this->supported_features);
}
void ListEntitiesWaterHeaterResponse::calculate_size(ProtoSize &size) const {
size.add_length(1, this->object_id_ref_.size());
size.add_fixed32(1, this->key);
size.add_length(1, this->name_ref_.size());
#ifdef USE_ENTITY_ICON
size.add_length(1, this->icon_ref_.size());
#endif
size.add_bool(1, this->disabled_by_default);
size.add_uint32(1, static_cast<uint32_t>(this->entity_category));
#ifdef USE_DEVICES
size.add_uint32(1, this->device_id);
#endif
size.add_float(1, this->min_temperature);
size.add_float(1, this->max_temperature);
size.add_float(1, this->target_temperature_step);
if (!this->supported_modes->empty()) {
for (const auto &it : *this->supported_modes) {
size.add_uint32_force(1, static_cast<uint32_t>(it));
}
}
size.add_uint32(1, this->supported_features);
}
void WaterHeaterStateResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_float(2, this->current_temperature);
buffer.encode_float(3, this->target_temperature);
buffer.encode_uint32(4, static_cast<uint32_t>(this->mode));
#ifdef USE_DEVICES
buffer.encode_uint32(5, this->device_id);
#endif
buffer.encode_uint32(6, this->state);
buffer.encode_float(7, this->target_temperature_low);
buffer.encode_float(8, this->target_temperature_high);
}
void WaterHeaterStateResponse::calculate_size(ProtoSize &size) const {
size.add_fixed32(1, this->key);
size.add_float(1, this->current_temperature);
size.add_float(1, this->target_temperature);
size.add_uint32(1, static_cast<uint32_t>(this->mode));
#ifdef USE_DEVICES
size.add_uint32(1, this->device_id);
#endif
size.add_uint32(1, this->state);
size.add_float(1, this->target_temperature_low);
size.add_float(1, this->target_temperature_high);
}
bool WaterHeaterCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
switch (field_id) {
case 2:
this->has_fields = value.as_uint32();
break;
case 3:
this->mode = static_cast<enums::WaterHeaterMode>(value.as_uint32());
break;
#ifdef USE_DEVICES
case 5:
this->device_id = value.as_uint32();
break;
#endif
case 6:
this->state = value.as_uint32();
break;
default:
return false;
}
return true;
}
bool WaterHeaterCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
switch (field_id) {
case 1:
this->key = value.as_fixed32();
break;
case 4:
this->target_temperature = value.as_float();
break;
case 7:
this->target_temperature_low = value.as_float();
break;
case 8:
this->target_temperature_high = value.as_float();
break;
default:
return false;
}
return true;
}
#endif
#ifdef USE_NUMBER
void ListEntitiesNumberResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->object_id_ref_);
@@ -1532,9 +1681,10 @@ bool SelectCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool SelectCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2:
this->state = value.as_string();
case 2: {
this->state = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -1560,8 +1710,8 @@ void ListEntitiesSirenResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(5, this->icon_ref_);
#endif
buffer.encode_bool(6, this->disabled_by_default);
for (auto &it : this->tones) {
buffer.encode_string(7, it, true);
for (const char *it : *this->tones) {
buffer.encode_string(7, it, strlen(it), true);
}
buffer.encode_bool(8, this->supports_duration);
buffer.encode_bool(9, this->supports_volume);
@@ -1578,9 +1728,9 @@ void ListEntitiesSirenResponse::calculate_size(ProtoSize &size) const {
size.add_length(1, this->icon_ref_.size());
#endif
size.add_bool(1, this->disabled_by_default);
if (!this->tones.empty()) {
for (const auto &it : this->tones) {
size.add_length_force(1, it.size());
if (!this->tones->empty()) {
for (const char *it : *this->tones) {
size.add_length_force(1, strlen(it));
}
}
size.add_bool(1, this->supports_duration);
@@ -1636,9 +1786,10 @@ bool SirenCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool SirenCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 5:
this->tone = value.as_string();
case 5: {
this->tone = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -1727,9 +1878,10 @@ bool LockCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool LockCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4:
this->code = value.as_string();
case 4: {
this->code = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -1824,7 +1976,7 @@ void ListEntitiesMediaPlayerResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(7, static_cast<uint32_t>(this->entity_category));
buffer.encode_bool(8, this->supports_pause);
for (auto &it : this->supported_formats) {
buffer.encode_message(9, it, true);
buffer.encode_message(9, it);
}
#ifdef USE_DEVICES
buffer.encode_uint32(10, this->device_id);
@@ -1897,9 +2049,10 @@ bool MediaPlayerCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt val
}
bool MediaPlayerCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 7:
this->media_url = value.as_string();
case 7: {
this->media_url = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -1944,7 +2097,7 @@ void BluetoothLERawAdvertisement::calculate_size(ProtoSize &size) const {
}
void BluetoothLERawAdvertisementsResponse::encode(ProtoWriteBuffer buffer) const {
for (uint16_t i = 0; i < this->advertisements_len; i++) {
buffer.encode_message(1, this->advertisements[i], true);
buffer.encode_message(1, this->advertisements[i]);
}
}
void BluetoothLERawAdvertisementsResponse::calculate_size(ProtoSize &size) const {
@@ -2017,7 +2170,7 @@ void BluetoothGATTCharacteristic::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint32(2, this->handle);
buffer.encode_uint32(3, this->properties);
for (auto &it : this->descriptors) {
buffer.encode_message(4, it, true);
buffer.encode_message(4, it);
}
buffer.encode_uint32(5, this->short_uuid);
}
@@ -2038,7 +2191,7 @@ void BluetoothGATTService::encode(ProtoWriteBuffer buffer) const {
}
buffer.encode_uint32(2, this->handle);
for (auto &it : this->characteristics) {
buffer.encode_message(3, it, true);
buffer.encode_message(3, it);
}
buffer.encode_uint32(4, this->short_uuid);
}
@@ -2054,7 +2207,7 @@ void BluetoothGATTService::calculate_size(ProtoSize &size) const {
void BluetoothGATTGetServicesResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
for (auto &it : this->services) {
buffer.encode_message(2, it, true);
buffer.encode_message(2, it);
}
}
void BluetoothGATTGetServicesResponse::calculate_size(ProtoSize &size) const {
@@ -2107,7 +2260,6 @@ bool BluetoothGATTWriteRequest::decode_varint(uint32_t field_id, ProtoVarInt val
bool BluetoothGATTWriteRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 4: {
// Use raw data directly to avoid allocation
this->data = value.data();
this->data_len = value.size();
break;
@@ -2146,7 +2298,6 @@ bool BluetoothGATTWriteDescriptorRequest::decode_varint(uint32_t field_id, Proto
bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3: {
// Use raw data directly to avoid allocation
this->data = value.data();
this->data_len = value.size();
break;
@@ -2330,12 +2481,14 @@ bool VoiceAssistantResponse::decode_varint(uint32_t field_id, ProtoVarInt value)
}
bool VoiceAssistantEventData::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->name = value.as_string();
case 1: {
this->name = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 2:
this->value = value.as_string();
}
case 2: {
this->value = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -2374,20 +2527,22 @@ bool VoiceAssistantAudio::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->data = value.as_string();
case 1: {
this->data = value.data();
this->data_len = value.size();
break;
}
default:
return false;
}
return true;
}
void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bytes(1, this->data_ptr_, this->data_len_);
buffer.encode_bytes(1, this->data, this->data_len);
buffer.encode_bool(2, this->end);
}
void VoiceAssistantAudio::calculate_size(ProtoSize &size) const {
size.add_length(1, this->data_len_);
size.add_length(1, this->data_len);
size.add_bool(1, this->end);
}
bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
@@ -2411,12 +2566,14 @@ bool VoiceAssistantTimerEventResponse::decode_varint(uint32_t field_id, ProtoVar
}
bool VoiceAssistantTimerEventResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2:
this->timer_id = value.as_string();
case 2: {
this->timer_id = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 3:
this->name = value.as_string();
}
case 3: {
this->name = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -2434,15 +2591,18 @@ bool VoiceAssistantAnnounceRequest::decode_varint(uint32_t field_id, ProtoVarInt
}
bool VoiceAssistantAnnounceRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->media_id = value.as_string();
case 1: {
this->media_id = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 2:
this->text = value.as_string();
}
case 2: {
this->text = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 3:
this->preannounce_media_id = value.as_string();
}
case 3: {
this->preannounce_media_id = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -2478,24 +2638,29 @@ bool VoiceAssistantExternalWakeWord::decode_varint(uint32_t field_id, ProtoVarIn
}
bool VoiceAssistantExternalWakeWord::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1:
this->id = value.as_string();
case 1: {
this->id = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 2:
this->wake_word = value.as_string();
}
case 2: {
this->wake_word = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
case 3:
this->trained_languages.push_back(value.as_string());
break;
case 4:
this->model_type = value.as_string();
case 4: {
this->model_type = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 6:
this->model_hash = value.as_string();
}
case 6: {
this->model_hash = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
case 7:
this->url = value.as_string();
}
case 7: {
this->url = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -2514,7 +2679,7 @@ bool VoiceAssistantConfigurationRequest::decode_length(uint32_t field_id, ProtoL
}
void VoiceAssistantConfigurationResponse::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->available_wake_words) {
buffer.encode_message(1, it, true);
buffer.encode_message(1, it);
}
for (const auto &it : *this->active_wake_words) {
buffer.encode_string(2, it, true);
@@ -2605,9 +2770,10 @@ bool AlarmControlPanelCommandRequest::decode_varint(uint32_t field_id, ProtoVarI
}
bool AlarmControlPanelCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 3:
this->code = value.as_string();
case 3: {
this->code = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -2689,9 +2855,10 @@ bool TextCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
}
bool TextCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2:
this->state = value.as_string();
case 2: {
this->state = StringRef(reinterpret_cast<const char *>(value.data()), value.size());
break;
}
default:
return false;
}
@@ -3159,7 +3326,6 @@ bool UpdateCommandRequest::decode_32bit(uint32_t field_id, Proto32Bit value) {
bool ZWaveProxyFrame::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 1: {
// Use raw data directly to avoid allocation
this->data = value.data();
this->data_len = value.size();
break;
@@ -3184,7 +3350,6 @@ bool ZWaveProxyRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
bool ZWaveProxyRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
switch (field_id) {
case 2: {
// Use raw data directly to avoid allocation
this->data = value.data();
this->data_len = value.size();
break;
@@ -3200,7 +3365,7 @@ void ZWaveProxyRequest::encode(ProtoWriteBuffer buffer) const {
}
void ZWaveProxyRequest::calculate_size(ProtoSize &size) const {
size.add_uint32(1, static_cast<uint32_t>(this->type));
size.add_length(2, this->data_len);
size.add_length(1, this->data_len);
}
#endif

View File

@@ -51,6 +51,7 @@ enum SensorStateClass : uint32_t {
STATE_CLASS_MEASUREMENT = 1,
STATE_CLASS_TOTAL_INCREASING = 2,
STATE_CLASS_TOTAL = 3,
STATE_CLASS_MEASUREMENT_ANGLE = 4,
};
#endif
enum LogLevel : uint32_t {
@@ -63,7 +64,7 @@ enum LogLevel : uint32_t {
LOG_LEVEL_VERBOSE = 6,
LOG_LEVEL_VERY_VERBOSE = 7,
};
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
enum ServiceArgType : uint32_t {
SERVICE_ARG_TYPE_BOOL = 0,
SERVICE_ARG_TYPE_INT = 1,
@@ -74,6 +75,12 @@ enum ServiceArgType : uint32_t {
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6,
SERVICE_ARG_TYPE_STRING_ARRAY = 7,
};
enum SupportsResponseType : uint32_t {
SUPPORTS_RESPONSE_NONE = 0,
SUPPORTS_RESPONSE_OPTIONAL = 1,
SUPPORTS_RESPONSE_ONLY = 2,
SUPPORTS_RESPONSE_STATUS = 100,
};
#endif
#ifdef USE_CLIMATE
enum ClimateMode : uint32_t {
@@ -122,6 +129,25 @@ enum ClimatePreset : uint32_t {
CLIMATE_PRESET_ACTIVITY = 7,
};
#endif
#ifdef USE_WATER_HEATER
enum WaterHeaterMode : uint32_t {
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,
};
#endif
enum WaterHeaterCommandHasField : uint32_t {
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,
};
#ifdef USE_NUMBER
enum NumberMode : uint32_t {
NUMBER_MODE_AUTO = 0,
@@ -331,12 +357,11 @@ class CommandProtoMessage : public ProtoDecodableMessage {
class HelloRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 1;
static constexpr uint8_t ESTIMATED_SIZE = 27;
static constexpr uint8_t ESTIMATED_SIZE = 17;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "hello_request"; }
#endif
const uint8_t *client_info{nullptr};
uint16_t client_info_len{0};
StringRef client_info{};
uint32_t api_version_major{0};
uint32_t api_version_minor{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -372,12 +397,11 @@ class HelloResponse final : public ProtoMessage {
class AuthenticationRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 3;
static constexpr uint8_t ESTIMATED_SIZE = 19;
static constexpr uint8_t ESTIMATED_SIZE = 9;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "authentication_request"; }
#endif
const uint8_t *password{nullptr};
uint16_t password_len{0};
StringRef password{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -771,7 +795,7 @@ class FanCommandRequest final : public CommandProtoMessage {
bool has_speed_level{false};
int32_t speed_level{0};
bool has_preset_mode{false};
std::string preset_mode{};
StringRef preset_mode{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -793,7 +817,7 @@ class ListEntitiesLightResponse final : public InfoResponseProtoMessage {
const light::ColorModeMask *supported_color_modes{};
float min_mireds{0.0f};
float max_mireds{0.0f};
std::vector<std::string> effects{};
const FixedVector<const char *> *effects{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -862,7 +886,7 @@ class LightCommandRequest final : public CommandProtoMessage {
bool has_flash_length{false};
uint32_t flash_length{0};
bool has_effect{false};
std::string effect{};
StringRef effect{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1049,7 +1073,8 @@ class NoiseEncryptionSetKeyRequest final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "noise_encryption_set_key_request"; }
#endif
std::string key{};
const uint8_t *key{nullptr};
uint16_t key_len{0};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1136,13 +1161,13 @@ class HomeassistantActionRequest final : public ProtoMessage {
class HomeassistantActionResponse final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 130;
static constexpr uint8_t ESTIMATED_SIZE = 34;
static constexpr uint8_t ESTIMATED_SIZE = 24;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "homeassistant_action_response"; }
#endif
uint32_t call_id{0};
bool success{false};
std::string error_message{};
StringRef error_message{};
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
const uint8_t *response_data{nullptr};
uint16_t response_data_len{0};
@@ -1197,9 +1222,9 @@ class HomeAssistantStateResponse final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "home_assistant_state_response"; }
#endif
std::string entity_id{};
std::string state{};
std::string attribute{};
StringRef entity_id{};
StringRef state{};
StringRef attribute{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1224,13 +1249,12 @@ class GetTimeRequest final : public ProtoMessage {
class GetTimeResponse final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 37;
static constexpr uint8_t ESTIMATED_SIZE = 24;
static constexpr uint8_t ESTIMATED_SIZE = 14;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "get_time_response"; }
#endif
uint32_t epoch_seconds{0};
const uint8_t *timezone{nullptr};
uint16_t timezone_len{0};
StringRef timezone{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1239,7 +1263,7 @@ class GetTimeResponse final : public ProtoDecodableMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
};
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
class ListEntitiesServicesArgument final : public ProtoMessage {
public:
StringRef name_ref_{};
@@ -1256,7 +1280,7 @@ class ListEntitiesServicesArgument final : public ProtoMessage {
class ListEntitiesServicesResponse final : public ProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 41;
static constexpr uint8_t ESTIMATED_SIZE = 48;
static constexpr uint8_t ESTIMATED_SIZE = 50;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "list_entities_services_response"; }
#endif
@@ -1264,6 +1288,7 @@ class ListEntitiesServicesResponse final : public ProtoMessage {
void set_name(const StringRef &ref) { this->name_ref_ = ref; }
uint32_t key{0};
FixedVector<ListEntitiesServicesArgument> args{};
enums::SupportsResponseType supports_response{};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1277,7 +1302,7 @@ class ExecuteServiceArgument final : public ProtoDecodableMessage {
bool bool_{false};
int32_t legacy_int{0};
float float_{0.0f};
std::string string_{};
StringRef string_{};
int32_t int_{0};
FixedVector<bool> bool_array{};
FixedVector<int32_t> int_array{};
@@ -1296,12 +1321,18 @@ class ExecuteServiceArgument final : public ProtoDecodableMessage {
class ExecuteServiceRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 42;
static constexpr uint8_t ESTIMATED_SIZE = 39;
static constexpr uint8_t ESTIMATED_SIZE = 45;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "execute_service_request"; }
#endif
uint32_t key{0};
FixedVector<ExecuteServiceArgument> args{};
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
uint32_t call_id{0};
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
bool return_response{false};
#endif
void decode(const uint8_t *buffer, size_t length) override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -1310,6 +1341,32 @@ class ExecuteServiceRequest final : public ProtoDecodableMessage {
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
class ExecuteServiceResponse final : public ProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 131;
static constexpr uint8_t ESTIMATED_SIZE = 34;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "execute_service_response"; }
#endif
uint32_t call_id{0};
bool success{false};
StringRef error_message_ref_{};
void set_error_message(const StringRef &ref) { this->error_message_ref_ = ref; }
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
const uint8_t *response_data{nullptr};
uint16_t response_data_len{0};
#endif
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
#endif
#ifdef USE_CAMERA
@@ -1451,11 +1508,11 @@ class ClimateCommandRequest final : public CommandProtoMessage {
bool has_swing_mode{false};
enums::ClimateSwingMode swing_mode{};
bool has_custom_fan_mode{false};
std::string custom_fan_mode{};
StringRef custom_fan_mode{};
bool has_preset{false};
enums::ClimatePreset preset{};
bool has_custom_preset{false};
std::string custom_preset{};
StringRef custom_preset{};
bool has_target_humidity{false};
float target_humidity{0.0f};
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -1468,6 +1525,70 @@ class ClimateCommandRequest final : public CommandProtoMessage {
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
#endif
#ifdef USE_WATER_HEATER
class ListEntitiesWaterHeaterResponse final : public InfoResponseProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 132;
static constexpr uint8_t ESTIMATED_SIZE = 63;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "list_entities_water_heater_response"; }
#endif
float min_temperature{0.0f};
float max_temperature{0.0f};
float target_temperature_step{0.0f};
const water_heater::WaterHeaterModeMask *supported_modes{};
uint32_t supported_features{0};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class WaterHeaterStateResponse final : public StateResponseProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 133;
static constexpr uint8_t ESTIMATED_SIZE = 35;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "water_heater_state_response"; }
#endif
float current_temperature{0.0f};
float target_temperature{0.0f};
enums::WaterHeaterMode mode{};
uint32_t state{0};
float target_temperature_low{0.0f};
float target_temperature_high{0.0f};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
};
class WaterHeaterCommandRequest final : public CommandProtoMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 134;
static constexpr uint8_t ESTIMATED_SIZE = 34;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "water_heater_command_request"; }
#endif
uint32_t has_fields{0};
enums::WaterHeaterMode mode{};
float target_temperature{0.0f};
uint32_t state{0};
float target_temperature_low{0.0f};
float target_temperature_high{0.0f};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
};
#endif
#ifdef USE_NUMBER
class ListEntitiesNumberResponse final : public InfoResponseProtoMessage {
public:
@@ -1568,7 +1689,7 @@ class SelectCommandRequest final : public CommandProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "select_command_request"; }
#endif
std::string state{};
StringRef state{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1587,7 +1708,7 @@ class ListEntitiesSirenResponse final : public InfoResponseProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "list_entities_siren_response"; }
#endif
std::vector<std::string> tones{};
const FixedVector<const char *> *tones{};
bool supports_duration{false};
bool supports_volume{false};
void encode(ProtoWriteBuffer buffer) const override;
@@ -1624,7 +1745,7 @@ class SirenCommandRequest final : public CommandProtoMessage {
bool has_state{false};
bool state{false};
bool has_tone{false};
std::string tone{};
StringRef tone{};
bool has_duration{false};
uint32_t duration{0};
bool has_volume{false};
@@ -1685,7 +1806,7 @@ class LockCommandRequest final : public CommandProtoMessage {
#endif
enums::LockCommand command{};
bool has_code{false};
std::string code{};
StringRef code{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -1795,7 +1916,7 @@ class MediaPlayerCommandRequest final : public CommandProtoMessage {
bool has_volume{false};
float volume{0.0f};
bool has_media_url{false};
std::string media_url{};
StringRef media_url{};
bool has_announcement{false};
bool announcement{false};
#ifdef HAS_PROTO_MESSAGE_DUMP
@@ -2025,7 +2146,7 @@ class BluetoothGATTReadResponse final : public ProtoMessage {
class BluetoothGATTWriteRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 75;
static constexpr uint8_t ESTIMATED_SIZE = 29;
static constexpr uint8_t ESTIMATED_SIZE = 19;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "bluetooth_gatt_write_request"; }
#endif
@@ -2061,7 +2182,7 @@ class BluetoothGATTReadDescriptorRequest final : public ProtoDecodableMessage {
class BluetoothGATTWriteDescriptorRequest final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 77;
static constexpr uint8_t ESTIMATED_SIZE = 27;
static constexpr uint8_t ESTIMATED_SIZE = 17;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "bluetooth_gatt_write_descriptor_request"; }
#endif
@@ -2371,8 +2492,8 @@ class VoiceAssistantResponse final : public ProtoDecodableMessage {
};
class VoiceAssistantEventData final : public ProtoDecodableMessage {
public:
std::string name{};
std::string value{};
StringRef name{};
StringRef value{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -2400,17 +2521,12 @@ class VoiceAssistantEventResponse final : public ProtoDecodableMessage {
class VoiceAssistantAudio final : public ProtoDecodableMessage {
public:
static constexpr uint8_t MESSAGE_TYPE = 106;
static constexpr uint8_t ESTIMATED_SIZE = 11;
static constexpr uint8_t ESTIMATED_SIZE = 21;
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "voice_assistant_audio"; }
#endif
std::string data{};
const uint8_t *data_ptr_{nullptr};
size_t data_len_{0};
void set_data(const uint8_t *data, size_t len) {
this->data_ptr_ = data;
this->data_len_ = len;
}
const uint8_t *data{nullptr};
uint16_t data_len{0};
bool end{false};
void encode(ProtoWriteBuffer buffer) const override;
void calculate_size(ProtoSize &size) const override;
@@ -2430,8 +2546,8 @@ class VoiceAssistantTimerEventResponse final : public ProtoDecodableMessage {
const char *message_name() const override { return "voice_assistant_timer_event_response"; }
#endif
enums::VoiceAssistantTimerEvent event_type{};
std::string timer_id{};
std::string name{};
StringRef timer_id{};
StringRef name{};
uint32_t total_seconds{0};
uint32_t seconds_left{0};
bool is_active{false};
@@ -2450,9 +2566,9 @@ class VoiceAssistantAnnounceRequest final : public ProtoDecodableMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "voice_assistant_announce_request"; }
#endif
std::string media_id{};
std::string text{};
std::string preannounce_media_id{};
StringRef media_id{};
StringRef text{};
StringRef preannounce_media_id{};
bool start_conversation{false};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
@@ -2495,13 +2611,13 @@ class VoiceAssistantWakeWord final : public ProtoMessage {
};
class VoiceAssistantExternalWakeWord final : public ProtoDecodableMessage {
public:
std::string id{};
std::string wake_word{};
StringRef id{};
StringRef wake_word{};
std::vector<std::string> trained_languages{};
std::string model_type{};
StringRef model_type{};
uint32_t model_size{0};
std::string model_hash{};
std::string url{};
StringRef model_hash{};
StringRef url{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -2602,7 +2718,7 @@ class AlarmControlPanelCommandRequest final : public CommandProtoMessage {
const char *message_name() const override { return "alarm_control_panel_command_request"; }
#endif
enums::AlarmControlPanelStateCommand command{};
std::string code{};
StringRef code{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif
@@ -2659,7 +2775,7 @@ class TextCommandRequest final : public CommandProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "text_command_request"; }
#endif
std::string state{};
StringRef state{};
#ifdef HAS_PROTO_MESSAGE_DUMP
void dump_to(std::string &out) const override;
#endif

View File

@@ -66,7 +66,7 @@ static void dump_field(std::string &out, const char *field_name, float value, in
static void dump_field(std::string &out, const char *field_name, uint64_t value, int indent = 2) {
char buffer[64];
append_field_prefix(out, field_name, indent);
snprintf(buffer, 64, "%llu", value);
snprintf(buffer, 64, "%" PRIu64, value);
append_with_newline(out, buffer);
}
@@ -179,6 +179,8 @@ template<> const char *proto_enum_to_string<enums::SensorStateClass>(enums::Sens
return "STATE_CLASS_TOTAL_INCREASING";
case enums::STATE_CLASS_TOTAL:
return "STATE_CLASS_TOTAL";
case enums::STATE_CLASS_MEASUREMENT_ANGLE:
return "STATE_CLASS_MEASUREMENT_ANGLE";
default:
return "UNKNOWN";
}
@@ -206,7 +208,7 @@ template<> const char *proto_enum_to_string<enums::LogLevel>(enums::LogLevel val
return "UNKNOWN";
}
}
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::ServiceArgType value) {
switch (value) {
case enums::SERVICE_ARG_TYPE_BOOL:
@@ -229,6 +231,20 @@ template<> const char *proto_enum_to_string<enums::ServiceArgType>(enums::Servic
return "UNKNOWN";
}
}
template<> const char *proto_enum_to_string<enums::SupportsResponseType>(enums::SupportsResponseType value) {
switch (value) {
case enums::SUPPORTS_RESPONSE_NONE:
return "SUPPORTS_RESPONSE_NONE";
case enums::SUPPORTS_RESPONSE_OPTIONAL:
return "SUPPORTS_RESPONSE_OPTIONAL";
case enums::SUPPORTS_RESPONSE_ONLY:
return "SUPPORTS_RESPONSE_ONLY";
case enums::SUPPORTS_RESPONSE_STATUS:
return "SUPPORTS_RESPONSE_STATUS";
default:
return "UNKNOWN";
}
}
#endif
#ifdef USE_CLIMATE
template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMode value) {
@@ -332,6 +348,47 @@ template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::Climate
}
}
#endif
#ifdef USE_WATER_HEATER
template<> const char *proto_enum_to_string<enums::WaterHeaterMode>(enums::WaterHeaterMode value) {
switch (value) {
case enums::WATER_HEATER_MODE_OFF:
return "WATER_HEATER_MODE_OFF";
case enums::WATER_HEATER_MODE_ECO:
return "WATER_HEATER_MODE_ECO";
case enums::WATER_HEATER_MODE_ELECTRIC:
return "WATER_HEATER_MODE_ELECTRIC";
case enums::WATER_HEATER_MODE_PERFORMANCE:
return "WATER_HEATER_MODE_PERFORMANCE";
case enums::WATER_HEATER_MODE_HIGH_DEMAND:
return "WATER_HEATER_MODE_HIGH_DEMAND";
case enums::WATER_HEATER_MODE_HEAT_PUMP:
return "WATER_HEATER_MODE_HEAT_PUMP";
case enums::WATER_HEATER_MODE_GAS:
return "WATER_HEATER_MODE_GAS";
default:
return "UNKNOWN";
}
}
#endif
template<>
const char *proto_enum_to_string<enums::WaterHeaterCommandHasField>(enums::WaterHeaterCommandHasField value) {
switch (value) {
case enums::WATER_HEATER_COMMAND_HAS_NONE:
return "WATER_HEATER_COMMAND_HAS_NONE";
case enums::WATER_HEATER_COMMAND_HAS_MODE:
return "WATER_HEATER_COMMAND_HAS_MODE";
case enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE:
return "WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE";
case enums::WATER_HEATER_COMMAND_HAS_STATE:
return "WATER_HEATER_COMMAND_HAS_STATE";
case enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW:
return "WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_LOW";
case enums::WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH:
return "WATER_HEATER_COMMAND_HAS_TARGET_TEMPERATURE_HIGH";
default:
return "UNKNOWN";
}
}
#ifdef USE_NUMBER
template<> const char *proto_enum_to_string<enums::NumberMode>(enums::NumberMode value) {
switch (value) {
@@ -679,7 +736,7 @@ template<> const char *proto_enum_to_string<enums::ZWaveProxyRequestType>(enums:
void HelloRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "HelloRequest");
out.append(" client_info: ");
out.append(format_hex_pretty(this->client_info, this->client_info_len));
out.append("'").append(this->client_info.c_str(), this->client_info.size()).append("'");
out.append("\n");
dump_field(out, "api_version_major", this->api_version_major);
dump_field(out, "api_version_minor", this->api_version_minor);
@@ -695,7 +752,7 @@ void HelloResponse::dump_to(std::string &out) const {
void AuthenticationRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "AuthenticationRequest");
out.append(" password: ");
out.append(format_hex_pretty(this->password, this->password_len));
out.append("'").append(this->password.c_str(), this->password.size()).append("'");
out.append("\n");
}
void AuthenticationResponse::dump_to(std::string &out) const {
@@ -907,7 +964,9 @@ void FanCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_speed_level", this->has_speed_level);
dump_field(out, "speed_level", this->speed_level);
dump_field(out, "has_preset_mode", this->has_preset_mode);
dump_field(out, "preset_mode", this->preset_mode);
out.append(" preset_mode: ");
out.append("'").append(this->preset_mode.c_str(), this->preset_mode.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
@@ -924,7 +983,7 @@ void ListEntitiesLightResponse::dump_to(std::string &out) const {
}
dump_field(out, "min_mireds", this->min_mireds);
dump_field(out, "max_mireds", this->max_mireds);
for (const auto &it : this->effects) {
for (const auto &it : *this->effects) {
dump_field(out, "effects", it, 4);
}
dump_field(out, "disabled_by_default", this->disabled_by_default);
@@ -983,7 +1042,9 @@ void LightCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_flash_length", this->has_flash_length);
dump_field(out, "flash_length", this->flash_length);
dump_field(out, "has_effect", this->has_effect);
dump_field(out, "effect", this->effect);
out.append(" effect: ");
out.append("'").append(this->effect.c_str(), this->effect.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
@@ -1095,7 +1156,7 @@ void SubscribeLogsResponse::dump_to(std::string &out) const {
void NoiseEncryptionSetKeyRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "NoiseEncryptionSetKeyRequest");
out.append(" key: ");
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->key.data()), this->key.size()));
out.append(format_hex_pretty(this->key, this->key_len));
out.append("\n");
}
void NoiseEncryptionSetKeyResponse::dump_to(std::string &out) const { dump_field(out, "success", this->success); }
@@ -1144,7 +1205,9 @@ void HomeassistantActionResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "HomeassistantActionResponse");
dump_field(out, "call_id", this->call_id);
dump_field(out, "success", this->success);
dump_field(out, "error_message", this->error_message);
out.append(" error_message: ");
out.append("'").append(this->error_message.c_str(), this->error_message.size()).append("'");
out.append("\n");
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
out.append(" response_data: ");
out.append(format_hex_pretty(this->response_data, this->response_data_len));
@@ -1164,9 +1227,15 @@ void SubscribeHomeAssistantStateResponse::dump_to(std::string &out) const {
}
void HomeAssistantStateResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "HomeAssistantStateResponse");
dump_field(out, "entity_id", this->entity_id);
dump_field(out, "state", this->state);
dump_field(out, "attribute", this->attribute);
out.append(" entity_id: ");
out.append("'").append(this->entity_id.c_str(), this->entity_id.size()).append("'");
out.append("\n");
out.append(" state: ");
out.append("'").append(this->state.c_str(), this->state.size()).append("'");
out.append("\n");
out.append(" attribute: ");
out.append("'").append(this->attribute.c_str(), this->attribute.size()).append("'");
out.append("\n");
}
#endif
void GetTimeRequest::dump_to(std::string &out) const { out.append("GetTimeRequest {}"); }
@@ -1174,10 +1243,10 @@ void GetTimeResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "GetTimeResponse");
dump_field(out, "epoch_seconds", this->epoch_seconds);
out.append(" timezone: ");
out.append(format_hex_pretty(this->timezone, this->timezone_len));
out.append("'").append(this->timezone.c_str(), this->timezone.size()).append("'");
out.append("\n");
}
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void ListEntitiesServicesArgument::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ListEntitiesServicesArgument");
dump_field(out, "name", this->name_ref_);
@@ -1192,13 +1261,16 @@ void ListEntitiesServicesResponse::dump_to(std::string &out) const {
it.dump_to(out);
out.append("\n");
}
dump_field(out, "supports_response", static_cast<enums::SupportsResponseType>(this->supports_response));
}
void ExecuteServiceArgument::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ExecuteServiceArgument");
dump_field(out, "bool_", this->bool_);
dump_field(out, "legacy_int", this->legacy_int);
dump_field(out, "float_", this->float_);
dump_field(out, "string_", this->string_);
out.append(" string_: ");
out.append("'").append(this->string_.c_str(), this->string_.size()).append("'");
out.append("\n");
dump_field(out, "int_", this->int_);
for (const auto it : this->bool_array) {
dump_field(out, "bool_array", static_cast<bool>(it), 4);
@@ -1221,6 +1293,25 @@ void ExecuteServiceRequest::dump_to(std::string &out) const {
it.dump_to(out);
out.append("\n");
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
dump_field(out, "call_id", this->call_id);
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
dump_field(out, "return_response", this->return_response);
#endif
}
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
void ExecuteServiceResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ExecuteServiceResponse");
dump_field(out, "call_id", this->call_id);
dump_field(out, "success", this->success);
dump_field(out, "error_message", this->error_message_ref_);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
out.append(" response_data: ");
out.append(format_hex_pretty(this->response_data, this->response_data_len));
out.append("\n");
#endif
}
#endif
#ifdef USE_CAMERA
@@ -1336,11 +1427,15 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_swing_mode", this->has_swing_mode);
dump_field(out, "swing_mode", static_cast<enums::ClimateSwingMode>(this->swing_mode));
dump_field(out, "has_custom_fan_mode", this->has_custom_fan_mode);
dump_field(out, "custom_fan_mode", this->custom_fan_mode);
out.append(" custom_fan_mode: ");
out.append("'").append(this->custom_fan_mode.c_str(), this->custom_fan_mode.size()).append("'");
out.append("\n");
dump_field(out, "has_preset", this->has_preset);
dump_field(out, "preset", static_cast<enums::ClimatePreset>(this->preset));
dump_field(out, "has_custom_preset", this->has_custom_preset);
dump_field(out, "custom_preset", this->custom_preset);
out.append(" custom_preset: ");
out.append("'").append(this->custom_preset.c_str(), this->custom_preset.size()).append("'");
out.append("\n");
dump_field(out, "has_target_humidity", this->has_target_humidity);
dump_field(out, "target_humidity", this->target_humidity);
#ifdef USE_DEVICES
@@ -1348,6 +1443,55 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
#endif
}
#endif
#ifdef USE_WATER_HEATER
void ListEntitiesWaterHeaterResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ListEntitiesWaterHeaterResponse");
dump_field(out, "object_id", this->object_id_ref_);
dump_field(out, "key", this->key);
dump_field(out, "name", this->name_ref_);
#ifdef USE_ENTITY_ICON
dump_field(out, "icon", this->icon_ref_);
#endif
dump_field(out, "disabled_by_default", this->disabled_by_default);
dump_field(out, "entity_category", static_cast<enums::EntityCategory>(this->entity_category));
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
dump_field(out, "min_temperature", this->min_temperature);
dump_field(out, "max_temperature", this->max_temperature);
dump_field(out, "target_temperature_step", this->target_temperature_step);
for (const auto &it : *this->supported_modes) {
dump_field(out, "supported_modes", static_cast<enums::WaterHeaterMode>(it), 4);
}
dump_field(out, "supported_features", this->supported_features);
}
void WaterHeaterStateResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "WaterHeaterStateResponse");
dump_field(out, "key", this->key);
dump_field(out, "current_temperature", this->current_temperature);
dump_field(out, "target_temperature", this->target_temperature);
dump_field(out, "mode", static_cast<enums::WaterHeaterMode>(this->mode));
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
dump_field(out, "state", this->state);
dump_field(out, "target_temperature_low", this->target_temperature_low);
dump_field(out, "target_temperature_high", this->target_temperature_high);
}
void WaterHeaterCommandRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "WaterHeaterCommandRequest");
dump_field(out, "key", this->key);
dump_field(out, "has_fields", this->has_fields);
dump_field(out, "mode", static_cast<enums::WaterHeaterMode>(this->mode));
dump_field(out, "target_temperature", this->target_temperature);
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
dump_field(out, "state", this->state);
dump_field(out, "target_temperature_low", this->target_temperature_low);
dump_field(out, "target_temperature_high", this->target_temperature_high);
}
#endif
#ifdef USE_NUMBER
void ListEntitiesNumberResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "ListEntitiesNumberResponse");
@@ -1417,7 +1561,9 @@ void SelectStateResponse::dump_to(std::string &out) const {
void SelectCommandRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "SelectCommandRequest");
dump_field(out, "key", this->key);
dump_field(out, "state", this->state);
out.append(" state: ");
out.append("'").append(this->state.c_str(), this->state.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
@@ -1433,7 +1579,7 @@ void ListEntitiesSirenResponse::dump_to(std::string &out) const {
dump_field(out, "icon", this->icon_ref_);
#endif
dump_field(out, "disabled_by_default", this->disabled_by_default);
for (const auto &it : this->tones) {
for (const auto &it : *this->tones) {
dump_field(out, "tones", it, 4);
}
dump_field(out, "supports_duration", this->supports_duration);
@@ -1457,7 +1603,9 @@ void SirenCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_state", this->has_state);
dump_field(out, "state", this->state);
dump_field(out, "has_tone", this->has_tone);
dump_field(out, "tone", this->tone);
out.append(" tone: ");
out.append("'").append(this->tone.c_str(), this->tone.size()).append("'");
out.append("\n");
dump_field(out, "has_duration", this->has_duration);
dump_field(out, "duration", this->duration);
dump_field(out, "has_volume", this->has_volume);
@@ -1499,7 +1647,9 @@ void LockCommandRequest::dump_to(std::string &out) const {
dump_field(out, "key", this->key);
dump_field(out, "command", static_cast<enums::LockCommand>(this->command));
dump_field(out, "has_code", this->has_code);
dump_field(out, "code", this->code);
out.append(" code: ");
out.append("'").append(this->code.c_str(), this->code.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
@@ -1577,7 +1727,9 @@ void MediaPlayerCommandRequest::dump_to(std::string &out) const {
dump_field(out, "has_volume", this->has_volume);
dump_field(out, "volume", this->volume);
dump_field(out, "has_media_url", this->has_media_url);
dump_field(out, "media_url", this->media_url);
out.append(" media_url: ");
out.append("'").append(this->media_url.c_str(), this->media_url.size()).append("'");
out.append("\n");
dump_field(out, "has_announcement", this->has_announcement);
dump_field(out, "announcement", this->announcement);
#ifdef USE_DEVICES
@@ -1807,8 +1959,12 @@ void VoiceAssistantResponse::dump_to(std::string &out) const {
}
void VoiceAssistantEventData::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantEventData");
dump_field(out, "name", this->name);
dump_field(out, "value", this->value);
out.append(" name: ");
out.append("'").append(this->name.c_str(), this->name.size()).append("'");
out.append("\n");
out.append(" value: ");
out.append("'").append(this->value.c_str(), this->value.size()).append("'");
out.append("\n");
}
void VoiceAssistantEventResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantEventResponse");
@@ -1822,28 +1978,34 @@ void VoiceAssistantEventResponse::dump_to(std::string &out) const {
void VoiceAssistantAudio::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantAudio");
out.append(" data: ");
if (this->data_ptr_ != nullptr) {
out.append(format_hex_pretty(this->data_ptr_, this->data_len_));
} else {
out.append(format_hex_pretty(reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size()));
}
out.append(format_hex_pretty(this->data, this->data_len));
out.append("\n");
dump_field(out, "end", this->end);
}
void VoiceAssistantTimerEventResponse::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantTimerEventResponse");
dump_field(out, "event_type", static_cast<enums::VoiceAssistantTimerEvent>(this->event_type));
dump_field(out, "timer_id", this->timer_id);
dump_field(out, "name", this->name);
out.append(" timer_id: ");
out.append("'").append(this->timer_id.c_str(), this->timer_id.size()).append("'");
out.append("\n");
out.append(" name: ");
out.append("'").append(this->name.c_str(), this->name.size()).append("'");
out.append("\n");
dump_field(out, "total_seconds", this->total_seconds);
dump_field(out, "seconds_left", this->seconds_left);
dump_field(out, "is_active", this->is_active);
}
void VoiceAssistantAnnounceRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantAnnounceRequest");
dump_field(out, "media_id", this->media_id);
dump_field(out, "text", this->text);
dump_field(out, "preannounce_media_id", this->preannounce_media_id);
out.append(" media_id: ");
out.append("'").append(this->media_id.c_str(), this->media_id.size()).append("'");
out.append("\n");
out.append(" text: ");
out.append("'").append(this->text.c_str(), this->text.size()).append("'");
out.append("\n");
out.append(" preannounce_media_id: ");
out.append("'").append(this->preannounce_media_id.c_str(), this->preannounce_media_id.size()).append("'");
out.append("\n");
dump_field(out, "start_conversation", this->start_conversation);
}
void VoiceAssistantAnnounceFinished::dump_to(std::string &out) const { dump_field(out, "success", this->success); }
@@ -1857,15 +2019,25 @@ void VoiceAssistantWakeWord::dump_to(std::string &out) const {
}
void VoiceAssistantExternalWakeWord::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantExternalWakeWord");
dump_field(out, "id", this->id);
dump_field(out, "wake_word", this->wake_word);
out.append(" id: ");
out.append("'").append(this->id.c_str(), this->id.size()).append("'");
out.append("\n");
out.append(" wake_word: ");
out.append("'").append(this->wake_word.c_str(), this->wake_word.size()).append("'");
out.append("\n");
for (const auto &it : this->trained_languages) {
dump_field(out, "trained_languages", it, 4);
}
dump_field(out, "model_type", this->model_type);
out.append(" model_type: ");
out.append("'").append(this->model_type.c_str(), this->model_type.size()).append("'");
out.append("\n");
dump_field(out, "model_size", this->model_size);
dump_field(out, "model_hash", this->model_hash);
dump_field(out, "url", this->url);
out.append(" model_hash: ");
out.append("'").append(this->model_hash.c_str(), this->model_hash.size()).append("'");
out.append("\n");
out.append(" url: ");
out.append("'").append(this->url.c_str(), this->url.size()).append("'");
out.append("\n");
}
void VoiceAssistantConfigurationRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "VoiceAssistantConfigurationRequest");
@@ -1924,7 +2096,9 @@ void AlarmControlPanelCommandRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "AlarmControlPanelCommandRequest");
dump_field(out, "key", this->key);
dump_field(out, "command", static_cast<enums::AlarmControlPanelStateCommand>(this->command));
dump_field(out, "code", this->code);
out.append(" code: ");
out.append("'").append(this->code.c_str(), this->code.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif
@@ -1961,7 +2135,9 @@ void TextStateResponse::dump_to(std::string &out) const {
void TextCommandRequest::dump_to(std::string &out) const {
MessageDumpHelper helper(out, "TextCommandRequest");
dump_field(out, "key", this->key);
dump_field(out, "state", this->state);
out.append(" state: ");
out.append("'").append(this->state.c_str(), this->state.size()).append("'");
out.append("\n");
#ifdef USE_DEVICES
dump_field(out, "device_id", this->device_id);
#endif

View File

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

View File

@@ -13,7 +13,7 @@ void APIServerConnectionBase::log_send_message_(const char *name, const std::str
}
#endif
void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) {
void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) {
switch (msg_type) {
case HelloRequest::MESSAGE_TYPE: {
HelloRequest msg;
@@ -193,7 +193,7 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
break;
}
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
case ExecuteServiceRequest::MESSAGE_TYPE: {
ExecuteServiceRequest msg;
msg.decode(msg_data, msg_size);
@@ -621,6 +621,17 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_homeassistant_action_response(msg);
break;
}
#endif
#ifdef USE_WATER_HEATER
case WaterHeaterCommandRequest::MESSAGE_TYPE: {
WaterHeaterCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_water_heater_command_request: %s", msg.dump().c_str());
#endif
this->on_water_heater_command_request(msg);
break;
}
#endif
default:
break;
@@ -670,7 +681,7 @@ void APIServerConnection::on_subscribe_home_assistant_states_request(const Subsc
this->subscribe_home_assistant_states(msg);
}
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void APIServerConnection::on_execute_service_request(const ExecuteServiceRequest &msg) { this->execute_service(msg); }
#endif
#ifdef USE_API_NOISE
@@ -827,7 +838,7 @@ void APIServerConnection::on_z_wave_proxy_frame(const ZWaveProxyFrame &msg) { th
void APIServerConnection::on_z_wave_proxy_request(const ZWaveProxyRequest &msg) { this->zwave_proxy_request(msg); }
#endif
void APIServerConnection::read_message(uint32_t msg_size, uint32_t msg_type, 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
switch (msg_type) {
case HelloRequest::MESSAGE_TYPE: // No setup required

View File

@@ -79,7 +79,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_get_time_response(const GetTimeResponse &value){};
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
#endif
@@ -91,6 +91,10 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_climate_command_request(const ClimateCommandRequest &value){};
#endif
#ifdef USE_WATER_HEATER
virtual void on_water_heater_command_request(const WaterHeaterCommandRequest &value){};
#endif
#ifdef USE_NUMBER
virtual void on_number_command_request(const NumberCommandRequest &value){};
#endif
@@ -218,7 +222,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_z_wave_proxy_request(const ZWaveProxyRequest &value){};
#endif
protected:
void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
};
class APIServerConnection : public APIServerConnectionBase {
@@ -239,7 +243,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_API_HOMEASSISTANT_STATES
virtual void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) = 0;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
virtual void execute_service(const ExecuteServiceRequest &msg) = 0;
#endif
#ifdef USE_API_NOISE
@@ -368,7 +372,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_API_HOMEASSISTANT_STATES
void on_subscribe_home_assistant_states_request(const SubscribeHomeAssistantStatesRequest &msg) override;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void on_execute_service_request(const ExecuteServiceRequest &msg) override;
#endif
#ifdef USE_API_NOISE
@@ -480,7 +484,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_ZWAVE_PROXY
void on_z_wave_proxy_request(const ZWaveProxyRequest &msg) override;
#endif
void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) override;
void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) override;
};
} // namespace esphome::api

View File

@@ -4,8 +4,8 @@
#include "api_connection.h"
#include "esphome/components/network/util.h"
#include "esphome/core/application.h"
#include "esphome/core/defines.h"
#include "esphome/core/controller_registry.h"
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "esphome/core/util.h"
@@ -52,11 +52,6 @@ void APIServer::setup() {
#endif
#endif
// Schedule reboot if no clients connect within timeout
if (this->reboot_timeout_ != 0) {
this->schedule_reboot_timeout_();
}
this->socket_ = socket::socket_ip_loop_monitored(SOCK_STREAM, 0); // monitored for incoming connections
if (this->socket_ == nullptr) {
ESP_LOGW(TAG, "Could not create socket");
@@ -101,42 +96,22 @@ void APIServer::setup() {
#ifdef USE_LOGGER
if (logger::global_logger != nullptr) {
logger::global_logger->add_on_log_callback(
[this](int level, const char *tag, const char *message, size_t message_len) {
if (this->shutting_down_) {
// Don't try to send logs during shutdown
// as it could result in a recursion and
// we would be filling a buffer we are trying to clear
return;
}
for (auto &c : this->clients_) {
if (!c->flags_.remove && c->get_log_subscription_level() >= level)
c->try_send_log_message(level, tag, message, message_len);
}
});
logger::global_logger->add_log_listener(this);
}
#endif
#ifdef USE_CAMERA
if (camera::Camera::instance() != nullptr && !camera::Camera::instance()->is_internal()) {
camera::Camera::instance()->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
for (auto &c : this->clients_) {
if (!c->flags_.remove)
c->set_camera_state(image);
}
});
camera::Camera::instance()->add_listener(this);
}
#endif
}
void APIServer::schedule_reboot_timeout_() {
this->status_set_warning();
this->set_timeout("api_reboot", this->reboot_timeout_, []() {
if (!global_api_server->is_connected()) {
ESP_LOGE(TAG, "No clients; rebooting");
App.reboot();
}
});
// Initialize last_connected_ for reboot timeout tracking
this->last_connected_ = App.get_loop_component_start_time();
// Set warning status if reboot timeout is enabled
if (this->reboot_timeout_ != 0) {
this->status_set_warning();
}
}
void APIServer::loop() {
@@ -150,29 +125,41 @@ void APIServer::loop() {
if (!sock)
break;
char peername[socket::PEERNAME_MAX_LEN];
sock->getpeername_to(peername);
// Check if we're at the connection limit
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
sock.reset();
continue;
}
ESP_LOGD(TAG, "Accept %s", sock->getpeername().c_str());
ESP_LOGD(TAG, "Accept %s", peername);
auto *conn = new APIConnection(std::move(sock), this);
this->clients_.emplace_back(conn);
conn->start();
// Clear warning status and cancel reboot when first client connects
// First client connected - clear warning and update timestamp
if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
this->status_clear_warning();
this->cancel_timeout("api_reboot");
this->last_connected_ = App.get_loop_component_start_time();
}
}
}
if (this->clients_.empty()) {
// Check reboot timeout - done in loop to avoid scheduler heap churn
// (cancelled scheduler items sit in heap memory until their scheduled time)
if (this->reboot_timeout_ != 0) {
const uint32_t now = App.get_loop_component_start_time();
if (now - this->last_connected_ > this->reboot_timeout_) {
ESP_LOGE(TAG, "No clients; rebooting");
App.reboot();
}
}
return;
}
@@ -182,8 +169,7 @@ void APIServer::loop() {
// Network is down - disconnect all clients
for (auto &client : this->clients_) {
client->on_fatal_error();
ESP_LOGW(TAG, "%s (%s): Network down; disconnect", client->client_info_.name.c_str(),
client->client_info_.peername.c_str());
client->log_client_(ESPHOME_LOG_LEVEL_WARN, LOG_STR("Network down; disconnect"));
}
// Continue to process and clean up the clients below
}
@@ -201,9 +187,14 @@ void APIServer::loop() {
// Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_.name, client->client_info_.peername);
char peername_buf[socket::PEERNAME_MAX_LEN];
client->get_peername_to(peername_buf);
this->client_disconnected_trigger_->trigger(std::string(client->get_name()), std::string(peername_buf));
#endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.name.c_str());
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->unregister_active_action_calls_for_connection(client.get());
#endif
ESP_LOGV(TAG, "Remove connection %s", client->get_name());
// Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) {
@@ -211,9 +202,10 @@ void APIServer::loop() {
}
this->clients_.pop_back();
// Schedule reboot when last client disconnects
// Last client disconnected - set warning and start tracking for reboot timeout
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
this->schedule_reboot_timeout_();
this->status_set_warning();
this->last_connected_ = App.get_loop_component_start_time();
}
// Don't increment client_index since we need to process the swapped element
}
@@ -227,8 +219,8 @@ void APIServer::dump_config() {
" Max connections: %u",
network::get_use_address(), this->port_, this->listen_backlog_, this->max_connections_);
#ifdef USE_API_NOISE
ESP_LOGCONFIG(TAG, " Noise encryption: %s", YESNO(this->noise_ctx_->has_psk()));
if (!this->noise_ctx_->has_psk()) {
ESP_LOGCONFIG(TAG, " Noise encryption: %s", YESNO(this->noise_ctx_.has_psk()));
if (!this->noise_ctx_.has_psk()) {
ESP_LOGCONFIG(TAG, " Supports encryption: YES");
}
#else
@@ -347,6 +339,10 @@ API_DISPATCH_UPDATE(valve::Valve, valve)
API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player)
#endif
#ifdef USE_WATER_HEATER
API_DISPATCH_UPDATE(water_heater::WaterHeater, water_heater)
#endif
#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()
@@ -402,7 +398,7 @@ void APIServer::register_action_response_callback(uint32_t call_id, ActionRespon
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) {
if (it->call_id == call_id) {
auto callback = std::move(it->callback);
@@ -414,7 +410,7 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
}
}
#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) {
for (auto it = this->action_response_callbacks_.begin(); it != this->action_response_callbacks_.end(); ++it) {
if (it->call_id == call_id) {
@@ -431,25 +427,76 @@ void APIServer::handle_action_response(uint32_t call_id, bool success, const std
#endif // USE_API_HOMEASSISTANT_SERVICES
#ifdef USE_API_HOMEASSISTANT_STATES
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f) {
// Helper to add subscription (reduces duplication)
void APIServer::add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
bool once) {
this->state_subs_.push_back(HomeAssistantStateSubscription{
.entity_id = std::move(entity_id),
.attribute = std::move(attribute),
.callback = std::move(f),
.once = false,
.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)
});
}
// Helper to add subscription with heap-allocated strings (reduces duplication)
void APIServer::add_state_subscription_(std::string entity_id, optional<std::string> attribute,
std::function<void(StringRef)> f, bool once) {
HomeAssistantStateSubscription sub;
// Allocate heap storage for the strings
sub.entity_id_dynamic_storage = std::make_unique<std::string>(std::move(entity_id));
sub.entity_id = sub.entity_id_dynamic_storage->c_str();
if (attribute.has_value()) {
sub.attribute_dynamic_storage = std::make_unique<std::string>(std::move(attribute.value()));
sub.attribute = sub.attribute_dynamic_storage->c_str();
} else {
sub.attribute = nullptr;
}
sub.callback = std::move(f);
sub.once = once;
this->state_subs_.push_back(std::move(sub));
}
// New const char* overload (for internal components - zero allocation)
void APIServer::subscribe_home_assistant_state(const char *entity_id, const char *attribute,
std::function<void(StringRef)> f) {
this->add_state_subscription_(entity_id, attribute, std::move(f), false);
}
void APIServer::get_home_assistant_state(const char *entity_id, const char *attribute,
std::function<void(StringRef)> f) {
this->add_state_subscription_(entity_id, attribute, std::move(f), true);
}
// std::string overload with StringRef callback (zero-allocation callback)
void APIServer::subscribe_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(StringRef)> 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(std::string)> f) {
this->state_subs_.push_back(HomeAssistantStateSubscription{
.entity_id = std::move(entity_id),
.attribute = std::move(attribute),
.callback = std::move(f),
.once = true,
});
};
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);
}
const std::vector<APIServer::HomeAssistantStateSubscription> &APIServer::get_state_subs() const {
return this->state_subs_;
@@ -493,7 +540,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
ESP_LOGW(TAG, "Key set in YAML");
return false;
#else
auto &old_psk = this->noise_ctx_->get_psk();
auto &old_psk = this->noise_ctx_.get_psk();
if (std::equal(old_psk.begin(), old_psk.end(), psk.begin())) {
ESP_LOGW(TAG, "New PSK matches old");
return true;
@@ -528,7 +575,42 @@ void APIServer::request_time() {
}
#endif
bool APIServer::is_connected() const { return !this->clients_.empty(); }
bool APIServer::is_connected(bool state_subscription_only) const {
if (!state_subscription_only) {
return !this->clients_.empty();
}
for (const auto &client : this->clients_) {
if (client->flags_.state_subscription) {
return true;
}
}
return false;
}
#ifdef USE_LOGGER
void APIServer::on_log(uint8_t level, const char *tag, const char *message, size_t message_len) {
if (this->shutting_down_) {
// Don't try to send logs during shutdown
// as it could result in a recursion and
// we would be filling a buffer we are trying to clear
return;
}
for (auto &c : this->clients_) {
if (!c->flags_.remove && c->get_log_subscription_level() >= level)
c->try_send_log_message(level, tag, message, message_len);
}
}
#endif
#ifdef USE_CAMERA
void APIServer::on_camera_image(const std::shared_ptr<camera::CameraImage> &image) {
for (auto &c : this->clients_) {
if (!c->flags_.remove)
c->set_camera_state(image);
}
}
#endif
void APIServer::on_shutdown() {
this->shutting_down_ = true;
@@ -565,5 +647,84 @@ bool APIServer::teardown() {
return this->clients_.empty();
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Timeout for action calls - matches aioesphomeapi client timeout (default 30s)
// Can be overridden via USE_API_ACTION_CALL_TIMEOUT_MS define for testing
#ifndef USE_API_ACTION_CALL_TIMEOUT_MS
#define USE_API_ACTION_CALL_TIMEOUT_MS 30000 // NOLINT
#endif
uint32_t APIServer::register_active_action_call(uint32_t client_call_id, APIConnection *conn) {
uint32_t action_call_id = this->next_action_call_id_++;
// Handle wraparound (skip 0 as it means "no call")
if (this->next_action_call_id_ == 0) {
this->next_action_call_id_ = 1;
}
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)
this->set_timeout(str_sprintf("action_call_%u", action_call_id), USE_API_ACTION_CALL_TIMEOUT_MS,
[this, action_call_id]() {
ESP_LOGD(TAG, "Action call %u timed out", action_call_id);
this->unregister_active_action_call(action_call_id);
});
return action_call_id;
}
void APIServer::unregister_active_action_call(uint32_t action_call_id) {
// Cancel the timeout for this action call
this->cancel_timeout(str_sprintf("action_call_%u", action_call_id));
// Swap-and-pop is more efficient than remove_if for unordered vectors
for (size_t i = 0; i < this->active_action_calls_.size(); i++) {
if (this->active_action_calls_[i].action_call_id == action_call_id) {
std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
this->active_action_calls_.pop_back();
return;
}
}
}
void APIServer::unregister_active_action_calls_for_connection(APIConnection *conn) {
// Remove all active action calls for disconnected connection using swap-and-pop
for (size_t i = 0; i < this->active_action_calls_.size();) {
if (this->active_action_calls_[i].connection == conn) {
// Cancel the timeout for this action call
this->cancel_timeout(str_sprintf("action_call_%u", this->active_action_calls_[i].action_call_id));
std::swap(this->active_action_calls_[i], this->active_action_calls_.back());
this->active_action_calls_.pop_back();
// Don't increment i - need to check the swapped element
} else {
i++;
}
}
}
void APIServer::send_action_response(uint32_t action_call_id, bool success, StringRef error_message) {
for (auto &call : this->active_action_calls_) {
if (call.action_call_id == action_call_id) {
call.connection->send_execute_service_response(call.client_call_id, success, error_message);
return;
}
}
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
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) {
for (auto &call : this->active_action_calls_) {
if (call.action_call_id == action_call_id) {
call.connection->send_execute_service_response(call.client_call_id, success, error_message, response_data,
response_data_len);
return;
}
}
ESP_LOGW(TAG, "Cannot send response: no active call found for action_call_id %u", action_call_id);
}
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
} // namespace esphome::api
#endif

View File

@@ -10,24 +10,42 @@
#include "esphome/core/component.h"
#include "esphome/core/controller.h"
#include "esphome/core/log.h"
#include "esphome/core/string_ref.h"
#include "list_entities.h"
#include "subscribe_state.h"
#ifdef USE_API_SERVICES
#include "user_services.h"
#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#endif
#ifdef USE_CAMERA
#include "esphome/components/camera/camera.h"
#endif
#include <map>
#include <vector>
namespace esphome::api {
#ifdef USE_API_USER_DEFINED_ACTIONS
// Forward declaration - full definition in user_services.h
class UserServiceDescriptor;
#endif
#ifdef USE_API_NOISE
struct SavedNoisePsk {
psk_t psk;
} PACKED; // NOLINT
#endif
class APIServer : public Component, public Controller {
class APIServer : public Component,
public Controller
#ifdef USE_LOGGER
,
public logger::LogListener
#endif
#ifdef USE_CAMERA
,
public camera::CameraListener
#endif
{
public:
APIServer();
void setup() override;
@@ -37,6 +55,12 @@ class APIServer : public Component, public Controller {
void dump_config() override;
void on_shutdown() override;
bool teardown() override;
#ifdef USE_LOGGER
void on_log(uint8_t level, const char *tag, const char *message, size_t message_len) override;
#endif
#ifdef USE_CAMERA
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);
@@ -54,8 +78,8 @@ class APIServer : public Component, public Controller {
#ifdef USE_API_NOISE
bool save_noise_psk(psk_t psk, bool make_active = true);
bool clear_noise_psk(bool make_active = true);
void set_noise_psk(psk_t psk) { noise_ctx_->set_psk(psk); }
std::shared_ptr<APINoiseContext> get_noise_ctx() { return noise_ctx_; }
void set_noise_psk(psk_t psk) { this->noise_ctx_.set_psk(psk); }
APINoiseContext &get_noise_ctx() { return this->noise_ctx_; }
#endif // USE_API_NOISE
void handle_disconnect(APIConnection *conn);
@@ -110,6 +134,9 @@ class APIServer : public Component, public Controller {
#ifdef USE_MEDIA_PLAYER
void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif
#ifdef USE_WATER_HEATER
void on_water_heater_update(water_heater::WaterHeater *obj) override;
#endif
#ifdef USE_API_HOMEASSISTANT_SERVICES
void send_homeassistant_action(const HomeassistantActionRequest &call);
@@ -117,14 +144,14 @@ class APIServer : public Component, public Controller {
// Action response handling
using ActionResponseCallback = std::function<void(const class ActionResponse &)>;
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
void handle_action_response(uint32_t call_id, bool success, const std::string &error_message,
const uint8_t *response_data, size_t response_data_len);
void handle_action_response(uint32_t call_id, bool success, StringRef error_message, const uint8_t *response_data,
size_t response_data_len);
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
#endif // USE_API_HOMEASSISTANT_ACTION_RESPONSES
#endif // USE_API_HOMEASSISTANT_SERVICES
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
void initialize_user_services(std::initializer_list<UserServiceDescriptor *> services) {
this->user_services_.assign(services);
}
@@ -132,6 +159,19 @@ class APIServer : public Component, public Controller {
// Only compile push_back method when custom_services: true (external components)
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
#endif
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Action call context management - supports concurrent calls from multiple clients
// Returns server-generated action_call_id to avoid collisions when clients use same call_id
uint32_t register_active_action_call(uint32_t client_call_id, APIConnection *conn);
void unregister_active_action_call(uint32_t action_call_id);
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)
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void send_action_response(uint32_t action_call_id, bool success, StringRef error_message,
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
#endif
#ifdef USE_HOMEASSISTANT_TIME
void request_time();
@@ -150,23 +190,40 @@ class APIServer : public Component, public Controller {
void on_zwave_proxy_request(const esphome::api::ProtoMessage &msg);
#endif
bool is_connected() const;
bool is_connected(bool state_subscription_only = false) const;
#ifdef USE_API_HOMEASSISTANT_STATES
struct HomeAssistantStateSubscription {
std::string entity_id;
optional<std::string> attribute;
std::function<void(std::string)> callback;
const char *entity_id; // Pointer to flash (internal) or heap (external)
const char *attribute; // Pointer to flash or nullptr (nullptr means no attribute)
std::function<void(StringRef)> callback;
bool once;
// Dynamic storage for external components using std::string API (custom_api_device.h)
// These are only allocated when using the std::string overload (nullptr for const char* overload)
std::unique_ptr<std::string> entity_id_dynamic_storage;
std::unique_ptr<std::string> attribute_dynamic_storage;
};
// New const char* overload (for internal components - zero allocation)
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(StringRef)> f);
// 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,
std::function<void(std::string)> f);
std::function<void(StringRef)> f);
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;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
#endif
@@ -180,11 +237,20 @@ class APIServer : public Component, public Controller {
#endif
protected:
void schedule_reboot_timeout_();
#ifdef USE_API_NOISE
bool update_noise_psk_(const SavedNoisePsk &new_psk, const LogString *save_log_msg, const LogString *fail_log_msg,
const psk_t &active_psk, bool make_active);
#endif // USE_API_NOISE
#ifdef USE_API_HOMEASSISTANT_STATES
// Helper methods to reduce code duplication
void add_state_subscription_(const char *entity_id, const char *attribute, std::function<void(StringRef)> f,
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,
std::function<void(const std::string &)> f, bool once);
#endif // USE_API_HOMEASSISTANT_STATES
// Pointers and pointer-like types first (4 bytes each)
std::unique_ptr<socket::Socket> socket_ = nullptr;
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
@@ -196,6 +262,7 @@ class APIServer : public Component, public Controller {
// 4-byte aligned types
uint32_t reboot_timeout_{300000};
uint32_t last_connected_{0};
// Vectors and strings (12 bytes each on 32-bit)
std::vector<std::unique_ptr<APIConnection>> clients_;
@@ -206,8 +273,19 @@ class APIServer : public Component, public Controller {
#ifdef USE_API_HOMEASSISTANT_STATES
std::vector<HomeAssistantStateSubscription> state_subs_;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
std::vector<UserServiceDescriptor *> user_services_;
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Active action calls - supports concurrent calls from multiple clients
// Uses server-generated action_call_id to avoid collisions when multiple clients use same call_id
struct ActiveActionCall {
uint32_t action_call_id; // Server-generated unique ID (passed to actions)
uint32_t client_call_id; // Client's original call_id (used in response)
APIConnection *connection;
};
std::vector<ActiveActionCall> active_action_calls_;
uint32_t next_action_call_id_{1}; // Counter for generating unique action_call_ids
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES
#endif
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
struct PendingActionResponse {
@@ -228,7 +306,7 @@ class APIServer : public Component, public Controller {
// 7 bytes used, 1 byte padding
#ifdef USE_API_NOISE
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();
APINoiseContext noise_ctx_;
ESPPreferenceObject noise_pref_;
#endif // USE_API_NOISE
};
@@ -236,8 +314,11 @@ class APIServer : public Component, public Controller {
extern APIServer *global_api_server; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
template<typename... Ts> class APIConnectedCondition : public Condition<Ts...> {
TEMPLATABLE_VALUE(bool, state_subscription_only)
public:
bool check(const Ts &...x) override { return global_api_server->is_connected(); }
bool check(const Ts &...x) override {
return global_api_server->is_connected(this->state_subscription_only_.value(x...));
}
};
} // namespace esphome::api

View File

@@ -3,12 +3,12 @@
#include <map>
#include "api_server.h"
#ifdef USE_API
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
#include "user_services.h"
#endif
namespace esphome::api {
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
template<typename T, typename... Ts> class CustomAPIDeviceService : public UserServiceDynamic<Ts...> {
public:
CustomAPIDeviceService(const std::string &name, const std::array<std::string, sizeof...(Ts)> &arg_names, T *obj,
@@ -16,12 +16,15 @@ template<typename T, typename... Ts> class CustomAPIDeviceService : public UserS
: UserServiceDynamic<Ts...>(name, arg_names), obj_(obj), callback_(callback) {}
protected:
void execute(Ts... x) override { (this->obj_->*this->callback_)(x...); } // NOLINT
// CustomAPIDevice services don't support action responses - ignore call_id and return_response
void execute(uint32_t /*call_id*/, bool /*return_response*/, Ts... x) override {
(this->obj_->*this->callback_)(x...); // NOLINT
}
T *obj_;
void (T::*callback_)(Ts...);
};
#endif // USE_API_SERVICES
#endif // USE_API_USER_DEFINED_ACTIONS
class CustomAPIDevice {
public:
@@ -49,7 +52,7 @@ class CustomAPIDevice {
* @param name The name of the service to register.
* @param arg_names The name of the arguments for the service, must match the arguments of the function.
*/
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
template<typename T, typename... Ts>
void register_service(void (T::*callback)(Ts...), const std::string &name,
const std::array<std::string, sizeof...(Ts)> &arg_names) {
@@ -90,7 +93,7 @@ class CustomAPIDevice {
* @param callback The member function to call when the service is triggered.
* @param name The name of the arguments for the service, must match the arguments of the function.
*/
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
template<typename T> void register_service(void (T::*callback)(), const std::string &name) {
#ifdef USE_API_CUSTOM_SERVICES
auto *service = new CustomAPIDeviceService<T>(name, {}, (T *) this, callback); // NOLINT
@@ -119,21 +122,36 @@ class CustomAPIDevice {
* subscribe_homeassistant_state(&CustomNativeAPI::on_state_changed, "climate.kitchen", "current_temperature");
* }
*
* void on_state_changed(std::string state) {
* // State of sensor.weather_forecast is `state`
* void on_state_changed(StringRef 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.
* @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 attribute The entity state attribute to track.
*/
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,
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), 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.
@@ -145,23 +163,45 @@ class CustomAPIDevice {
* 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`
* }
* ```
*
* @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 attribute The entity state attribute to track.
*/
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,
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), 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
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>
void subscribe_homeassistant_state(void (T::*callback)(std::string), const std::string &entity_id,
const std::string &attribute = "") {
@@ -170,6 +210,14 @@ class CustomAPIDevice {
"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>
void subscribe_homeassistant_state(void (T::*callback)(std::string, std::string), const std::string &entity_id,
const std::string &attribute = "") {

View File

@@ -12,10 +12,17 @@
#endif
#include "esphome/core/automation.h"
#include "esphome/core/helpers.h"
#include "esphome/core/string_ref.h"
namespace esphome::api {
template<typename... X> class TemplatableStringValue : public TemplatableValue<std::string, X...> {
// Verify that const char* uses the base class STATIC_STRING optimization (no heap allocation)
// rather than being wrapped in a lambda. The base class constructor for const char* is more
// specialized than the templated constructor here, so it should be selected.
static_assert(std::is_constructible_v<TemplatableValue<std::string, X...>, const char *>,
"Base class must have const char* constructor for STATIC_STRING optimization");
private:
// Helper to convert value to string - handles the case where value is already a string
template<typename T> static std::string value_to_string(T &&val) { return to_string(std::forward<T>(val)); }
@@ -46,23 +53,25 @@ template<typename... Ts> class TemplatableKeyValuePair {
// Keys are always string literals from YAML dictionary keys (e.g., "code", "event")
// and never templatable values or lambdas. Only the value parameter can be a lambda/template.
// Using pass-by-value with std::move allows optimal performance for both lvalues and rvalues.
template<typename T> TemplatableKeyValuePair(std::string key, T value) : key(std::move(key)), value(value) {}
// Using const char* avoids std::string heap allocation - keys remain in flash.
template<typename T> TemplatableKeyValuePair(const char *key, T value) : key(key), value(value) {}
std::string key;
const char *key{nullptr};
TemplatableStringValue<Ts...> value;
};
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
// Represents the response data from a Home Assistant action
// Note: This class holds a StringRef to the error_message from the protobuf message.
// The protobuf message must outlive the ActionResponse (which is guaranteed since
// the callback is invoked synchronously while the message is on the stack).
class ActionResponse {
public:
ActionResponse(bool success, std::string error_message = "")
: success_(success), error_message_(std::move(error_message)) {}
ActionResponse(bool success, StringRef error_message) : success_(success), error_message_(error_message) {}
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
ActionResponse(bool success, std::string error_message, const uint8_t *data, size_t data_len)
: success_(success), error_message_(std::move(error_message)) {
ActionResponse(bool success, StringRef error_message, const uint8_t *data, size_t data_len)
: success_(success), error_message_(error_message) {
if (data == nullptr || data_len == 0)
return;
this->json_document_ = json::parse_json(data, data_len);
@@ -70,7 +79,8 @@ class ActionResponse {
#endif
bool is_success() const { return this->success_; }
const std::string &get_error_message() const { return this->error_message_; }
// Returns reference to error message - can be implicitly converted to std::string if needed
const StringRef &get_error_message() const { return this->error_message_; }
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
// Get data as parsed JSON object (const version returns read-only view)
@@ -79,7 +89,7 @@ class ActionResponse {
protected:
bool success_;
std::string error_message_;
StringRef error_message_;
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES_JSON
JsonDocument json_document_;
#endif
@@ -105,14 +115,15 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
// Keys are always string literals from the Python code generation (e.g., cg.add(var.add_data("tag_id", templ))).
// The value parameter can be a lambda/template, but keys are never templatable.
template<typename K, typename V> void add_data(K &&key, V &&value) {
this->add_kv_(this->data_, std::forward<K>(key), std::forward<V>(value));
// Using const char* for keys avoids std::string heap allocation - keys remain in flash.
template<typename V> void add_data(const char *key, V &&value) {
this->add_kv_(this->data_, key, std::forward<V>(value));
}
template<typename K, typename V> void add_data_template(K &&key, V &&value) {
this->add_kv_(this->data_template_, std::forward<K>(key), std::forward<V>(value));
template<typename V> void add_data_template(const char *key, V &&value) {
this->add_kv_(this->data_template_, key, std::forward<V>(value));
}
template<typename K, typename V> void add_variable(K &&key, V &&value) {
this->add_kv_(this->variables_, std::forward<K>(key), std::forward<V>(value));
template<typename V> void add_variable(const char *key, V &&value) {
this->add_kv_(this->variables_, key, std::forward<V>(value));
}
#ifdef USE_API_HOMEASSISTANT_ACTION_RESPONSES
@@ -185,10 +196,11 @@ template<typename... Ts> class HomeAssistantServiceCallAction : public Action<Ts
}
protected:
// Helper to add key-value pairs to FixedVectors with perfect forwarding to avoid copies
template<typename K, typename V> void add_kv_(FixedVector<TemplatableKeyValuePair<Ts...>> &vec, K &&key, V &&value) {
// Helper to add key-value pairs to FixedVectors
// Keys are always string literals (const char*), values can be lambdas/templates
template<typename V> void add_kv_(FixedVector<TemplatableKeyValuePair<Ts...>> &vec, const char *key, V &&value) {
auto &kv = vec.emplace_back();
kv.key = std::forward<K>(key);
kv.key = key;
kv.value = std::forward<V>(value);
}

View File

@@ -5,6 +5,9 @@
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/util.h"
#ifdef USE_API_USER_DEFINED_ACTIONS
#include "user_services.h"
#endif
namespace esphome::api {
@@ -70,6 +73,9 @@ LIST_ENTITIES_HANDLER(media_player, media_player::MediaPlayer, ListEntitiesMedia
LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel,
ListEntitiesAlarmControlPanelResponse)
#endif
#ifdef USE_WATER_HEATER
LIST_ENTITIES_HANDLER(water_heater, water_heater::WaterHeater, ListEntitiesWaterHeaterResponse)
#endif
#ifdef USE_EVENT
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
#endif
@@ -82,7 +88,7 @@ bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
auto resp = service->encode_list_service_response();
return this->client_->send_message(resp, ListEntitiesServicesResponse::MESSAGE_TYPE);

View File

@@ -43,7 +43,7 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
bool on_service(UserServiceDescriptor *service) override;
#endif
#ifdef USE_CAMERA
@@ -82,6 +82,9 @@ class ListEntitiesIterator : public ComponentIterator {
#ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif
#ifdef USE_WATER_HEATER
bool on_water_heater(water_heater::WaterHeater *entity) override;
#endif
#ifdef USE_EVENT
bool on_event(event::Event *entity) override;
#endif

View File

@@ -334,7 +334,7 @@ class ProtoWriteBuffer {
void encode_sint64(uint32_t field_id, int64_t value, bool force = false) {
this->encode_uint64(field_id, encode_zigzag64(value), force);
}
void encode_message(uint32_t field_id, const ProtoMessage &value, bool force = false);
void encode_message(uint32_t field_id, const ProtoMessage &value);
std::vector<uint8_t> *get_buffer() const { return buffer_; }
protected:
@@ -795,7 +795,7 @@ class ProtoSize {
};
// 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
// Calculate the message size first
@@ -846,7 +846,7 @@ class ProtoService {
*/
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
virtual bool send_buffer(ProtoWriteBuffer buffer, uint8_t message_type) = 0;
virtual void read_message(uint32_t msg_size, uint32_t msg_type, uint8_t *msg_data) = 0;
virtual void read_message(uint32_t msg_size, uint32_t msg_type, const uint8_t *msg_data) = 0;
// Optimized method that pre-allocates buffer based on message size
bool send_message_(const ProtoMessage &msg, uint8_t message_type) {

View File

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

View File

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

View File

@@ -1,20 +1,31 @@
#pragma once
#include <tuple>
#include <utility>
#include <vector>
#include "esphome/core/component.h"
#include "esphome/core/automation.h"
#include "api_pb2.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
#include "esphome/components/json/json_util.h"
#endif
#ifdef USE_API_SERVICES
#ifdef USE_API_USER_DEFINED_ACTIONS
namespace esphome::api {
// Forward declaration - full definition in api_server.h
class APIServer;
class UserServiceDescriptor {
public:
virtual ListEntitiesServicesResponse encode_list_service_response() = 0;
virtual bool execute_service(const ExecuteServiceRequest &req) = 0;
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Overload that accepts server-generated action_call_id (avoids client call_id collisions)
virtual bool execute_service(const ExecuteServiceRequest &req, uint32_t action_call_id) = 0;
#endif
bool is_internal() { return false; }
};
@@ -27,8 +38,9 @@ template<typename T> enums::ServiceArgType to_service_arg_type();
// Stores only pointers to string literals in flash - no heap allocation
template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
public:
UserServiceBase(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names)
: name_(name), arg_names_(arg_names) {
UserServiceBase(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names,
enums::SupportsResponseType supports_response = enums::SUPPORTS_RESPONSE_NONE)
: name_(name), arg_names_(arg_names), supports_response_(supports_response) {
this->key_ = fnv1_hash(name);
}
@@ -36,6 +48,7 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
ListEntitiesServicesResponse msg;
msg.set_name(StringRef(this->name_));
msg.key = this->key_;
msg.supports_response = this->supports_response_;
std::array<enums::ServiceArgType, sizeof...(Ts)> arg_types = {to_service_arg_type<Ts>()...};
msg.args.init(sizeof...(Ts));
for (size_t i = 0; i < sizeof...(Ts); i++) {
@@ -51,20 +64,37 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
return false;
if (req.args.size() != sizeof...(Ts))
return false;
this->execute_(req.args, typename gens<sizeof...(Ts)>::type());
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->execute_(req.args, req.call_id, req.return_response, std::make_index_sequence<sizeof...(Ts)>{});
#else
this->execute_(req.args, 0, false, std::make_index_sequence<sizeof...(Ts)>{});
#endif
return true;
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
bool execute_service(const ExecuteServiceRequest &req, uint32_t action_call_id) override {
if (req.key != this->key_)
return false;
if (req.args.size() != sizeof...(Ts))
return false;
this->execute_(req.args, action_call_id, req.return_response, std::make_index_sequence<sizeof...(Ts)>{});
return true;
}
#endif
protected:
virtual void execute(Ts... x) = 0;
template<typename ArgsContainer, int... S> void execute_(const ArgsContainer &args, seq<S...> type) {
this->execute((get_execute_arg_value<Ts>(args[S]))...);
virtual void execute(uint32_t call_id, bool return_response, Ts... x) = 0;
template<typename ArgsContainer, size_t... S>
void execute_(const ArgsContainer &args, uint32_t call_id, bool return_response, std::index_sequence<S...> /*type*/) {
this->execute(call_id, return_response, (get_execute_arg_value<Ts>(args[S]))...);
}
// Pointers to string literals in flash - no heap allocation
const char *name_;
std::array<const char *, sizeof...(Ts)> arg_names_;
uint32_t key_{0};
enums::SupportsResponseType supports_response_{enums::SUPPORTS_RESPONSE_NONE};
};
// Separate class for custom_api_device services (rare case)
@@ -80,6 +110,7 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
ListEntitiesServicesResponse msg;
msg.set_name(StringRef(this->name_));
msg.key = this->key_;
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>()...};
msg.args.init(sizeof...(Ts));
for (size_t i = 0; i < sizeof...(Ts); i++) {
@@ -95,14 +126,31 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
return false;
if (req.args.size() != sizeof...(Ts))
return false;
this->execute_(req.args, typename gens<sizeof...(Ts)>::type());
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
this->execute_(req.args, req.call_id, req.return_response, std::make_index_sequence<sizeof...(Ts)>{});
#else
this->execute_(req.args, 0, false, std::make_index_sequence<sizeof...(Ts)>{});
#endif
return true;
}
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Dynamic services don't support responses yet, but need to implement the interface
bool execute_service(const ExecuteServiceRequest &req, uint32_t action_call_id) override {
if (req.key != this->key_)
return false;
if (req.args.size() != sizeof...(Ts))
return false;
this->execute_(req.args, action_call_id, req.return_response, std::make_index_sequence<sizeof...(Ts)>{});
return true;
}
#endif
protected:
virtual void execute(Ts... x) = 0;
template<typename ArgsContainer, int... S> void execute_(const ArgsContainer &args, seq<S...> type) {
this->execute((get_execute_arg_value<Ts>(args[S]))...);
virtual void execute(uint32_t call_id, bool return_response, Ts... x) = 0;
template<typename ArgsContainer, size_t... S>
void execute_(const ArgsContainer &args, uint32_t call_id, bool return_response, std::index_sequence<S...> /*type*/) {
this->execute(call_id, return_response, (get_execute_arg_value<Ts>(args[S]))...);
}
// Heap-allocated strings for runtime-generated names
@@ -111,15 +159,149 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
uint32_t key_{0};
};
template<typename... Ts> class UserServiceTrigger : public UserServiceBase<Ts...>, public Trigger<Ts...> {
// Primary template declaration
template<enums::SupportsResponseType Mode, typename... Ts> class UserServiceTrigger;
// Specialization for NONE - no extra trigger arguments
template<typename... Ts>
class UserServiceTrigger<enums::SUPPORTS_RESPONSE_NONE, Ts...> : public UserServiceBase<Ts...>, public Trigger<Ts...> {
public:
// Constructor for static names (YAML-defined services - used by code generator)
UserServiceTrigger(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names)
: UserServiceBase<Ts...>(name, arg_names) {}
: UserServiceBase<Ts...>(name, arg_names, enums::SUPPORTS_RESPONSE_NONE) {}
protected:
void execute(Ts... x) override { this->trigger(x...); } // NOLINT
void execute(uint32_t /*call_id*/, bool /*return_response*/, Ts... x) override { this->trigger(x...); }
};
// Specialization for OPTIONAL - call_id and return_response trigger arguments
template<typename... Ts>
class UserServiceTrigger<enums::SUPPORTS_RESPONSE_OPTIONAL, Ts...> : public UserServiceBase<Ts...>,
public Trigger<uint32_t, bool, Ts...> {
public:
UserServiceTrigger(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names)
: UserServiceBase<Ts...>(name, arg_names, enums::SUPPORTS_RESPONSE_OPTIONAL) {}
protected:
void execute(uint32_t call_id, bool return_response, Ts... x) override {
this->trigger(call_id, return_response, x...);
}
};
// Specialization for ONLY - just call_id trigger argument
template<typename... Ts>
class UserServiceTrigger<enums::SUPPORTS_RESPONSE_ONLY, Ts...> : public UserServiceBase<Ts...>,
public Trigger<uint32_t, Ts...> {
public:
UserServiceTrigger(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names)
: UserServiceBase<Ts...>(name, arg_names, enums::SUPPORTS_RESPONSE_ONLY) {}
protected:
void execute(uint32_t call_id, bool /*return_response*/, Ts... x) override { this->trigger(call_id, x...); }
};
// Specialization for STATUS - just call_id trigger argument (reports success/error without data)
template<typename... Ts>
class UserServiceTrigger<enums::SUPPORTS_RESPONSE_STATUS, Ts...> : public UserServiceBase<Ts...>,
public Trigger<uint32_t, Ts...> {
public:
UserServiceTrigger(const char *name, const std::array<const char *, sizeof...(Ts)> &arg_names)
: UserServiceBase<Ts...>(name, arg_names, enums::SUPPORTS_RESPONSE_STATUS) {}
protected:
void execute(uint32_t call_id, bool /*return_response*/, Ts... x) override { this->trigger(call_id, x...); }
};
} // namespace esphome::api
#endif // USE_API_SERVICES
#endif // USE_API_USER_DEFINED_ACTIONS
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES
// Include full definition of APIServer for template implementation
// Must be outside namespace to avoid including STL headers inside namespace
#include "api_server.h"
namespace esphome::api {
template<typename... Ts> class APIRespondAction : public Action<Ts...> {
public:
explicit APIRespondAction(APIServer *parent) : parent_(parent) {}
template<typename V> void set_success(V success) { this->success_ = success; }
template<typename V> void set_error_message(V error) { this->error_message_ = error; }
void set_is_optional_mode(bool is_optional) { this->is_optional_mode_ = is_optional; }
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
void set_data(std::function<void(Ts..., JsonObject)> func) {
this->json_builder_ = std::move(func);
this->has_data_ = true;
}
#endif
void play(const Ts &...x) override {
// Extract call_id from first argument - it's always first for optional/only/status modes
auto args = std::make_tuple(x...);
uint32_t call_id = std::get<0>(args);
bool success = this->success_.value(x...);
std::string error_message = this->error_message_.value(x...);
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
if (this->has_data_) {
// For optional mode, check return_response (second arg) to decide if client wants data
// Use nested if constexpr to avoid compile error when tuple doesn't have enough elements
// (std::tuple_element_t is evaluated before the && short-circuit, so we must nest)
if constexpr (sizeof...(Ts) >= 2) {
if constexpr (std::is_same_v<std::tuple_element_t<1, std::tuple<Ts...>>, bool>) {
if (this->is_optional_mode_) {
bool return_response = std::get<1>(args);
if (!return_response) {
// Client doesn't want response data, just send success/error
this->parent_->send_action_response(call_id, success, error_message);
return;
}
}
}
}
// Build and send JSON response
json::JsonBuilder builder;
this->json_builder_(x..., builder.root());
std::string json_str = builder.serialize();
this->parent_->send_action_response(call_id, success, error_message,
reinterpret_cast<const uint8_t *>(json_str.data()), json_str.size());
return;
}
#endif
this->parent_->send_action_response(call_id, success, error_message);
}
protected:
APIServer *parent_;
TemplatableValue<bool, Ts...> success_{true};
TemplatableValue<std::string, Ts...> error_message_{""};
#ifdef USE_API_USER_DEFINED_ACTION_RESPONSES_JSON
std::function<void(Ts..., JsonObject)> json_builder_;
bool has_data_{false};
#endif
bool is_optional_mode_{false};
};
// Action to unregister a service call after execution completes
// Automatically appended to the end of action lists for non-none response modes
template<typename... Ts> class APIUnregisterServiceCallAction : public Action<Ts...> {
public:
explicit APIUnregisterServiceCallAction(APIServer *parent) : parent_(parent) {}
void play(const Ts &...x) override {
// Extract call_id from first argument - same convention as APIRespondAction
auto args = std::make_tuple(x...);
uint32_t call_id = std::get<0>(args);
if (call_id != 0) {
this->parent_->unregister_active_action_call(call_id);
}
}
protected:
APIServer *parent_;
};
} // namespace esphome::api
#endif // USE_API_USER_DEFINED_ACTION_RESPONSES

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

@@ -2,13 +2,11 @@
#include <cstdint>
namespace esphome {
namespace hm3301 {
namespace esphome::aqi {
class AbstractAQICalculator {
public:
virtual uint16_t get_aqi(uint16_t pm2_5_value, uint16_t pm10_0_value) = 0;
};
} // namespace hm3301
} // namespace esphome
} // namespace esphome::aqi

View File

@@ -1,10 +1,11 @@
#pragma once
#include <climits>
#include "abstract_aqi_calculator.h"
// https://document.airnow.gov/technical-assistance-document-for-the-reporting-of-daily-air-quailty.pdf
namespace esphome {
namespace hm3301 {
namespace esphome::aqi {
class AQICalculator : public AbstractAQICalculator {
public:
@@ -28,6 +29,9 @@ class AQICalculator : public AbstractAQICalculator {
int calculate_index_(uint16_t value, int array[AMOUNT_OF_LEVELS][2]) {
int grid_index = get_grid_index_(value, array);
if (grid_index == -1) {
return -1;
}
int aqi_lo = index_grid_[grid_index][0];
int aqi_hi = index_grid_[grid_index][1];
int conc_lo = array[grid_index][0];
@@ -46,5 +50,4 @@ class AQICalculator : public AbstractAQICalculator {
}
};
} // namespace hm3301
} // namespace esphome
} // namespace esphome::aqi

View File

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

View File

@@ -3,8 +3,7 @@
#include "esphome/core/log.h"
#include "abstract_aqi_calculator.h"
namespace esphome {
namespace hm3301 {
namespace esphome::aqi {
class CAQICalculator : public AbstractAQICalculator {
public:
@@ -48,5 +47,4 @@ class CAQICalculator : public AbstractAQICalculator {
}
};
} // namespace hm3301
} // namespace esphome
} // namespace esphome::aqi

View File

@@ -1,6 +1,6 @@
#include "audio_reader.h"
#ifdef USE_ESP_IDF
#ifdef USE_ESP32
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"

View File

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

View File

@@ -1,12 +1,7 @@
import esphome.codegen as cg
from esphome.components import ble_client, climate
from esphome.components import climate
import esphome.config_validation as cv
from esphome.const import (
CONF_HEAT_MODE,
CONF_RECEIVE_TIMEOUT,
CONF_TEMPERATURE_SOURCE,
CONF_TIME_ID,
)
from esphome.const import CONF_HEAT_MODE, CONF_TEMPERATURE_SOURCE
from .. import BEDJET_CLIENT_SCHEMA, bedjet_ns, register_bedjet_child
@@ -38,22 +33,6 @@ CONFIG_SCHEMA = (
}
)
.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.html"
),
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)
)

View File

@@ -1,8 +1,8 @@
#include "bh1750.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"
namespace esphome {
namespace bh1750 {
namespace esphome::bh1750 {
static const char *const TAG = "bh1750.sensor";
@@ -13,6 +13,31 @@ static const uint8_t BH1750_COMMAND_ONE_TIME_L = 0b00100011;
static const uint8_t BH1750_COMMAND_ONE_TIME_H = 0b00100000;
static const uint8_t BH1750_COMMAND_ONE_TIME_H2 = 0b00100001;
static constexpr uint32_t MEASUREMENT_TIMEOUT_MS = 2000;
static constexpr float HIGH_LIGHT_THRESHOLD_LX = 7000.0f;
// Measurement time constants (datasheet values)
static constexpr uint16_t MTREG_DEFAULT = 69;
static constexpr uint16_t MTREG_MIN = 31;
static constexpr uint16_t MTREG_MAX = 254;
static constexpr uint16_t MEAS_TIME_L_MS = 24; // L-resolution max measurement time @ mtreg=69
static constexpr uint16_t MEAS_TIME_H_MS = 180; // H/H2-resolution max measurement time @ mtreg=69
// Conversion constants (datasheet formulas)
static constexpr float RESOLUTION_DIVISOR = 1.2f; // counts to lux conversion divisor
static constexpr float MODE_H2_DIVISOR = 2.0f; // H2 mode has 2x higher resolution
// MTreg calculation constants
static constexpr int COUNTS_TARGET = 50000; // Target counts for optimal range (avoid saturation)
static constexpr int COUNTS_NUMERATOR = 10;
static constexpr int COUNTS_DENOMINATOR = 12;
// MTreg register bit manipulation constants
static constexpr uint8_t MTREG_HI_SHIFT = 5; // High 3 bits start at bit 5
static constexpr uint8_t MTREG_HI_MASK = 0b111; // 3-bit mask for high bits
static constexpr uint8_t MTREG_LO_SHIFT = 0; // Low 5 bits start at bit 0
static constexpr uint8_t MTREG_LO_MASK = 0b11111; // 5-bit mask for low bits
/*
bh1750 properties:
@@ -43,74 +68,7 @@ void BH1750Sensor::setup() {
this->mark_failed();
return;
}
}
void BH1750Sensor::read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function<void(float)> &f) {
// turn on (after one-shot sensor automatically powers down)
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Power on failed");
f(NAN);
return;
}
if (active_mtreg_ != mtreg) {
// set mtreg
uint8_t mtreg_hi = BH1750_COMMAND_MT_REG_HI | ((mtreg >> 5) & 0b111);
uint8_t mtreg_lo = BH1750_COMMAND_MT_REG_LO | ((mtreg >> 0) & 0b11111);
if (this->write(&mtreg_hi, 1) != i2c::ERROR_OK || this->write(&mtreg_lo, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Set measurement time failed");
active_mtreg_ = 0;
f(NAN);
return;
}
active_mtreg_ = mtreg;
}
uint8_t cmd;
uint16_t meas_time;
switch (mode) {
case BH1750_MODE_L:
cmd = BH1750_COMMAND_ONE_TIME_L;
meas_time = 24 * mtreg / 69;
break;
case BH1750_MODE_H:
cmd = BH1750_COMMAND_ONE_TIME_H;
meas_time = 180 * mtreg / 69;
break;
case BH1750_MODE_H2:
cmd = BH1750_COMMAND_ONE_TIME_H2;
meas_time = 180 * mtreg / 69;
break;
default:
f(NAN);
return;
}
if (this->write(&cmd, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Start measurement failed");
f(NAN);
return;
}
// probably not needed, but adjust for rounding
meas_time++;
this->set_timeout("read", meas_time, [this, mode, mtreg, f]() {
uint16_t raw_value;
if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Read data failed");
f(NAN);
return;
}
raw_value = i2c::i2ctohs(raw_value);
float lx = float(raw_value) / 1.2f;
lx *= 69.0f / mtreg;
if (mode == BH1750_MODE_H2)
lx /= 2.0f;
f(lx);
});
this->state_ = IDLE;
}
void BH1750Sensor::dump_config() {
@@ -124,45 +82,189 @@ void BH1750Sensor::dump_config() {
}
void BH1750Sensor::update() {
// first do a quick measurement in L-mode with full range
// to find right range
this->read_lx_(BH1750_MODE_L, 31, [this](float val) {
if (std::isnan(val)) {
this->status_set_warning();
this->publish_state(NAN);
const uint32_t now = millis();
// Start coarse measurement to determine optimal mode/mtreg
if (this->state_ != IDLE) {
// Safety timeout: reset if stuck
if (now - this->measurement_start_time_ > MEASUREMENT_TIMEOUT_MS) {
ESP_LOGW(TAG, "Measurement timeout, resetting state");
this->state_ = IDLE;
} else {
ESP_LOGW(TAG, "Previous measurement not complete, skipping update");
return;
}
}
BH1750Mode use_mode;
uint8_t use_mtreg;
if (val <= 7000) {
use_mode = BH1750_MODE_H2;
use_mtreg = 254;
} else {
use_mode = BH1750_MODE_H;
// lx = counts / 1.2 * (69 / mtreg)
// -> mtreg = counts / 1.2 * (69 / lx)
// calculate for counts=50000 (allow some range to not saturate, but maximize mtreg)
// -> mtreg = 50000*(10/12)*(69/lx)
int ideal_mtreg = 50000 * 10 * 69 / (12 * (int) val);
use_mtreg = std::min(254, std::max(31, ideal_mtreg));
}
ESP_LOGV(TAG, "L result: %f -> Calculated mode=%d, mtreg=%d", val, (int) use_mode, use_mtreg);
if (!this->start_measurement_(BH1750_MODE_L, MTREG_MIN, now)) {
this->status_set_warning();
this->publish_state(NAN);
return;
}
this->read_lx_(use_mode, use_mtreg, [this](float val) {
if (std::isnan(val)) {
this->status_set_warning();
this->publish_state(NAN);
return;
this->state_ = WAITING_COARSE_MEASUREMENT;
this->enable_loop(); // Enable loop while measurement in progress
}
void BH1750Sensor::loop() {
const uint32_t now = App.get_loop_component_start_time();
switch (this->state_) {
case IDLE:
// Disable loop when idle to save cycles
this->disable_loop();
break;
case WAITING_COARSE_MEASUREMENT:
if (now - this->measurement_start_time_ >= this->measurement_duration_) {
this->state_ = READING_COARSE_RESULT;
}
ESP_LOGD(TAG, "'%s': Illuminance=%.1flx", this->get_name().c_str(), val);
break;
case READING_COARSE_RESULT: {
float lx;
if (!this->read_measurement_(lx)) {
this->fail_and_reset_();
break;
}
this->process_coarse_result_(lx);
// Start fine measurement with optimal settings
// fetch millis() again since the read can take a bit
if (!this->start_measurement_(this->fine_mode_, this->fine_mtreg_, millis())) {
this->fail_and_reset_();
break;
}
this->state_ = WAITING_FINE_MEASUREMENT;
break;
}
case WAITING_FINE_MEASUREMENT:
if (now - this->measurement_start_time_ >= this->measurement_duration_) {
this->state_ = READING_FINE_RESULT;
}
break;
case READING_FINE_RESULT: {
float lx;
if (!this->read_measurement_(lx)) {
this->fail_and_reset_();
break;
}
ESP_LOGD(TAG, "'%s': Illuminance=%.1flx", this->get_name().c_str(), lx);
this->status_clear_warning();
this->publish_state(val);
});
});
this->publish_state(lx);
this->state_ = IDLE;
break;
}
}
}
bool BH1750Sensor::start_measurement_(BH1750Mode mode, uint8_t mtreg, uint32_t now) {
// Power on
uint8_t turn_on = BH1750_COMMAND_POWER_ON;
if (this->write(&turn_on, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Power on failed");
return false;
}
// Set MTreg if changed
if (this->active_mtreg_ != mtreg) {
uint8_t mtreg_hi = BH1750_COMMAND_MT_REG_HI | ((mtreg >> MTREG_HI_SHIFT) & MTREG_HI_MASK);
uint8_t mtreg_lo = BH1750_COMMAND_MT_REG_LO | ((mtreg >> MTREG_LO_SHIFT) & MTREG_LO_MASK);
if (this->write(&mtreg_hi, 1) != i2c::ERROR_OK || this->write(&mtreg_lo, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Set measurement time failed");
this->active_mtreg_ = 0;
return false;
}
this->active_mtreg_ = mtreg;
}
// Start measurement
uint8_t cmd;
uint16_t meas_time;
switch (mode) {
case BH1750_MODE_L:
cmd = BH1750_COMMAND_ONE_TIME_L;
meas_time = MEAS_TIME_L_MS * mtreg / MTREG_DEFAULT;
break;
case BH1750_MODE_H:
cmd = BH1750_COMMAND_ONE_TIME_H;
meas_time = MEAS_TIME_H_MS * mtreg / MTREG_DEFAULT;
break;
case BH1750_MODE_H2:
cmd = BH1750_COMMAND_ONE_TIME_H2;
meas_time = MEAS_TIME_H_MS * mtreg / MTREG_DEFAULT;
break;
default:
return false;
}
if (this->write(&cmd, 1) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Start measurement failed");
return false;
}
// Store current measurement parameters
this->current_mode_ = mode;
this->current_mtreg_ = mtreg;
this->measurement_start_time_ = now;
this->measurement_duration_ = meas_time + 1; // Add 1ms for safety
return true;
}
bool BH1750Sensor::read_measurement_(float &lx_out) {
uint16_t raw_value;
if (this->read(reinterpret_cast<uint8_t *>(&raw_value), 2) != i2c::ERROR_OK) {
ESP_LOGW(TAG, "Read data failed");
return false;
}
raw_value = i2c::i2ctohs(raw_value);
float lx = float(raw_value) / RESOLUTION_DIVISOR;
lx *= float(MTREG_DEFAULT) / this->current_mtreg_;
if (this->current_mode_ == BH1750_MODE_H2) {
lx /= MODE_H2_DIVISOR;
}
lx_out = lx;
return true;
}
void BH1750Sensor::process_coarse_result_(float lx) {
if (std::isnan(lx)) {
// Use defaults if coarse measurement failed
this->fine_mode_ = BH1750_MODE_H2;
this->fine_mtreg_ = MTREG_MAX;
return;
}
if (lx <= HIGH_LIGHT_THRESHOLD_LX) {
this->fine_mode_ = BH1750_MODE_H2;
this->fine_mtreg_ = MTREG_MAX;
} else {
this->fine_mode_ = BH1750_MODE_H;
// lx = counts / 1.2 * (69 / mtreg)
// -> mtreg = counts / 1.2 * (69 / lx)
// calculate for counts=50000 (allow some range to not saturate, but maximize mtreg)
// -> mtreg = 50000*(10/12)*(69/lx)
int ideal_mtreg = COUNTS_TARGET * COUNTS_NUMERATOR * MTREG_DEFAULT / (COUNTS_DENOMINATOR * (int) lx);
this->fine_mtreg_ = std::min((int) MTREG_MAX, std::max((int) MTREG_MIN, ideal_mtreg));
}
ESP_LOGV(TAG, "L result: %.1f -> Calculated mode=%d, mtreg=%d", lx, (int) this->fine_mode_, this->fine_mtreg_);
}
void BH1750Sensor::fail_and_reset_() {
this->status_set_warning();
this->publish_state(NAN);
this->state_ = IDLE;
}
float BH1750Sensor::get_setup_priority() const { return setup_priority::DATA; }
} // namespace bh1750
} // namespace esphome
} // namespace esphome::bh1750

View File

@@ -4,10 +4,9 @@
#include "esphome/components/sensor/sensor.h"
#include "esphome/components/i2c/i2c.h"
namespace esphome {
namespace bh1750 {
namespace esphome::bh1750 {
enum BH1750Mode {
enum BH1750Mode : uint8_t {
BH1750_MODE_L,
BH1750_MODE_H,
BH1750_MODE_H2,
@@ -21,13 +20,36 @@ class BH1750Sensor : public sensor::Sensor, public PollingComponent, public i2c:
void setup() override;
void dump_config() override;
void update() override;
void loop() override;
float get_setup_priority() const override;
protected:
void read_lx_(BH1750Mode mode, uint8_t mtreg, const std::function<void(float)> &f);
// State machine states
enum State : uint8_t {
IDLE,
WAITING_COARSE_MEASUREMENT,
READING_COARSE_RESULT,
WAITING_FINE_MEASUREMENT,
READING_FINE_RESULT,
};
// 4-byte aligned members
uint32_t measurement_start_time_{0};
uint32_t measurement_duration_{0};
// 1-byte members grouped together to minimize padding
State state_{IDLE};
BH1750Mode current_mode_{BH1750_MODE_L};
uint8_t current_mtreg_{31};
BH1750Mode fine_mode_{BH1750_MODE_H2};
uint8_t fine_mtreg_{254};
uint8_t active_mtreg_{0};
// Helper methods
bool start_measurement_(BH1750Mode mode, uint8_t mtreg, uint32_t now);
bool read_measurement_(float &lx_out);
void process_coarse_result_(float lx);
void fail_and_reset_();
};
} // namespace bh1750
} // namespace esphome
} // namespace esphome::bh1750

View File

@@ -20,16 +20,6 @@ CONFIG_SCHEMA = (
device_class=DEVICE_CLASS_ILLUMINANCE,
state_class=STATE_CLASS_MEASUREMENT,
)
.extend(
{
cv.Optional("resolution"): cv.invalid(
"The 'resolution' option has been removed. The optimal value is now dynamically calculated."
),
cv.Optional("measurement_duration"): cv.invalid(
"The 'measurement_duration' option has been removed. The optimal value is now dynamically calculated."
),
}
)
.extend(cv.polling_component_schema("60s"))
.extend(i2c.i2c_device_schema(0x23))
)

View File

@@ -23,7 +23,7 @@ void BH1900NUXSensor::setup() {
i2c::ErrorCode result_code =
this->write_register(SOFT_RESET_REG, &SOFT_RESET_PAYLOAD, 1); // Software Reset to check communication
if (result_code != i2c::ERROR_OK) {
this->mark_failed(ESP_LOG_MSG_COMM_FAIL);
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
}

View File

@@ -1,12 +1,11 @@
#include "automation.h"
#include "esphome/core/log.h"
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
static const char *const TAG = "binary_sensor.automation";
void binary_sensor::MultiClickTrigger::on_state_(bool state) {
void MultiClickTrigger::on_state_(bool state) {
// Handle duplicate events
if (state == this->last_state_) {
return;
@@ -67,7 +66,7 @@ void binary_sensor::MultiClickTrigger::on_state_(bool state) {
*this->at_index_ = *this->at_index_ + 1;
}
void binary_sensor::MultiClickTrigger::schedule_cooldown_() {
void MultiClickTrigger::schedule_cooldown_() {
ESP_LOGV(TAG, "Multi Click: Invalid length of press, starting cooldown of %" PRIu32 " ms", this->invalid_cooldown_);
this->is_in_cooldown_ = true;
this->set_timeout("cooldown", this->invalid_cooldown_, [this]() {
@@ -79,7 +78,7 @@ void binary_sensor::MultiClickTrigger::schedule_cooldown_() {
this->cancel_timeout("is_valid");
this->cancel_timeout("is_not_valid");
}
void binary_sensor::MultiClickTrigger::schedule_is_valid_(uint32_t min_length) {
void MultiClickTrigger::schedule_is_valid_(uint32_t min_length) {
if (min_length == 0) {
this->is_valid_ = true;
return;
@@ -90,19 +89,19 @@ void binary_sensor::MultiClickTrigger::schedule_is_valid_(uint32_t min_length) {
this->is_valid_ = true;
});
}
void binary_sensor::MultiClickTrigger::schedule_is_not_valid_(uint32_t max_length) {
void MultiClickTrigger::schedule_is_not_valid_(uint32_t max_length) {
this->set_timeout("is_not_valid", max_length, [this]() {
ESP_LOGV(TAG, "Multi Click: You waited too long to %s.", this->parent_->state ? "RELEASE" : "PRESS");
this->is_valid_ = false;
this->schedule_cooldown_();
});
}
void binary_sensor::MultiClickTrigger::cancel() {
void MultiClickTrigger::cancel() {
ESP_LOGV(TAG, "Multi Click: Sequence explicitly cancelled.");
this->is_valid_ = false;
this->schedule_cooldown_();
}
void binary_sensor::MultiClickTrigger::trigger_() {
void MultiClickTrigger::trigger_() {
ESP_LOGV(TAG, "Multi Click: Hooray, multi click is valid. Triggering!");
this->at_index_.reset();
this->cancel_timeout("trigger");
@@ -118,5 +117,4 @@ bool match_interval(uint32_t min_length, uint32_t max_length, uint32_t length) {
return length >= min_length && length <= max_length;
}
}
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -9,8 +9,7 @@
#include "esphome/core/helpers.h"
#include "esphome/components/binary_sensor/binary_sensor.h"
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
struct MultiClickTriggerEvent {
bool state;
@@ -172,5 +171,4 @@ template<typename... Ts> class BinarySensorInvalidateAction : public Action<Ts..
BinarySensor *sensor_;
};
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -3,9 +3,7 @@
#include "esphome/core/controller_registry.h"
#include "esphome/core/log.h"
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
static const char *const TAG = "binary_sensor";
@@ -36,13 +34,20 @@ void BinarySensor::publish_initial_state(bool new_state) {
void BinarySensor::send_state_internal(bool new_state) {
// copy the new state to the visible property for backwards compatibility, before any callbacks
this->state = new_state;
// Note that set_state_ de-dups and will only trigger callbacks if the state has actually changed
if (this->set_state_(new_state)) {
ESP_LOGD(TAG, "'%s': New state is %s", this->get_name().c_str(), ONOFF(new_state));
// Note that set_new_state_ de-dups and will only trigger callbacks if the state has actually changed
this->set_new_state(new_state);
}
bool BinarySensor::set_new_state(const optional<bool> &new_state) {
if (StatefulEntityBase::set_new_state(new_state)) {
// weirdly, this file could be compiled even without USE_BINARY_SENSOR defined
#if defined(USE_BINARY_SENSOR) && defined(USE_CONTROLLER_REGISTRY)
ControllerRegistry::notify_binary_sensor_update(this);
#endif
ESP_LOGD(TAG, "'%s': %s", this->get_name().c_str(), ONOFFMAYBE(new_state));
return true;
}
return false;
}
void BinarySensor::add_filter(Filter *filter) {
@@ -63,6 +68,4 @@ void BinarySensor::add_filters(std::initializer_list<Filter *> filters) {
}
bool BinarySensor::is_status_binary_sensor() const { return false; }
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -6,9 +6,7 @@
#include <initializer_list>
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
class BinarySensor;
void log_binary_sensor(const char *tag, const char *prefix, const char *type, BinarySensor *obj);
@@ -63,6 +61,8 @@ class BinarySensor : public StatefulEntityBase<bool>, public EntityBase_DeviceCl
protected:
Filter *filter_list_{nullptr};
bool set_new_state(const optional<bool> &new_state) override;
};
class BinarySensorInitiallyOff : public BinarySensor {
@@ -70,5 +70,4 @@ class BinarySensorInitiallyOff : public BinarySensor {
bool has_state() const override { return true; }
};
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -2,9 +2,7 @@
#include "binary_sensor.h"
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
static const char *const TAG = "sensor.filter";
@@ -132,6 +130,4 @@ optional<bool> SettleFilter::new_value(bool value) {
float SettleFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -4,9 +4,7 @@
#include "esphome/core/component.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace binary_sensor {
namespace esphome::binary_sensor {
class BinarySensor;
@@ -139,6 +137,4 @@ class SettleFilter : public Filter, public Component {
bool steady_{true};
};
} // namespace binary_sensor
} // namespace esphome
} // namespace esphome::binary_sensor

View File

@@ -2,12 +2,10 @@
#include "automation.h"
namespace esphome {
namespace ble_client {
namespace esphome::ble_client {
const char *const Automation::TAG = "ble_client.automation";
} // namespace ble_client
} // namespace esphome
} // namespace esphome::ble_client
#endif

View File

@@ -7,10 +7,13 @@
#include "esphome/core/automation.h"
#include "esphome/components/ble_client/ble_client.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace ble_client {
// Maximum bytes to log in hex format for BLE writes (many logging buffers are 256 chars)
static constexpr size_t BLE_WRITE_MAX_LOG_BYTES = 64;
namespace esphome::ble_client {
// placeholder class for static TAG .
class Automation {
@@ -152,7 +155,10 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
esph_log_w(Automation::TAG, "Cannot write to BLE characteristic - not connected");
return false;
}
esph_log_vv(Automation::TAG, "Will write %d bytes: %s", len, format_hex_pretty(data, len).c_str());
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERY_VERBOSE
char hex_buf[format_hex_pretty_size(BLE_WRITE_MAX_LOG_BYTES)];
esph_log_vv(Automation::TAG, "Will write %d bytes: %s", len, format_hex_pretty_to(hex_buf, data, len));
#endif
esp_err_t err =
esp_ble_gattc_write_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->char_handle_, len,
const_cast<uint8_t *>(data), this->write_type_, ESP_GATT_AUTH_REQ_NONE);
@@ -198,7 +204,7 @@ template<typename... Ts> class BLEClientWriteAction : public Action<Ts...>, publ
}
this->node_state = espbt::ClientState::ESTABLISHED;
esph_log_d(Automation::TAG, "Found characteristic %s on device %s", this->char_uuid_.to_string().c_str(),
ble_client_->address_str().c_str());
ble_client_->address_str());
break;
}
default:
@@ -391,7 +397,6 @@ template<typename... Ts> class BLEClientDisconnectAction : public Action<Ts...>,
BLEClient *ble_client_;
std::tuple<Ts...> var_{};
};
} // namespace ble_client
} // namespace esphome
} // namespace esphome::ble_client
#endif

View File

@@ -7,8 +7,7 @@
#ifdef USE_ESP32
namespace esphome {
namespace ble_client {
namespace esphome::ble_client {
static const char *const TAG = "ble_client";
@@ -39,7 +38,7 @@ void BLEClient::set_enabled(bool enabled) {
return;
this->enabled = enabled;
if (!enabled) {
ESP_LOGI(TAG, "[%s] Disabling BLE client.", this->address_str().c_str());
ESP_LOGI(TAG, "[%s] Disabling BLE client.", this->address_str());
this->disconnect();
}
}
@@ -82,7 +81,6 @@ bool BLEClient::all_nodes_established_() {
return true;
}
} // namespace ble_client
} // namespace esphome
} // namespace esphome::ble_client
#endif

View File

@@ -15,8 +15,7 @@
#include <string>
#include <vector>
namespace esphome {
namespace ble_client {
namespace esphome::ble_client {
namespace espbt = esphome::esp32_ble_tracker;
@@ -75,7 +74,6 @@ class BLEClient : public BLEClientBase {
std::vector<BLEClientNode *> nodes_;
};
} // namespace ble_client
} // namespace esphome
} // namespace esphome::ble_client
#endif

View File

@@ -3,8 +3,7 @@
#include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h"
#ifdef USE_ESP32
namespace esphome {
namespace ble_client {
namespace esphome::ble_client {
static const char *const TAG = "ble_binary_output";
@@ -14,7 +13,7 @@ void BLEBinaryOutput::dump_config() {
" MAC address : %s\n"
" Service UUID : %s\n"
" Characteristic UUID: %s",
this->parent_->address_str().c_str(), this->service_uuid_.to_string().c_str(),
this->parent_->address_str(), this->service_uuid_.to_string().c_str(),
this->char_uuid_.to_string().c_str());
LOG_BINARY_OUTPUT(this);
}
@@ -44,7 +43,7 @@ void BLEBinaryOutput::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_i
}
this->node_state = espbt::ClientState::ESTABLISHED;
ESP_LOGD(TAG, "Found characteristic %s on device %s", this->char_uuid_.to_string().c_str(),
this->parent()->address_str().c_str());
this->parent()->address_str());
this->node_state = espbt::ClientState::ESTABLISHED;
break;
}
@@ -75,6 +74,5 @@ void BLEBinaryOutput::write_state(bool state) {
ESP_LOGW(TAG, "[%s] Write error, err=%d", this->char_uuid_.to_string().c_str(), err);
}
} // namespace ble_client
} // namespace esphome
} // namespace esphome::ble_client
#endif

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