Compare commits

..

941 Commits

Author SHA1 Message Date
J. Nick Koston
6c62d4a923 Merge branch 'fix_bytes_encoding' into integration 2025-07-01 22:44:43 -05:00
J. Nick Koston
6e42d009fb Fix bytes field encoding in protobuf code generator 2025-07-01 20:26:34 -05:00
Jonathan Swoboda
04a46de237 [esp32_rmt_led_strip] Reduce memory usage by 32x with IDF 5.3 (#8388) 2025-07-02 11:40:39 +12:00
J. Nick Koston
0083abe3b5 Fix regression: BK7231N devices not returning entities via API (#9283) 2025-07-02 11:30:03 +12:00
J. Nick Koston
7d7769ea5d Merge branch 'component_memory' into integration 2025-07-01 14:11:58 -05:00
J. Nick Koston
3908677fe2 Merge branch 'ota_base_extract' into integration 2025-07-01 14:09:51 -05:00
J. Nick Koston
9799a2b636 test 2025-07-01 13:47:59 -05:00
J. Nick Koston
099474053e cleanuip 2025-07-01 13:38:47 -05:00
J. Nick Koston
efafabed97 fix rp2040 2025-07-01 13:23:24 -05:00
J. Nick Koston
d463dd0f57 Merge branch 'bk7200_tagged_pointer_fix' into integration 2025-07-01 11:57:11 -05:00
J. Nick Koston
c33c14a46f tidy 2025-07-01 11:57:02 -05:00
J. Nick Koston
2d0c109dc1 Merge remote-tracking branch 'origin/dev' into ota_base_extract 2025-07-01 11:50:49 -05:00
J. Nick Koston
825d0bed88 fix esp8266 error handling 2025-07-01 11:29:38 -05:00
Jonathan Swoboda
3470305d9d [esp32] Remove IDF 4 support and clean up code (#9145) 2025-07-01 16:22:41 +00:00
J. Nick Koston
cd1390916c md5 fixes 2025-07-01 11:09:08 -05:00
J. Nick Koston
149bdaf146 fixes 2025-07-01 10:50:17 -05:00
J. Nick Koston
ad628c9cba single ota path 2025-07-01 10:36:36 -05:00
J. Nick Koston
b88f87799e single ota path 2025-07-01 10:30:52 -05:00
J. Nick Koston
1ff7cf1125 single ota path 2025-07-01 10:28:48 -05:00
J. Nick Koston
31db6e51eb single ota path 2025-07-01 10:27:46 -05:00
J. Nick Koston
681d9236f9 single ota path 2025-07-01 10:26:55 -05:00
J. Nick Koston
8aa8af735d single ota path 2025-07-01 10:25:48 -05:00
J. Nick Koston
943d0f103d single ota path 2025-07-01 10:17:28 -05:00
J. Nick Koston
8b195d7f63 use ota backend 2025-07-01 10:11:41 -05:00
J. Nick Koston
649ad47e62 web_server_ support for ota backend idf 2025-07-01 10:05:23 -05:00
J. Nick Koston
93dc5765bb Merge upstream/dev into ota_base_extract 2025-07-01 09:57:09 -05:00
J. Nick Koston
b000b1b70c Fix regression: BK7231N devices not returning entities via API 2025-07-01 09:43:50 -05:00
J. Nick Koston
8707b6e01a lint 2025-07-01 07:31:45 -05:00
Javier Peletier
35de36d690 [modbus] Modbus server role: write holding registers (#9156) 2025-07-01 15:39:06 +12:00
J. Nick Koston
16ef5a9377 Add OTA support to ESP-IDF webserver (#9264) 2025-07-01 15:21:11 +12:00
J. Nick Koston
e3ccb9b46c Use interrupt based approach for esp32_touch (#9059)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2025-07-01 15:04:50 +12:00
Javier Peletier
8c34b72b62 Jinja expressions in configs (Take #3) (#8955) 2025-07-01 14:57:00 +12:00
Jesse Hills
27c745d5a1 [host] Disable platformio ldf (#9277) 2025-07-01 14:38:39 +12:00
J. Nick Koston
9a0ba1657e Fix entity hash collisions by enforcing unique names across devices per platform (#9276) 2025-07-01 14:38:19 +12:00
J. Nick Koston
34abd67f3e Merge branch 'component_memory' into integration 2025-06-30 21:21:07 -05:00
J. Nick Koston
45f1db9233 address review comments 2025-06-30 21:20:58 -05:00
J. Nick Koston
beb4d1511a Merge branch 'component_memory' into integration 2025-06-30 21:18:06 -05:00
J. Nick Koston
adeceee71f Reduce Component memory usage by 40% (8 bytes per component) 2025-06-30 21:15:20 -05:00
J. Nick Koston
7d4b11d112 Reduce Component memory usage by 40% (8 bytes per component) 2025-06-30 21:11:49 -05:00
J. Nick Koston
6733cd4ed1 Merge branch 'entity_name_must_be_unique' into integration 2025-06-30 18:31:40 -05:00
J. Nick Koston
07f361a404 empty name uses device name, use get_base_entity_object_id 2025-06-30 18:26:09 -05:00
J. Nick Koston
ae981ea7f2 Merge branch 'entity_name_must_be_unique' into integration 2025-06-30 17:48:49 -05:00
J. Nick Koston
b7d0f5e36b Fix entity hash collisions by enforcing unique names across devices per platform 2025-06-30 17:38:04 -05:00
Mathieu Rene
db7a420e54 Fix - Pass thread TLVs down to openthread if they are defined (#9182)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-01 10:07:30 +12:00
Jonathan Swoboda
e58baab563 [ethernet] P4 changes and 5.3.0 deprecated warnings (#8457)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-01 10:06:59 +12:00
piechade
08c88ba0f2 [smt100] Rename `dielectric_constant to permittivity` (#9175)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-30 20:54:23 +00:00
Jesse Hills
78c8cd4c4e [http_request.update] Fix `size_t` printing (#9144) 2025-06-30 15:50:19 -05:00
Jesse Hills
98e106e0ae [pins] Update `internal_gpio_pin_number to work directly like internal_gpio_output_pin_number` (#9270) 2025-07-01 08:09:11 +12:00
J. Nick Koston
0cbb5e6c1c Fix flaky test_api_conditional_memory by waiting for all required states (#9271) 2025-07-01 08:02:43 +12:00
J. Nick Koston
3cbce4df42 Merge branch 'esp32_touch_isr' into integration 2025-06-30 14:38:54 -05:00
J. Nick Koston
7e77e40bda cleanup 2025-06-30 14:37:30 -05:00
J. Nick Koston
305805256d dry 2025-06-30 14:34:07 -05:00
J. Nick Koston
e36c669dc0 dry 2025-06-30 14:32:13 -05:00
J. Nick Koston
71aff9bc60 dry 2025-06-30 14:30:07 -05:00
J. Nick Koston
36d11c969f dry 2025-06-30 14:29:57 -05:00
J. Nick Koston
f76ce5d3bb dry 2025-06-30 14:28:31 -05:00
J. Nick Koston
0df454481e safer 2025-06-30 14:15:26 -05:00
J. Nick Koston
83c1a30cfb Merge branch 'esp32_touch_isr' into integration 2025-06-30 13:46:54 -05:00
J. Nick Koston
6cbd1479c6 loop 2025-06-30 13:46:47 -05:00
J. Nick Koston
3e6e438920 Merge remote-tracking branch 'upstream/dev' into esp32_touch_isr 2025-06-30 13:43:18 -05:00
J. Nick Koston
560886eb90 clenaup 2025-06-30 13:32:59 -05:00
J. Nick Koston
340bb5cef6 clenaup 2025-06-30 13:31:55 -05:00
David Woodhouse
8014cbc71e Fixes for async MQTT (#9273) 2025-06-30 13:25:54 -05:00
J. Nick Koston
44a7c1d4a5 cleanup 2025-06-30 13:14:55 -05:00
J. Nick Koston
519c49f175 Revert "fix"
This reverts commit c96ffefa42.
2025-06-30 13:11:27 -05:00
J. Nick Koston
c96ffefa42 fix 2025-06-30 13:02:26 -05:00
J. Nick Koston
490ca8ad5a relo 2025-06-30 12:53:41 -05:00
J. Nick Koston
e385f87d6c move more 2025-06-30 12:46:47 -05:00
J. Nick Koston
58de53123a move more 2025-06-30 12:41:55 -05:00
J. Nick Koston
4f365c1716 todo 2025-06-30 12:11:37 -05:00
J. Nick Koston
981177da23 todo 2025-06-30 12:09:07 -05:00
J. Nick Koston
088bea9ccd split 2025-06-30 10:50:26 -05:00
J. Nick Koston
36350f179e split 2025-06-30 10:49:59 -05:00
J. Nick Koston
902f08c1bc Extract OTA backend functionality into separate ota_base component 2025-06-30 10:38:31 -05:00
J. Nick Koston
47ad206ccd Extract OTA backend functionality into separate ota_base component 2025-06-30 10:35:19 -05:00
J. Nick Koston
9f51546023 Extract OTA backend functionality into separate ota_base component 2025-06-30 10:33:43 -05:00
J. Nick Koston
f6d679f056 Merge branch 'idf_webserver_ota' into integration 2025-06-30 10:04:39 -05:00
J. Nick Koston
93c45e88e7 revert ota backend changes 2025-06-30 10:04:23 -05:00
J. Nick Koston
da189da9ae Merge branch 'idf_webserver_ota' into integration 2025-06-30 09:56:30 -05:00
J. Nick Koston
c40a33cb48 revert ota backend changes 2025-06-30 09:56:20 -05:00
J. Nick Koston
9846beee7d revert ota backend changes 2025-06-30 09:55:02 -05:00
J. Nick Koston
81685f9132 Merge branch 'idf_webserver_ota' into integration 2025-06-30 09:50:56 -05:00
J. Nick Koston
14123d25c2 fixes 2025-06-30 09:50:46 -05:00
J. Nick Koston
928819ffbd fixes 2025-06-30 09:49:59 -05:00
J. Nick Koston
7f2f9636f5 make sure ota still works without ota loaded 2025-06-30 09:46:33 -05:00
J. Nick Koston
b49fe146ad make sure ota still works without ota loaded 2025-06-30 09:44:20 -05:00
J. Nick Koston
98bbd4136b Merge branch 'idf_webserver_ota' into integration 2025-06-30 09:24:05 -05:00
J. Nick Koston
d8d02f71ba cleanup 2025-06-30 09:23:57 -05:00
J. Nick Koston
26980df2b9 Merge branch 'idf_webserver_ota' into integration 2025-06-30 08:25:08 -05:00
J. Nick Koston
ffe39473d0 fixes 2025-06-30 08:18:34 -05:00
J. Nick Koston
6af8d152ee fixes 2025-06-30 08:18:18 -05:00
J. Nick Koston
de846a8f7a Merge branch 'idf_webserver_ota' into integration 2025-06-30 07:54:26 -05:00
J. Nick Koston
8e31316e3d Merge remote-tracking branch 'upstream/dev' into idf_webserver_ota 2025-06-30 07:51:22 -05:00
J. Nick Koston
fb6edb3243 fixes 2025-06-30 07:51:11 -05:00
J. Nick Koston
244bd9256f tidy 2025-06-30 06:55:08 -05:00
J. Nick Koston
aaa7117ec9 Update libsodium to 1.0.20 (#9240)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-30 20:47:04 +12:00
J. Nick Koston
1f61fd383c Merge branch 'dev' into esp32_touch_isr 2025-06-30 01:06:49 -05:00
Keith Burzinski
3930609d8b [ld2420] Move consts to cpp file, optimize memory use (#9216) 2025-06-30 01:05:59 -05:00
J. Nick Koston
ce294ce0c1 Merge branch 'idf_webserver_ota' into integration 2025-06-30 01:01:29 -05:00
J. Nick Koston
dcbdc0ac51 Merge branch 'dev' into esp32_touch_isr 2025-06-30 00:59:07 -05:00
J. Nick Koston
daea06586d Merge branch 'update_libsodium' into integration 2025-06-30 00:54:49 -05:00
J. Nick Koston
9c8bf2587b Merge remote-tracking branch 'origin/update_libsodium' into update_libsodium 2025-06-30 00:50:31 -05:00
J. Nick Koston
9871cb04ea 0.1.10 2025-06-30 00:50:18 -05:00
Gábor Poczkodi
3e553f517b [remote_base] Fix dumper base class and enable schema extension (#9218) 2025-06-30 17:12:44 +12:00
Keith Burzinski
af0bb634c6 [light] Fix transitions with `lerp` (#9269) 2025-06-30 05:05:52 +00:00
Bjørn Mork
8a9769d4e9 Support DM9051 SPI ethernet device (#6861)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-30 16:49:38 +12:00
J. Nick Koston
7dc093815f reduce 2025-06-29 23:40:09 -05:00
J. Nick Koston
087697106c remove debug 2025-06-29 23:32:59 -05:00
J. Nick Koston
9beebc7bfe Merge branch 'dev' into idf_webserver_ota 2025-06-29 23:22:34 -05:00
lamauny
d86f319d66 Add support for LN882X Family (with LibreTiny) (#8954)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-30 16:20:36 +12:00
J. Nick Koston
4a948b7aae Merge branch 'dev' into update_libsodium 2025-06-29 23:20:30 -05:00
J. Nick Koston
0d3bc21e97 Merge branch 'dev' from upstream
Resolved conflicts in:
- esphome/components/api/list_entities.h
- esphome/components/api/subscribe_state.h

Both conflicts were about NOLINT comment style - chose upstream's inline comment format.
2025-06-29 23:18:41 -05:00
J. Nick Koston
7496894ae6 0.1.9 2025-06-29 23:16:20 -05:00
J. Nick Koston
918d7217a9 fix 2025-06-29 23:15:28 -05:00
J. Nick Koston
2103d583f9 bump to 0.1.8 2025-06-29 23:12:48 -05:00
J. Nick Koston
9890659f61 Optimize web_server UrlMatch to avoid heap allocations (#9263) 2025-06-30 04:12:03 +00:00
J. Nick Koston
837c446926 Merge branch 'dev' from upstream 2025-06-29 23:10:20 -05:00
J. Nick Koston
480ea54ee0 Merge branch 'dev' into update_libsodium 2025-06-29 22:49:46 -05:00
J. Nick Koston
97e7c34cb6 Merge branch 'dev' into idf_webserver_ota 2025-06-29 22:41:30 -05:00
J. Nick Koston
140ca070a2 Optimize scheduler string storage to eliminate heap allocations (#9251)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-30 15:40:36 +12:00
J. Nick Koston
fe65b149f5 tweak 2025-06-29 22:34:42 -05:00
J. Nick Koston
6a354d7c94 Reduce API component memory usage with conditional compilation (#9262) 2025-06-30 15:33:35 +12:00
J. Nick Koston
4106b97174 tweak 2025-06-29 22:31:47 -05:00
J. Nick Koston
8648954b94 tweak 2025-06-29 22:29:40 -05:00
J. Nick Koston
9f1fae0955 tweak 2025-06-29 22:27:36 -05:00
Jesse Hills
1d631c3c6d Update platformio.ini 2025-06-30 15:26:14 +12:00
J. Nick Koston
727161f1db tweak 2025-06-29 22:24:28 -05:00
Jesse Hills
bf5f628769 Update esphome/components/api/__init__.py 2025-06-30 15:23:40 +12:00
J. Nick Koston
8563a5785f tweak 2025-06-29 22:19:29 -05:00
J. Nick Koston
4082634e6d tweak 2025-06-29 22:14:15 -05:00
J. Nick Koston
a74adb5865 tweak 2025-06-29 22:13:56 -05:00
J. Nick Koston
2e4d7301f2 tweak 2025-06-29 22:12:36 -05:00
J. Nick Koston
94845222ad tweak 2025-06-29 22:12:20 -05:00
J. Nick Koston
7f6ac2deee tweak 2025-06-29 22:10:50 -05:00
J. Nick Koston
a054aa9c52 clean 2025-06-29 21:57:50 -05:00
J. Nick Koston
22cb59b88c clean 2025-06-29 21:55:13 -05:00
J. Nick Koston
6968772a31 preen 2025-06-29 21:48:35 -05:00
J. Nick Koston
004f4b51d1 preen 2025-06-29 21:41:57 -05:00
J. Nick Koston
8c8dd7b4bc preen 2025-06-29 21:40:20 -05:00
J. Nick Koston
9778289d33 revert 2025-06-29 21:36:25 -05:00
J. Nick Koston
a43caf08a6 cleanup 2025-06-29 21:31:54 -05:00
J. Nick Koston
01e550fac9 cleanup 2025-06-29 21:13:05 -05:00
J. Nick Koston
ad4dd6a060 cleanup 2025-06-29 21:07:39 -05:00
J. Nick Koston
849d99b0dc cleanup 2025-06-29 21:06:04 -05:00
J. Nick Koston
f5df5f71a3 cleanup 2025-06-29 21:04:45 -05:00
J. Nick Koston
429be0a5ae cleanup 2025-06-29 21:03:13 -05:00
J. Nick Koston
148e4ec555 cleanup 2025-06-29 20:59:51 -05:00
J. Nick Koston
bb22f4d6a3 cleanup 2025-06-29 20:54:36 -05:00
J. Nick Koston
f94703360b cleanup 2025-06-29 20:54:13 -05:00
J. Nick Koston
f26bec1a5a preen 2025-06-29 20:18:32 -05:00
J. Nick Koston
d065f4ae62 cleanup 2025-06-29 20:15:18 -05:00
J. Nick Koston
ed2c3e626b cleanup 2025-06-29 19:53:29 -05:00
J. Nick Koston
1927f92358 cleanup 2025-06-29 19:49:01 -05:00
J. Nick Koston
939144174c cleanup 2025-06-29 19:32:43 -05:00
J. Nick Koston
59bcbe7fef proper state machine 2025-06-29 19:31:01 -05:00
J. Nick Koston
8e00fedc67 rwatchdog 2025-06-29 19:24:40 -05:00
J. Nick Koston
0ac879ae0b remove 2025-06-29 19:22:13 -05:00
J. Nick Koston
22d1a18d22 Merge remote-tracking branch 'upstream/dev' into idf_webserver_ota 2025-06-29 19:19:32 -05:00
J. Nick Koston
7f8dd4b254 Fix thread-safe cleanup of event source connections in ESP-IDF web server (#9268) 2025-06-29 19:19:18 -05:00
J. Nick Koston
ca203bff9b cleanup 2025-06-29 19:18:33 -05:00
J. Nick Koston
e01d16ce82 cleanup 2025-06-29 19:07:47 -05:00
J. Nick Koston
93b6b9835c cleanup 2025-06-29 19:04:54 -05:00
J. Nick Koston
d0ac5388d9 cleanup 2025-06-29 19:03:54 -05:00
J. Nick Koston
9097d646ca cleanup 2025-06-29 19:03:48 -05:00
J. Nick Koston
596a28e1fb cleanup 2025-06-29 19:00:07 -05:00
J. Nick Koston
5205ff5c43 cleanup 2025-06-29 18:59:09 -05:00
J. Nick Koston
c420bf5f4f cleanup 2025-06-29 18:55:46 -05:00
J. Nick Koston
18844e15dc cleanup 2025-06-29 18:54:48 -05:00
J. Nick Koston
af2f5b7348 cleanup 2025-06-29 18:54:14 -05:00
J. Nick Koston
bcbf0f0e26 cleanup 2025-06-29 18:53:43 -05:00
J. Nick Koston
4d460d4bc3 cleanup 2025-06-29 18:51:35 -05:00
J. Nick Koston
0b1b8f05e1 Reduce loop enable/disable log spam by using very verbose level (#9267) 2025-06-30 11:49:31 +12:00
J. Nick Koston
92f6f3ac0d cleanup 2025-06-29 18:48:30 -05:00
Jesse Hills
53e9ffe656 [pi4ioe5v6408] Add new IO Expander (#8888)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2025-06-30 11:48:19 +12:00
J. Nick Koston
2289073a1e Add interrupt support to GPIO binary sensors (#9115)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-30 11:47:50 +12:00
J. Nick Koston
687cb1cd2b Reduce web_server RAM usage by 96 bytes with conditional sorting compilation (#9227) 2025-06-30 11:47:20 +12:00
J. Nick Koston
bc63d246c8 cleanup 2025-06-29 18:46:15 -05:00
J. Nick Koston
e907050a17 Remove unused return value from read_message and fix ifdef placement in generated API code (#9256) 2025-06-30 11:45:03 +12:00
J. Nick Koston
b25f272d72 lint 2025-06-29 18:44:14 -05:00
J. Nick Koston
e3a3305adb delete 2025-06-29 18:44:02 -05:00
J. Nick Koston
a4b57c7e44 Reduce flash usage by making add_message_object non-template (#9258) 2025-06-30 11:43:47 +12:00
J. Nick Koston
24bbfcdce7 Reduce API memory footprint through bitfield consolidation and type sizing (#9252) 2025-06-30 11:42:57 +12:00
J. Nick Koston
c655c4e106 remove cruft 2025-06-29 18:39:17 -05:00
J. Nick Koston
d78b720350 Remove single-use send_*_info wrappers in API connection (#9255) 2025-06-30 11:38:11 +12:00
J. Nick Koston
7fe8cdaa34 remove cruft 2025-06-29 18:37:48 -05:00
J. Nick Koston
df97985048 Merge remote-tracking branch 'origin/integration' into integration 2025-06-29 18:33:46 -05:00
J. Nick Koston
3779675816 Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-29 18:33:34 -05:00
J. Nick Koston
0005aad5b5 cleanup 2025-06-29 18:30:00 -05:00
J. Nick Koston
98c18517e2 Merge branch 'another_webserver_crash' into idf_webserver_ota 2025-06-29 18:23:25 -05:00
J. Nick Koston
e4dee935ce Fix thread-safe cleanup of event source connections in ESP-IDF web server 2025-06-29 18:21:24 -05:00
J. Nick Koston
f8cb44fb3c fixes 2025-06-29 17:54:11 -05:00
J. Nick Koston
d592208c74 Fix crash when event last_event_type is null in web_server (#9266) 2025-06-29 22:45:41 +00:00
J. Nick Koston
101901fdb8 Merge remote-tracking branch 'upstream/loop_enable_disable_log_spam' into idf_webserver_ota 2025-06-29 17:41:04 -05:00
J. Nick Koston
b8579d2040 Reduce loop enable/disable log spam by using very verbose level 2025-06-29 17:39:48 -05:00
J. Nick Koston
3fca3df756 working 2025-06-29 17:22:33 -05:00
J. Nick Koston
2f5db85997 Merge remote-tracking branch 'upstream/last_Event_fix' into idf_webserver_ota 2025-06-29 16:54:00 -05:00
Jesse Hills
e0d4361875 Update esphome/components/gpio/binary_sensor/__init__.py 2025-06-30 09:53:54 +12:00
J. Nick Koston
30bafc43bd make bot happy 2025-06-29 16:52:55 -05:00
J. Nick Koston
3530437b48 Merge branch 'last_Event_fix' into idf_webserver_ota 2025-06-29 16:19:20 -05:00
J. Nick Koston
81db42942c Fix crash when event last_event_type is null in web_server 2025-06-29 16:16:53 -05:00
J. Nick Koston
6cb0d9e0b5 fixes 2025-06-29 16:11:33 -05:00
J. Nick Koston
19f7e36753 fixes 2025-06-29 16:10:58 -05:00
J. Nick Koston
a963f97520 fixes 2025-06-29 16:07:26 -05:00
J. Nick Koston
ad2d48e9b7 fixes 2025-06-29 16:03:05 -05:00
J. Nick Koston
5c0d67ca14 fixes 2025-06-29 15:50:12 -05:00
J. Nick Koston
3467329a7c cleanup 2025-06-29 15:43:41 -05:00
J. Nick Koston
d73fa370f3 cleanup 2025-06-29 15:35:59 -05:00
David Woodhouse
971bbd088c Fix MQTT blocking main loop for multiple seconds at a time (#8325)
Co-authored-by: patagona <patagonahn@gmail.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-06-30 08:34:59 +12:00
J. Nick Koston
78fd0a4870 cleanup 2025-06-29 15:23:32 -05:00
J. Nick Koston
3162bb475d cleanup 2025-06-29 15:08:27 -05:00
Jesse Hills
b743577ebe Fix api log client crashing when api encryption is dynamic (#9245) 2025-06-30 08:07:29 +12:00
J. Nick Koston
c17503abd5 cleanup 2025-06-29 15:03:48 -05:00
J. Nick Koston
3433ee8171 cleanup 2025-06-29 14:59:41 -05:00
J. Nick Koston
344297b0a7 cleanup 2025-06-29 14:51:24 -05:00
J. Nick Koston
947456628e cleanup 2025-06-29 14:51:01 -05:00
J. Nick Koston
80dd6c111d cleanup 2025-06-29 14:44:47 -05:00
J. Nick Koston
b70188ba4b cleanup 2025-06-29 14:40:13 -05:00
J. Nick Koston
c6064aa2b4 Merge remote-tracking branch 'upstream/dev' into idf_webserver_ota 2025-06-29 14:35:44 -05:00
J. Nick Koston
6596f864be merg3 2025-06-29 14:35:38 -05:00
dependabot[bot]
a4cc6166a0 Bump aioesphomeapi from 33.1.1 to 34.0.0 (#9265)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-06-29 14:20:52 -05:00
J. Nick Koston
ed9850c4a4 Remove redundant get_setup_priority() overrides returning default value (#9253) 2025-06-29 13:46:28 -05:00
J. Nick Koston
ddbcf8549c Reduce web_server code duplication by extracting detail parameter parsing (#9257) 2025-06-29 13:29:18 -05:00
J. Nick Koston
f61a40efb8 fixes 2025-06-29 11:16:00 -05:00
J. Nick Koston
b049f0b480 fixes 2025-06-29 11:13:25 -05:00
J. Nick Koston
b2641d29c1 fixes 2025-06-29 11:12:40 -05:00
J. Nick Koston
7b8cfc768d fixes 2025-06-29 11:11:47 -05:00
J. Nick Koston
04860567f7 fixes 2025-06-29 11:10:29 -05:00
J. Nick Koston
b16edb5a99 fixes 2025-06-29 11:09:05 -05:00
J. Nick Koston
15a995b2e7 fixes 2025-06-29 11:07:48 -05:00
J. Nick Koston
f57e26c54e fixes 2025-06-29 11:07:25 -05:00
J. Nick Koston
2b7bc1cd9f fixes 2025-06-29 11:03:37 -05:00
J. Nick Koston
614a2f66a3 fixes 2025-06-29 10:57:00 -05:00
J. Nick Koston
9047b02c92 fixes 2025-06-29 10:53:29 -05:00
J. Nick Koston
e73d0477bb Merge branch 'api_conditional_memory' into integration 2025-06-29 10:42:24 -05:00
J. Nick Koston
2b1e623eb4 defines 2025-06-29 10:42:11 -05:00
J. Nick Koston
c366d555e9 Add OTA support to ESP-IDF webserver 2025-06-29 10:38:53 -05:00
J. Nick Koston
7efbd62730 Add OTA support to ESP-IDF webserver 2025-06-29 10:34:49 -05:00
J. Nick Koston
b77c1d0af8 Add OTA support to ESP-IDF webserver 2025-06-29 10:33:49 -05:00
J. Nick Koston
f8810ea6a8 Merge branch 'webserver_eliminate_heap_url_match' into integration 2025-06-29 10:26:55 -05:00
J. Nick Koston
40dd667211 fixes 2025-06-29 10:26:39 -05:00
J. Nick Koston
848b572864 Merge branch 'webserver_eliminate_heap_url_match' into integration 2025-06-29 10:17:49 -05:00
J. Nick Koston
7c858fbccd Optimize web_server UrlMatch to avoid heap allocations 2025-06-29 10:15:06 -05:00
Rezoran
921d0888cd [uart] fix: missing uart_config_t struct initialisation (#9235) 2025-06-29 15:05:23 +00:00
J. Nick Koston
a1814ea37d Merge branch 'useless_default_data' into integration 2025-06-29 09:22:57 -05:00
J. Nick Koston
5892a1dbe2 tests 2025-06-29 08:40:26 -05:00
J. Nick Koston
29f524f432 tests 2025-06-29 08:37:53 -05:00
J. Nick Koston
4ec588ebd7 Merge remote-tracking branch 'origin/integration' into integration 2025-06-29 08:20:36 -05:00
J. Nick Koston
efdef61477 Merge branch 'api_reduce' into integration 2025-06-29 08:20:22 -05:00
J. Nick Koston
fe2b9f8c12 correct fix 2025-06-29 08:20:12 -05:00
J. Nick Koston
c6be55eb55 Merge branch 'api_conditional_memory' into integration 2025-06-29 08:14:25 -05:00
J. Nick Koston
4c69925b84 lint 2025-06-29 08:13:28 -05:00
J. Nick Koston
bc6407df0a Merge branch 'bitpack_api' into integration 2025-06-29 08:09:52 -05:00
J. Nick Koston
01982a8d0a reduce upper bound of batch delay as it did not make sense 2025-06-29 07:59:59 -05:00
J. Nick Koston
b995cd6257 Merge remote-tracking branch 'origin/integration' into integration 2025-06-29 07:47:28 -05:00
J. Nick Koston
b16d7b7a95 Merge branch 'api_conditional_memory' into integration 2025-06-29 07:47:17 -05:00
J. Nick Koston
42aea701d3 Reduce API component memory usage with conditional compilation 2025-06-29 07:45:48 -05:00
J. Nick Koston
5f56c85182 Merge remote-tracking branch 'origin/integration' into integration 2025-06-29 07:42:05 -05:00
J. Nick Koston
52b4eb8950 Merge branch 'api_reduce' into integration 2025-06-29 07:41:00 -05:00
J. Nick Koston
eeb2b42a0f fixes 2025-06-29 07:39:07 -05:00
Keith Burzinski
21e1f3d103 [light] Memory optimizations (#9260) 2025-06-29 11:28:51 +00:00
Keith Burzinski
53ab016098 [adc] Memory optimizations (#9247) 2025-06-29 06:17:53 -05:00
Keith Burzinski
0c249a7006 [thermostat] Memory optimizations (#9259) 2025-06-29 06:16:34 -05:00
J. Nick Koston
90772033d1 revert bad feedback 2025-06-29 06:10:55 -05:00
J. Nick Koston
dadeb4d2a9 Merge branch 'api_reduce' into integration 2025-06-28 23:24:40 -05:00
J. Nick Koston
60a5029c88 lint 2025-06-28 23:24:30 -05:00
J. Nick Koston
d7ba16b48b Merge branch 'api_reduce' into integration 2025-06-28 23:06:51 -05:00
J. Nick Koston
fca9befa63 cleanup 2025-06-28 23:06:40 -05:00
J. Nick Koston
187cbde0db cleanup 2025-06-28 23:06:34 -05:00
J. Nick Koston
f5ae5cade8 cleanup 2025-06-28 23:06:09 -05:00
J. Nick Koston
3e66c28aff Merge branch 'api_reduce' into integration 2025-06-28 23:05:15 -05:00
J. Nick Koston
89703a1aef cleanup 2025-06-28 23:05:02 -05:00
J. Nick Koston
cba31617e9 Merge branch 'api_reduce' into integration 2025-06-28 23:02:05 -05:00
J. Nick Koston
a3eeb46961 reduce 2025-06-28 23:01:48 -05:00
J. Nick Koston
128bd76f20 reduce 2025-06-28 22:45:00 -05:00
J. Nick Koston
c0355fd2c6 Merge branch 'webserver_helper_reduce_flash' into integration 2025-06-28 22:09:03 -05:00
J. Nick Koston
a5fd440e25 cleanup 2025-06-28 22:08:47 -05:00
J. Nick Koston
592ef8be2a Merge remote-tracking branch 'origin/integration' into integration 2025-06-28 22:04:41 -05:00
J. Nick Koston
3bcc1c7297 Merge branch 'add_message_object' into integration 2025-06-28 22:04:27 -05:00
J. Nick Koston
3b44c3acd1 Reduce flash usage by making add_message_object non-template 2025-06-28 22:03:04 -05:00
J. Nick Koston
ec4911643a Merge remote-tracking branch 'upstream/integration' into integration 2025-06-28 21:40:44 -05:00
J. Nick Koston
f4fedbab44 Merge branch 'webserver_helper_reduce_flash' into integration 2025-06-28 21:40:26 -05:00
J. Nick Koston
553d441ecc Reduce web_server code duplication by extracting detail parameter parsing 2025-06-28 21:38:40 -05:00
J. Nick Koston
1946116438 Merge branch 'api_read_message' into integration 2025-06-28 21:22:25 -05:00
J. Nick Koston
ab28515fba fix 2025-06-28 21:17:59 -05:00
J. Nick Koston
4dc11fb95e Merge branch 'api_read_message' into integration 2025-06-28 21:11:16 -05:00
J. Nick Koston
e27094e0f3 Remove unused return value from read_message and fix ifdef placement in generated API code 2025-06-28 21:09:33 -05:00
J. Nick Koston
88302201eb Merge remote-tracking branch 'origin/integration' into integration 2025-06-28 20:56:24 -05:00
J. Nick Koston
8afb172e83 Merge branch 'api_reduce' into integration 2025-06-28 20:56:00 -05:00
J. Nick Koston
562d024623 Remove single-use send_*_info wrappers in API connection 2025-06-28 20:49:09 -05:00
J. Nick Koston
50b094547c Remove single-use send_*_info wrappers in API connection 2025-06-28 20:47:57 -05:00
J. Nick Koston
a6c1e50985 Remove single-use send_*_info wrappers in API connection 2025-06-28 20:46:17 -05:00
J. Nick Koston
96772bdfc6 Merge remote-tracking branch 'origin/integration' into integration 2025-06-28 20:13:13 -05:00
J. Nick Koston
ed154d373c Merge remote-tracking branch 'origin/dev' into integration 2025-06-28 20:12:59 -05:00
J. Nick Koston
a5e862ce36 Remove redundant get_setup_priority() overrides returning default value 2025-06-28 17:21:20 -05:00
J. Nick Koston
ae55964bd9 Merge remote-tracking branch 'origin/bitpack_api' into integration 2025-06-28 16:47:43 -05:00
J. Nick Koston
c162309f41 Pack APIConnection members to reduce memory footprint 2025-06-28 16:46:17 -05:00
J. Nick Koston
62c667f1a0 Merge remote-tracking branch 'origin/dev' into integration 2025-06-28 16:11:15 -05:00
J. Nick Koston
86c0fb48a3 Replace ping retry timer with batch queue fallback (#9207) 2025-06-29 09:08:30 +12:00
J. Nick Koston
3d08eae8e4 Merge branch 'scheduler_copy' into integration 2025-06-28 15:52:09 -05:00
J. Nick Koston
2af5a0a6dd Merge remote-tracking branch 'origin/scheduler_copy' into scheduler_copy 2025-06-28 15:52:03 -05:00
J. Nick Koston
6d24b04235 cover 2025-06-28 15:51:50 -05:00
J. Nick Koston
3ee8103353 Merge branch 'scheduler_copy' into integration 2025-06-28 15:49:33 -05:00
J. Nick Koston
1296165fce Merge branch 'dev' into scheduler_copy 2025-06-28 15:48:11 -05:00
J. Nick Koston
7100c22dc4 address copilot comments 2025-06-28 15:47:24 -05:00
J. Nick Koston
3f1f99cf37 Extract lock-free queue and event pool to core helpers (#9238) 2025-06-29 08:08:33 +12:00
J. Nick Koston
13d4823db6 Fix buffer corruption in API message encoding with very verbose logging (#9249) 2025-06-29 08:04:42 +12:00
Jimmy Hedman
30f61b26ff Remove backports of std (#9246) 2025-06-29 07:56:12 +12:00
J. Nick Koston
5718c0f5b8 Update test_scheduler_string_test.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-28 11:25:42 -05:00
J. Nick Koston
25ebddfa1c Update test_scheduler_string_test.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-28 11:25:36 -05:00
J. Nick Koston
2c0558fe23 Update test_scheduler_string_test.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-28 11:25:30 -05:00
J. Nick Koston
7192108fc1 Merge branch 'scheduler_copy' into integration 2025-06-28 10:32:21 -05:00
J. Nick Koston
847696c342 safer 2025-06-28 10:32:10 -05:00
J. Nick Koston
912ae1fc87 Merge remote-tracking branch 'origin/integration' into integration 2025-06-28 10:28:35 -05:00
J. Nick Koston
a86f75d31d Merge branch 'scheduler_copy' into integration 2025-06-28 10:28:22 -05:00
J. Nick Koston
fe1e25b5c7 Merge remote-tracking branch 'upstream/integration' into integration 2025-06-28 10:22:18 -05:00
J. Nick Koston
9b241b596a Merge branch 'scheduler_copy' into integration 2025-06-28 10:22:07 -05:00
J. Nick Koston
53b9c8d5bb cleanup 2025-06-28 10:15:05 -05:00
J. Nick Koston
2946bc9d72 cover 2025-06-28 10:10:43 -05:00
J. Nick Koston
67a20e212d safe 2025-06-28 09:59:50 -05:00
J. Nick Koston
a9ace366eb dry 2025-06-28 09:50:27 -05:00
J. Nick Koston
df3469efba dry 2025-06-28 09:48:58 -05:00
J. Nick Koston
0a3bbb8554 dry 2025-06-28 09:48:26 -05:00
J. Nick Koston
a15b9f5d3b dry 2025-06-28 09:45:59 -05:00
J. Nick Koston
e6334b0716 dry 2025-06-28 09:41:12 -05:00
J. Nick Koston
7a835baa5a Merge remote-tracking branch 'upstream/dev' into scheduler_copy 2025-06-28 09:36:32 -05:00
J. Nick Koston
c9c21a5728 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-28 09:36:07 -05:00
J. Nick Koston
956959fc32 safety 2025-06-28 09:23:16 -05:00
J. Nick Koston
6f67f74638 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-28 08:43:19 -05:00
dependabot[bot]
58b7d0b412 Bump ruff from 0.12.0 to 0.12.1 (#9241)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-06-28 10:21:53 +00:00
Jonathan Swoboda
d37f5b87bd [esp32] Allow 5.4.2 (#9243) 2025-06-28 01:30:59 -05:00
J. Nick Koston
3f65cee17c Silence protobuf compatibility warnings when importing aioesphomeapi (#9236) 2025-06-28 16:59:52 +12:00
J. Nick Koston
094bf19ec4 Disable dynamic log level control for ESP32 ESP-IDF builds (#9233) 2025-06-28 16:58:53 +12:00
J. Nick Koston
f8d59b5aeb Reduce libretiny logconfig messages (#9239) 2025-06-28 15:53:40 +12:00
Jesse Hills
e9870c2922 Merge branch 'release' into dev 2025-06-28 15:48:11 +12:00
Jesse Hills
50b7349fe0 Merge pull request #9234 from esphome/bump-2025.6.2
2025.6.2
2025-06-28 15:47:02 +12:00
Jonathan Swoboda
61b3379f48 [i2c] Disable i2c scan on certain idf versions (#9237) 2025-06-28 13:33:05 +12:00
Samuel Sieb
5010a0f5e7 [mcp23xxx_base] fix pin interrupts (#9244)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2025-06-28 13:32:57 +12:00
Jonathan Swoboda
52ca8deb10 [i2c] Disable i2c scan on certain idf versions (#9237) 2025-06-28 13:32:18 +12:00
Samuel Sieb
156a9160ba [mcp23xxx_base] fix pin interrupts (#9244)
Co-authored-by: Samuel Sieb <samuel@sieb.net>
2025-06-28 13:31:23 +12:00
J. Nick Koston
b3dd4543b7 Merge branch 'update_libsodium' into integration 2025-06-27 17:10:52 -05:00
J. Nick Koston
4f17a28ac5 Merge branch 'extract_helpers' into integration 2025-06-27 17:10:17 -05:00
J. Nick Koston
90736f367a release 2025-06-27 16:36:32 -05:00
J. Nick Koston
9af88bd482 DNM: Update libsodium
needs https://github.com/esphome/noise-c/pull/4
2025-06-27 14:07:27 -05:00
J. Nick Koston
13b89f4934 Merge branch 'libretiny_logconfig' into integration 2025-06-27 13:59:01 -05:00
J. Nick Koston
d00a00d142 Reduce libretiny logconfig messages
align with https://developers.esphome.io/architecture/logging
2025-06-27 13:58:33 -05:00
J. Nick Koston
e662c39e16 Merge branch 'extract_helpers' into integration 2025-06-27 13:18:50 -05:00
J. Nick Koston
95ef131285 address bot comments 2025-06-27 13:18:39 -05:00
J. Nick Koston
7476f170f6 Merge remote-tracking branch 'upstream/extract_helpers' into extract_helpers 2025-06-27 13:16:17 -05:00
J. Nick Koston
3b6bd55d1e address bot comments 2025-06-27 13:16:06 -05:00
J. Nick Koston
10dbc9e884 Merge remote-tracking branch 'origin/extract_helpers' into integration 2025-06-27 13:03:20 -05:00
J. Nick Koston
860f619dfe Merge branch 'dev' into extract_helpers 2025-06-27 20:02:57 +02:00
J. Nick Koston
17ddc9ee0c Merge branch 'extract_helpers' into integration 2025-06-27 12:56:28 -05:00
J. Nick Koston
949689c318 address bot review 2025-06-27 12:55:58 -05:00
J. Nick Koston
86a2aac011 Merge branch 'extract_helpers' into integration 2025-06-27 12:50:37 -05:00
J. Nick Koston
d0a402f201 Extract lock-free queue and event pool to core helpers 2025-06-27 12:49:44 -05:00
Jimmy Hedman
68d66c873e Upgrade to use C++20 (#9135)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-06-27 17:31:50 +00:00
J. Nick Koston
05772d5365 Merge remote-tracking branch 'origin/integration' into integration 2025-06-27 10:19:35 -05:00
J. Nick Koston
c2a68f5147 Merge branch 'duplicate_webserver_code' into integration 2025-06-27 10:19:21 -05:00
J. Nick Koston
697ca1c7be simplify 2025-06-27 10:17:33 -05:00
J. Nick Koston
409346952f clang-format 2025-06-27 10:15:04 -05:00
J. Nick Koston
f4b3539d77 clang-format 2025-06-27 10:05:30 -05:00
J. Nick Koston
c12166c1a1 missed one 2025-06-27 10:04:29 -05:00
J. Nick Koston
8d20f003cb Merge branch 'duplicate_webserver_code' into integration 2025-06-27 09:45:00 -05:00
J. Nick Koston
88f857a2f0 defines 2025-06-27 09:44:50 -05:00
J. Nick Koston
fb7faadd99 reduce memory 2025-06-27 09:41:20 -05:00
J. Nick Koston
5c8d6752fb Merge branch 'dev' into duplicate_webserver_code 2025-06-27 16:01:32 +02:00
J. Nick Koston
dda81fbc2c Merge branch 'dev' into binary_sensor_gpio_polling 2025-06-27 15:58:14 +02:00
J. Nick Koston
c40dff5d63 cleanup 2025-06-27 06:30:51 -05:00
J. Nick Koston
6f07b54772 cleanup 2025-06-27 06:30:42 -05:00
J. Nick Koston
ce0f1dfcb6 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-27 06:30:15 -05:00
Jesse Hills
948aa13fb9 Bump version to 2025.6.2 2025-06-27 23:16:13 +12:00
scaiper
9e993ac603 [esp32] Change `enable_lwip_mdns_queries default to True` (#9188) 2025-06-27 23:16:12 +12:00
Kevin Ahrendt
9f3f4ead4f [voice_assistant] Support streaming TTS responses and fixes crash for long responses (#9224) 2025-06-27 23:16:12 +12:00
Kevin Ahrendt
068aa0ff1e [speaker] bugfix: continue to block tasks if stop flag is set (#9222) 2025-06-27 23:16:12 +12:00
Kevin Ahrendt
e146c0796a [audio] Bugfix: improve timeout handling (#9221) 2025-06-27 23:16:12 +12:00
Clyde Stubbs
cceab26bfb [lvgl] Fix dangling pointer issue with qrcode (#9190) 2025-06-27 23:16:12 +12:00
scaiper
c0b1f32889 [esp32] Change `enable_lwip_mdns_queries default to True` (#9188) 2025-06-27 22:43:18 +12:00
J. Nick Koston
837dd46adf Reduce component_iterator memory usage (#9205) 2025-06-27 01:56:54 -05:00
J. Nick Koston
13512440ac [gpio] Reduce ESP32 memory usage by optimizing struct padding (#9230) 2025-06-27 01:53:40 -05:00
J. Nick Koston
7931423e8c Reduce ethernet component memory usage by 8 bytes (#9231) 2025-06-27 01:52:12 -05:00
J. Nick Koston
62f28902c5 [wifi] Reduce memory usage (#9232) 2025-06-27 01:50:26 -05:00
Jonathan Swoboda
1f94e4cc14 [esp32] Update IDF components to use the registry (#9223) 2025-06-27 03:37:30 +00:00
Thomas Rupprecht
61dfd5541f use c++17 [[fallthrough]]; (#9149) 2025-06-27 02:40:42 +00:00
J. Nick Koston
9a3a5d48eb Merge branch 'dynamic_logging' into integration 2025-06-26 20:47:40 -05:00
J. Nick Koston
4a759eda02 Disable dynamic log level control for ESP32 ESP-IDF builds 2025-06-26 20:47:02 -05:00
Jonathan Swoboda
87321ce10b [esp32_hosted] Add support for remote wifi (#8833)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-27 11:51:13 +12:00
J. Nick Koston
4f5aacdb3a Optimize SafeModeComponent memory layout to reduce padding (#9228) 2025-06-27 01:25:26 +02:00
J. Nick Koston
26badf201d fixes 2025-06-27 01:17:26 +02:00
J. Nick Koston
384f27cd6d Merge branch 'wifi_memory' into integration 2025-06-27 01:13:11 +02:00
J. Nick Koston
ac1c5f9f58 Reduce WiFi component memory usage 2025-06-27 01:12:19 +02:00
J. Nick Koston
8ad058fdf4 Merge branch 'ethernet_padding' into integration 2025-06-27 01:00:27 +02:00
J. Nick Koston
9024c3c67a Reduce ethernet component memory usage by 8 bytes through struct optimization 2025-06-27 00:59:50 +02:00
J. Nick Koston
fc81a47499 Merge branch 'esp32_gpio_padding_waste' into integration 2025-06-27 00:43:41 +02:00
J. Nick Koston
a331452076 Reduce ESP32 GPIO memory usage by optimizing struct padding 2025-06-27 00:42:30 +02:00
J. Nick Koston
b1c6e8168e Merge remote-tracking branch 'origin/ota_memory_str' into integration 2025-06-27 00:34:36 +02:00
J. Nick Koston
b41cc0226e Optimize OTA password storage from std::string to const char 2025-06-27 00:24:45 +02:00
J. Nick Koston
450429ddd5 Merge branch 'safe_mode_padding' into integration 2025-06-27 00:22:40 +02:00
J. Nick Koston
f7b24f4b4b Optimize SafeModeComponent memory layout to reduce padding 2025-06-27 00:20:44 +02:00
J. Nick Koston
294c985380 Merge branch 'duplicate_webserver_code' into integration 2025-06-27 00:09:07 +02:00
J. Nick Koston
720964b901 Refactor web_server to extract duplicate sorting info code into helper method 2025-06-27 00:05:56 +02:00
Kevin Ahrendt
b182f2d544 [voice_assistant] Support streaming TTS responses and fixes crash for long responses (#9224) 2025-06-27 07:18:51 +12:00
Kevin Ahrendt
4fac8e9cd5 [speaker] bugfix: continue to block tasks if stop flag is set (#9222) 2025-06-27 07:12:58 +12:00
Kevin Ahrendt
d94896c0fb [audio] Bugfix: improve timeout handling (#9221) 2025-06-27 07:11:50 +12:00
Jesse Hills
15c5dd222f [tests] Remove extra newline (#9213) 2025-06-26 11:21:19 +00:00
J. Nick Koston
8895c8a987 bitpack api flags 2025-06-26 12:46:57 +02:00
J. Nick Koston
740dcd72a2 Merge branch 'duplicate_client_peername' into integration 2025-06-26 12:00:03 +02:00
J. Nick Koston
ffd442624f Optimize API connection memory usage by removing client_peername_ 2025-06-26 11:59:03 +02:00
Keith Burzinski
2930c8e9a8 [ld2450] Move consts to cpp file, optimize memory use (#9215) 2025-06-26 04:37:27 -05:00
Keith Burzinski
b12b9b97f4 [ld2410] More optimizations (#9209)
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-06-26 04:04:38 -05:00
J. Nick Koston
088fd85694 Merge branch 'batch_ping_fallback' into integration 2025-06-26 10:14:21 +02:00
J. Nick Koston
d5b68d69d3 tweak 2025-06-26 10:14:05 +02:00
J. Nick Koston
bb0f7bb393 Merge branch 'batch_ping_fallback' into integration 2025-06-26 10:10:12 +02:00
J. Nick Koston
d86a108f18 Merge remote-tracking branch 'upstream/dev' into batch_ping_fallback 2025-06-26 10:09:24 +02:00
J. Nick Koston
7828ed2d9e Merge branch 'batch_ping_fallback' into integration 2025-06-26 10:05:06 +02:00
J. Nick Koston
ebf14f50fb Merge branch 'dev' of https://github.com/esphome/esphome into batch_ping_fallback 2025-06-26 10:02:32 +02:00
Jesse Hills
09e5aa6011 [script] Add exec bit to run-in-env (#9212) 2025-06-26 00:59:16 -05:00
Jesse Hills
9549304007 [ci] Lint lock.yml (#9214) 2025-06-26 17:44:02 +12:00
Keith Burzinski
f7ac32ceda [ld2450] More optimizing, fix copypasta (#9210) 2025-06-26 00:35:30 -05:00
Jonathan Swoboda
92365f133d [esp32] Improve and simplify IDF component support (#9163) 2025-06-26 17:29:42 +12:00
Jesse Hills
9daa9a6de8 Use shared workflow for locking (#9211) 2025-06-26 16:21:51 +12:00
J. Nick Koston
23b1e428de Optimize Application class memory layout and reduce loop_interval size (#9208) 2025-06-26 15:35:01 +12:00
J. Nick Koston
f029f4f20e Fix missing protobuf message dump for batched messages with very verbose logging (#9206) 2025-06-26 13:57:41 +12:00
J. Nick Koston
79e3d2b2d7 Optimize API connection memory with tagged pointers (#9203) 2025-06-26 13:55:12 +12:00
J. Nick Koston
c74e5e0f04 Optimize TemplatableValue memory (#9202) 2025-06-26 13:51:51 +12:00
J. Nick Koston
15ef93ccc9 Optimize API connection loop performance (#9184) 2025-06-26 13:47:41 +12:00
J. Nick Koston
e017250445 Reduce logger CPU usage by disabling loop when buffer is empty (#9160)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-26 13:44:07 +12:00
J. Nick Koston
1546ff615b Merge branch 'app_padding' into integration 2025-06-26 02:47:46 +02:00
J. Nick Koston
46cf1fb597 comment 2025-06-26 02:47:33 +02:00
J. Nick Koston
8bf8655054 Merge branch 'app_padding' into integration 2025-06-26 02:45:13 +02:00
J. Nick Koston
a6d84948e2 Optimize Application class memory layout and reduce loop_interval size 2025-06-26 02:44:44 +02:00
J. Nick Koston
fac20a1f97 Merge branch 'batch_ping_fallback' into integration 2025-06-26 02:15:41 +02:00
J. Nick Koston
c65586b5e1 cleanup 2025-06-26 02:15:32 +02:00
J. Nick Koston
b27b018b06 Merge remote-tracking branch 'origin/integration' into integration 2025-06-26 02:13:42 +02:00
J. Nick Koston
403da1e632 Merge branch 'batch_ping_fallback' into integration 2025-06-26 02:12:53 +02:00
J. Nick Koston
2371ec1f9e Replace ping retry timer with batch queue fallback 2025-06-26 02:11:17 +02:00
J. Nick Koston
17497eec43 Reduce memory required for sensor entities (#9201)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-25 18:15:59 -05:00
Clyde Stubbs
6d0c6329ad [lvgl] Allow linear positioning of grid cells (#9196) 2025-06-26 10:45:14 +12:00
J. Nick Koston
5e3ec2d34b lint 2025-06-26 00:24:53 +02:00
J. Nick Koston
78d84644c9 lint 2025-06-26 00:24:12 +02:00
J. Nick Koston
0cd0f8015a Merge branch 'message_creator_ram' into integration 2025-06-26 00:09:31 +02:00
J. Nick Koston
4b5424f695 nolint 2025-06-26 00:08:15 +02:00
J. Nick Koston
a1d59040f7 Merge remote-tracking branch 'origin/message_creator_ram' into integration 2025-06-25 23:54:37 +02:00
J. Nick Koston
0306398072 Merge remote-tracking branch 'origin/component_iterator' into integration 2025-06-25 23:54:33 +02:00
J. Nick Koston
a7e0bf9013 tweak 2025-06-25 23:53:22 +02:00
J. Nick Koston
ddb988cd83 Merge remote-tracking branch 'upstream/dev' into component_iterator 2025-06-25 23:39:45 +02:00
J. Nick Koston
04b54353f1 Merge remote-tracking branch 'upstream/dev' into scheduler_copy 2025-06-25 23:36:41 +02:00
J. Nick Koston
f058107c05 tweak 2025-06-25 23:33:54 +02:00
J. Nick Koston
6b5b0815d7 tidy issues 2025-06-25 23:26:57 +02:00
J. Nick Koston
8388497038 tidy issues 2025-06-25 23:18:50 +02:00
J. Nick Koston
825b1113b6 tweak 2025-06-25 23:17:41 +02:00
J. Nick Koston
9074ef792f Reduce component_iterator memory usage 2025-06-25 19:35:40 +02:00
J. Nick Koston
0946f28511 avoid string copy in scheduler for const strings 2025-06-25 19:08:18 +02:00
J. Nick Koston
23765cd4f5 Merge branch 'message_creator_ram' into integration 2025-06-25 18:28:56 +02:00
J. Nick Koston
e20c6468d0 fix missed one 2025-06-25 18:27:43 +02:00
J. Nick Koston
b90516de1d Merge branch 'template_value' into integration 2025-06-25 17:30:36 +02:00
J. Nick Koston
ec5cc0f00f Merge branch 'integration' of https://github.com/esphome/esphome into integration 2025-06-25 17:30:27 +02:00
J. Nick Koston
5dda5a976e Merge branch 'message_creator_ram' into integration 2025-06-25 17:22:41 +02:00
J. Nick Koston
915da9ae13 make the bot happy 2025-06-25 17:22:23 +02:00
J. Nick Koston
8652464f4e Merge branch 'dev' into message_creator_ram 2025-06-25 17:16:31 +02:00
J. Nick Koston
ce6ce1c1f8 Merge branch 'message_creator_ram' into integration 2025-06-25 17:10:41 +02:00
J. Nick Koston
39efe67e55 Optimize API connection memory with tagged pointers 2025-06-25 17:08:57 +02:00
J. Nick Koston
748ffa00f3 Optimize TemplatableValue memory 2025-06-25 14:49:01 +02:00
J. Nick Koston
e8d9df2b0e Merge branch 'sensor_memory' into integration 2025-06-25 14:32:47 +02:00
J. Nick Koston
17396d67de revert 2025-06-25 14:32:38 +02:00
J. Nick Koston
edd6a86714 Merge branch 'sensor_memory' into integration 2025-06-25 14:26:03 +02:00
J. Nick Koston
85b4012c56 Merge branch 'dev' into sensor_memory 2025-06-25 14:24:09 +02:00
J. Nick Koston
7d98433502 Update tests/integration/test_host_mode_sensor.py
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-25 14:23:59 +02:00
J. Nick Koston
23774ae03b Reduce memory required for sensor entities 2025-06-25 14:17:05 +02:00
Clyde Stubbs
f35be6b5cc [binary_sensor] Add timeout filter (#9198) 2025-06-25 14:09:43 +02:00
DanielV
b18ff48b4a [API] Sub devices and areas (#8544)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-06-25 12:03:41 +00:00
J. Nick Koston
0dedbcdd71 Merge branch 'multi_device' into integration 2025-06-25 13:44:20 +02:00
Artem Draft
7c28134214 Rename kVARh/VARh to kvarh/varh (#9191) 2025-06-25 22:36:24 +12:00
Rodrigo Martín
16860e8a30 fix(MQTT): Call disconnect callback on DNS error (#9016)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-25 22:20:29 +12:00
Jonathan Swoboda
5362d1a89f [esp32_hall] Add dummy component (#9125)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-06-25 21:49:31 +12:00
Keith Burzinski
5531296ee0 [ld2410] Use `App.get_loop_component_start_time()`, shorten log messages (#9194)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-06-25 21:48:32 +12:00
Keith Burzinski
47db5e26f3 [ld2420] Shorten log messages + other clean-up (#9200) 2025-06-25 03:16:05 -05:00
Keith Burzinski
cf5197b68a [ld2450] Use `App.get_loop_component_start_time()`, shorten log messages (#9192) 2025-06-25 03:15:50 -05:00
Keith Burzinski
9f831e91b3 [helpers] Add `format_mac_address_pretty` function, migrate components (#9193) 2025-06-25 12:36:33 +12:00
Javier Peletier
2df0ebd895 [modbus_controller] Fix modbus read_lambda precision for non-floats or large integers (#9159) 2025-06-25 11:31:23 +12:00
J. Nick Koston
8b25b1eee6 update tests now that duplicate names are validated 2025-06-25 00:18:28 +02:00
J. Nick Koston
3bbf30ff5f Merge branch 'multi_device' into integration 2025-06-25 00:04:33 +02:00
J. Nick Koston
254b6a17f3 Merge remote-tracking branch 'dala318/multi_device' into integration 2025-06-24 23:54:40 +02:00
J. Nick Koston
dbb0d6349a Merge branch 'multi_device' into integration 2025-06-24 18:08:14 +02:00
J. Nick Koston
5cd498fbe9 Merge branch 'multi_device' into integration 2025-06-23 22:56:28 +02:00
J. Nick Koston
250f515f08 Merge branch 'api_opt' into integration 2025-06-23 12:20:40 +02:00
J. Nick Koston
0ec0a9e313 missing ifdef 2025-06-23 12:19:21 +02:00
J. Nick Koston
184f42ef03 Merge branch 'api_opt' into integration 2025-06-23 12:10:26 +02:00
J. Nick Koston
499517418d clang-tidy 2025-06-23 12:10:15 +02:00
J. Nick Koston
606b9c1a6d Merge branch 'api_opt' into integration 2025-06-23 12:00:34 +02:00
J. Nick Koston
971e954a54 follow logging guidelines 2025-06-23 11:59:07 +02:00
J. Nick Koston
e3aaf3219d speed up test 2025-06-23 11:58:16 +02:00
J. Nick Koston
0eea1c0e40 preen 2025-06-23 11:56:09 +02:00
J. Nick Koston
0773819778 cleanup 2025-06-23 11:45:58 +02:00
J. Nick Koston
170869b7db preen 2025-06-23 11:39:25 +02:00
J. Nick Koston
5dc54782e5 preen 2025-06-23 11:38:30 +02:00
J. Nick Koston
97b26fbefe preen 2025-06-23 11:38:10 +02:00
J. Nick Koston
686cc58d6c preen 2025-06-23 11:37:59 +02:00
J. Nick Koston
76a59759b2 preen 2025-06-23 11:37:27 +02:00
J. Nick Koston
93245a24b5 preen 2025-06-23 11:36:54 +02:00
J. Nick Koston
6a22ea1c7d preen 2025-06-23 11:35:41 +02:00
J. Nick Koston
56a02409c8 preen 2025-06-23 11:34:11 +02:00
J. Nick Koston
edeafd5a53 preen 2025-06-23 11:31:38 +02:00
J. Nick Koston
f67490b69b preen 2025-06-23 11:29:04 +02:00
J. Nick Koston
b76e34fb7b preen 2025-06-23 11:25:52 +02:00
J. Nick Koston
ddbda5032b preen 2025-06-23 11:25:24 +02:00
J. Nick Koston
5898d34b0a preen 2025-06-23 11:22:45 +02:00
J. Nick Koston
b0c02341ff preen 2025-06-23 11:22:08 +02:00
J. Nick Koston
19cbc8c33b preen 2025-06-23 11:21:37 +02:00
J. Nick Koston
02e61ef5d3 preen 2025-06-23 11:20:06 +02:00
J. Nick Koston
8d5d18064d preen 2025-06-23 11:19:56 +02:00
J. Nick Koston
c5ef7ebd27 preen 2025-06-23 11:19:07 +02:00
J. Nick Koston
047a3e0e8c preen 2025-06-23 11:18:47 +02:00
J. Nick Koston
13b23f840b preen 2025-06-23 11:17:17 +02:00
J. Nick Koston
147f6012b2 preen 2025-06-23 11:16:34 +02:00
J. Nick Koston
2c315595f0 preen 2025-06-23 11:12:04 +02:00
J. Nick Koston
20405c84ac preen 2025-06-23 11:10:07 +02:00
J. Nick Koston
0bc59b97de more api loop reductions 2025-06-23 11:06:51 +02:00
J. Nick Koston
a3a3bdc7eb more api loop reductions 2025-06-23 11:02:27 +02:00
J. Nick Koston
e767f30886 more api loop reductions 2025-06-23 10:59:49 +02:00
J. Nick Koston
e8c250a03c more api loop reductions 2025-06-23 10:59:00 +02:00
J. Nick Koston
d6725fc1ca more api loop reductions 2025-06-23 10:54:50 +02:00
J. Nick Koston
8ec998ff30 more api loop reductions 2025-06-23 10:52:34 +02:00
J. Nick Koston
23cc0c7f39 Merge remote-tracking branch 'upstream/dev' into api_reboot 2025-06-23 10:48:26 +02:00
J. Nick Koston
19b8bd6aa8 Merge remote-tracking branch 'upstream/logger_disable_loop' into integration 2025-06-23 09:03:16 +02:00
J. Nick Koston
ed57e7c6b0 Update esphome/components/logger/logger.cpp 2025-06-23 09:02:22 +02:00
J. Nick Koston
9f489c9f27 Update esphome/components/logger/logger.h 2025-06-23 09:01:21 +02:00
J. Nick Koston
f036989361 Update esphome/components/logger/logger.h 2025-06-23 09:01:01 +02:00
J. Nick Koston
6afa8141c0 Update esphome/components/logger/logger.cpp 2025-06-23 09:00:46 +02:00
J. Nick Koston
587964c6f1 Merge branch 'dev' into logger_disable_loop 2025-06-23 09:00:22 +02:00
Jesse Hills
7aea82a273 Move define 2025-06-23 14:15:10 +12:00
J. Nick Koston
bfa80157f2 Merge branch 'scheduler_memory_opt' into integration 2025-06-23 00:07:43 +02:00
J. Nick Koston
99b1b079d0 Reduce RAM usage for scheduled tasks 2025-06-23 00:03:01 +02:00
J. Nick Koston
5697d549a8 Use scheduler for api reboot 2025-06-22 23:44:08 +02:00
J. Nick Koston
a0b3527710 Merge branch 'logger_memory' into integration 2025-06-22 22:59:51 +02:00
J. Nick Koston
df24f48fa1 Merge branch 'pre_preserve_looping_components' into integration 2025-06-22 22:57:38 +02:00
J. Nick Koston
13d53590b2 Pre-reserve looping components vector to reduce memory allocations 2025-06-22 22:56:31 +02:00
J. Nick Koston
e7fa156254 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-22 20:15:02 +02:00
J. Nick Koston
a8ab6b1c43 Merge branch 'dev' into logger_disable_loop 2025-06-22 20:12:17 +02:00
J. Nick Koston
6212c6f80f Merge branch 'dev' into logger_disable_loop 2025-06-22 12:10:11 +02:00
J. Nick Koston
bbd5d050a9 Merge branch 'dev' into logger_disable_loop 2025-06-21 18:36:59 +02:00
J. Nick Koston
71a96fdcbf Merge branch 'dev' into logger_disable_loop 2025-06-21 18:11:19 +02:00
J. Nick Koston
41697a7b1b Merge remote-tracking branch 'upstream/logger_disable_loop' into integration 2025-06-21 11:19:12 +02:00
J. Nick Koston
912e265bc0 Merge branch 'dev' into logger_disable_loop 2025-06-21 11:18:59 +02:00
J. Nick Koston
96ee6fb064 Merge branch 'logger_disable_loop' into integration 2025-06-21 11:17:13 +02:00
J. Nick Koston
788dba8ef3 define 2025-06-21 11:16:14 +02:00
J. Nick Koston
fdde9c4681 Reduce Logger memory usage by optimizing variable sizes 2025-06-21 00:27:05 +02:00
J. Nick Koston
f195e73d38 Merge branch 'logger_disable_loop' into integration 2025-06-20 22:54:40 +02:00
J. Nick Koston
b0d9ffc6a1 Reduce logger CPU usage by disabling loop when buffer is empty 2025-06-20 22:53:12 +02:00
J. Nick Koston
e17619841d fix last component being charged for stats 2025-06-20 22:03:53 +02:00
J. Nick Koston
eb6a7cf3b9 fix last component being charged for stats 2025-06-20 22:02:19 +02:00
J. Nick Koston
9901e2d72e Merge branch 'dev' into integration 2025-06-20 21:36:36 +02:00
J. Nick Koston
1be4e23b68 Merge branch 'dev' into binary_sensor_gpio_polling 2025-06-19 11:07:42 +02:00
J. Nick Koston
e78094cc0a Merge branch 'dev' into esp32_touch_isr 2025-06-19 10:49:17 +02:00
J. Nick Koston
bcf961c0b0 Merge branch 'dev' into integration 2025-06-19 04:05:25 +02:00
J. Nick Koston
f84a4c9753 Merge remote-tracking branch 'origin/disable_ethernet_loop' into integration 2025-06-19 03:42:53 +02:00
J. Nick Koston
df56ca0236 remove redundant enable_loop, it must already be enabled to get here 2025-06-19 03:41:25 +02:00
J. Nick Koston
de0cd0ec67 Merge branch 'dev' into disable_ethernet_loop 2025-06-19 03:39:15 +02:00
J. Nick Koston
67c30245c4 make copilot happy 2025-06-19 02:01:55 +02:00
J. Nick Koston
1f72757591 tidy 2025-06-19 01:35:45 +02:00
J. Nick Koston
35c2fdf6af dry 2025-06-19 01:31:11 +02:00
J. Nick Koston
d1ecd841be avoid auto 2025-06-19 01:28:17 +02:00
J. Nick Koston
828a49697c Merge branch 'gap_events' into integration 2025-06-19 01:18:36 +02:00
J. Nick Koston
0551495501 try another way 2025-06-19 01:18:26 +02:00
J. Nick Koston
2bbffe4a68 try another way 2025-06-19 01:18:11 +02:00
J. Nick Koston
281ad90e39 fixes 2025-06-19 01:16:46 +02:00
J. Nick Koston
ed50976a07 fixes 2025-06-19 01:16:22 +02:00
J. Nick Koston
a3400037d9 fixes 2025-06-19 01:14:15 +02:00
J. Nick Koston
f0d82f75bc fixes 2025-06-19 01:14:05 +02:00
J. Nick Koston
349cb80e90 Merge remote-tracking branch 'origin/integration' into integration 2025-06-19 01:12:20 +02:00
J. Nick Koston
c263ee39af Merge branch 'gap_events' into integration 2025-06-19 01:12:07 +02:00
J. Nick Koston
e99bc52756 Fix missing BLE GAP events causing RSSI sensor and beacon failures 2025-06-19 01:09:13 +02:00
J. Nick Koston
7944b2b8e9 Merge branch 'ota_perf' into integration 2025-06-19 00:40:07 +02:00
J. Nick Koston
ca6ae746c1 be explict 2025-06-19 00:39:19 +02:00
J. Nick Koston
deabac18b2 Merge branch 'disable_ethernet_loop' into integration 2025-06-18 21:39:35 +02:00
J. Nick Koston
5cf8681c61 Merge branch 'ota_perf' into integration 2025-06-18 21:35:14 +02:00
J. Nick Koston
ca7ede8f96 more cleanups 2025-06-18 21:35:04 +02:00
J. Nick Koston
4969682d52 Merge branch 'ota_perf' into integration 2025-06-18 21:27:51 +02:00
J. Nick Koston
8002fe0dd5 remove safety check 2025-06-18 21:27:30 +02:00
J. Nick Koston
7dfdf965b7 remove safety check 2025-06-18 21:26:32 +02:00
J. Nick Koston
b408795dd6 Merge branch 'api_reads' into integration 2025-06-18 19:24:32 +02:00
J. Nick Koston
a5a099336b one more 2025-06-18 19:22:23 +02:00
J. Nick Koston
4ae56fc004 Merge branch 'api_reads' into integration 2025-06-18 18:40:35 +02:00
J. Nick Koston
3f71c09b7b Fix slow noise handshake by reading multiple messages per loop 2025-06-18 18:36:55 +02:00
J. Nick Koston
bd50a7f1ab cleanup 2025-06-18 14:33:58 +02:00
J. Nick Koston
51e4c45e5c Merge branch 'loop_done_enable_isr' into disable_ethernet_loop 2025-06-18 14:27:18 +02:00
J. Nick Koston
e3fae49add Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-18 14:24:42 +02:00
J. Nick Koston
610215ab60 updates 2025-06-18 14:24:31 +02:00
J. Nick Koston
74acbda435 Merge branch 'loop_done_enable_isr' into binary_sensor_gpio_polling 2025-06-18 14:19:03 +02:00
J. Nick Koston
25c4af777c Merge branch 'loop_done_enable_isr' into integration 2025-06-18 14:18:35 +02:00
J. Nick Koston
ec186e6324 rename 2025-06-18 14:17:45 +02:00
J. Nick Koston
150b7a98f3 Merge branch 'dev' into ota_perf 2025-06-18 13:57:20 +02:00
J. Nick Koston
8ae7c1cff0 Merge branch 'ota_perf' into integration 2025-06-18 13:46:36 +02:00
J. Nick Koston
7f1d0eef98 Optimize OTA loop to avoid unnecessary stack allocations 2025-06-18 13:44:07 +02:00
J. Nick Koston
1179ab33f2 tweaks 2025-06-18 12:52:18 +02:00
J. Nick Koston
a09faa1c10 Merge branch 'dev' into disable_ethernet_loop 2025-06-18 12:36:22 +02:00
J. Nick Koston
c0319d9b2f Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-18 12:28:59 +02:00
J. Nick Koston
4870cd2921 use enable_loop_soon_from_isr 2025-06-18 12:28:49 +02:00
J. Nick Koston
d4280ec68b Merge branch 'loop_done_enable_isr' into binary_sensor_gpio_polling 2025-06-18 12:23:55 +02:00
J. Nick Koston
52cdc11927 Merge remote-tracking branch 'origin/proxy_memory' into integration 2025-06-18 12:21:31 +02:00
J. Nick Koston
8345b8c9ce Update esphome/components/esp32_ble_client/ble_client_base.h
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-18 12:21:10 +02:00
J. Nick Koston
c56f0677c3 Merge remote-tracking branch 'upstream/proxy_memory' into integration 2025-06-18 12:16:23 +02:00
J. Nick Koston
00e9e1421e Merge branch 'dev' into proxy_memory 2025-06-18 12:16:12 +02:00
J. Nick Koston
93c72c6e6c Merge branch 'loop_done_enable_isr' into integration 2025-06-18 12:15:24 +02:00
J. Nick Koston
9cea930dbd Merge remote-tracking branch 'upstream/dev' into integration 2025-06-18 12:15:18 +02:00
J. Nick Koston
7b9bd70729 Add enable_loop_soon_from_isr 2025-06-18 12:09:12 +02:00
J. Nick Koston
5115c7a100 Merge branch 'bump_ruff_precommit' into integration 2025-06-18 00:15:23 +02:00
J. Nick Koston
5634494e64 Bump ruff in pre-commit to 0.12.0
matches https://github.com/esphome/esphome/pull/9120
2025-06-18 00:11:40 +02:00
J. Nick Koston
aa8bd4abf1 Bump ruff in pre-commit to 0.12.0
matches https://github.com/esphome/esphome/pull/9120
2025-06-18 00:10:30 +02:00
J. Nick Koston
17fd69dd7f Bump ruff in pre-commit to 0.12.0
matches https://github.com/esphome/esphome/pull/9120
2025-06-18 00:09:18 +02:00
J. Nick Koston
1d9dae374b Merge branch 'loop_done' into integration 2025-06-17 23:45:20 +02:00
J. Nick Koston
cb2241ad91 make sure components that disable in setup are disabled at start 2025-06-17 23:45:16 +02:00
J. Nick Koston
d8a7e9abc8 make sure components that disable in setup are disabled at start 2025-06-17 23:44:32 +02:00
J. Nick Koston
969abc3f29 make sure components that disable in setup are disabled at start 2025-06-17 23:40:46 +02:00
J. Nick Koston
766fdc8a1f make sure components that disable in setup are disabled at start 2025-06-17 23:40:31 +02:00
J. Nick Koston
4c37c20d76 cleaner fix 2025-06-17 22:30:35 +02:00
J. Nick Koston
7d314398e1 cleaner fix 2025-06-17 22:30:31 +02:00
J. Nick Koston
b69191e3a8 cleaner fix 2025-06-17 22:29:21 +02:00
J. Nick Koston
b27c6b3596 cleaner fix 2025-06-17 22:27:24 +02:00
J. Nick Koston
5453835963 make ble client disable/enable smarter 2025-06-17 18:13:09 +02:00
J. Nick Koston
4d55ba057c make ble client disable/enable smarter 2025-06-17 18:09:53 +02:00
J. Nick Koston
325c01242c tweak 2025-06-17 16:16:20 +02:00
J. Nick Koston
45b32bca89 tweak 2025-06-17 16:08:28 +02:00
J. Nick Koston
7620049214 tweak 2025-06-17 16:05:48 +02:00
J. Nick Koston
3553495a60 Merge remote-tracking branch 'origin/integration' into integration 2025-06-17 15:55:51 +02:00
J. Nick Koston
3ce6db61d5 Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-17 15:55:28 +02:00
J. Nick Koston
798ff32c40 cleanup 2025-06-17 15:55:10 +02:00
J. Nick Koston
430cee8bda Merge branch 'integration' of https://github.com/esphome/esphome into integration 2025-06-17 15:05:27 +02:00
J. Nick Koston
1fe3fb25a6 Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-17 14:38:08 +02:00
J. Nick Koston
685ed87581 preen 2025-06-17 14:38:00 +02:00
J. Nick Koston
ea3ea1eee7 tweak 2025-06-17 14:17:35 +02:00
J. Nick Koston
c9edcb909b Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-17 13:42:02 +02:00
J. Nick Koston
35bfc9f069 tweak 2025-06-17 13:41:57 +02:00
J. Nick Koston
c4aec194b9 Merge branch 'binary_sensor_gpio_polling' into integration 2025-06-17 13:31:44 +02:00
J. Nick Koston
e8547b16f6 Avoid polling for GPIO binary sensors when possible 2025-06-17 13:20:41 +02:00
J. Nick Koston
2bbe08cee0 Avoid polling for GPIO binary sensors when possible 2025-06-17 13:18:45 +02:00
J. Nick Koston
0a0c369b88 Avoid polling for GPIO binary sensors when possible 2025-06-17 13:17:35 +02:00
J. Nick Koston
5d2f454a94 Avoid polling for GPIO binary sensors when possible 2025-06-17 13:13:58 +02:00
J. Nick Koston
04bcc5c879 Avoid polling for GPIO binary sensors when possible 2025-06-17 13:02:00 +02:00
J. Nick Koston
d4db16665f Avoid polling for GPIO binary sensors when possible 2025-06-17 12:41:17 +02:00
J. Nick Koston
20b7a494f6 Merge remote-tracking branch 'origin/proxy_memory' into integration 2025-06-17 12:05:43 +02:00
J. Nick Koston
fbdce3ad89 Optimize bluetooth_proxy memory usage on ESP32 2025-06-17 12:04:49 +02:00
J. Nick Koston
4fc8807f02 Merge branch 'light_memory' into integration 2025-06-17 11:49:58 +02:00
J. Nick Koston
83075bfb5c Optimize LightState memory layout 2025-06-17 11:49:15 +02:00
J. Nick Koston
4074ec0425 Merge branch 'switch_memory' into integration 2025-06-17 11:27:45 +02:00
J. Nick Koston
8e1694dd0f Reduce Switch component memory usage by 8 bytes per instance 2025-06-17 11:27:11 +02:00
J. Nick Koston
911df18855 Merge branch 'api_memory' into integration 2025-06-17 11:10:17 +02:00
J. Nick Koston
6b049e93f8 Optimize API component memory usage by reordering class members to reduce padding 2025-06-17 11:09:22 +02:00
J. Nick Koston
a335dcc379 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-17 10:40:41 +02:00
J. Nick Koston
c6478c8a79 Merge branch 'reduce_duplicate_gen_code_api' into integration 2025-06-17 10:40:23 +02:00
J. Nick Koston
cc9d40cb60 tweaks 2025-06-17 10:40:12 +02:00
J. Nick Koston
0a6b7f9a1b Update script/api_protobuf/api_protobuf.py 2025-06-17 10:39:49 +02:00
J. Nick Koston
daa1fb9a7a Merge remote-tracking branch 'swoboda1337/bump_libretiny' into integration 2025-06-17 04:33:57 +02:00
Jonathan Swoboda
b7d543290b Bump LibreTiny 2025-06-16 21:40:06 -04:00
J. Nick Koston
ea852b60ac Merge branch 'esp32_ble_tracker_reduce_memory' into integration 2025-06-16 22:07:13 +02:00
J. Nick Koston
ed341988ea Use smaller atomic types for ESP32 BLE Tracker ring buffer indices 2025-06-16 22:06:04 +02:00
J. Nick Koston
057b6c8e30 Merge branch 'api_reduce_millis' into integration 2025-06-16 19:34:07 +02:00
J. Nick Koston
44444fe071 Optimize API server performance by using cached loop time 2025-06-16 19:33:29 +02:00
J. Nick Koston
797330d6ab Disable Ethernet loop polling when connected and stable 2025-06-16 17:28:04 +02:00
J. Nick Koston
a630d5b5f5 Merge branch 'ble_pool' into integration 2025-06-16 15:45:50 +02:00
J. Nick Koston
eb3dc82b5d naming 2025-06-16 15:45:38 +02:00
J. Nick Koston
34ed18d562 Merge branch 'ble_pool' into integration 2025-06-16 15:43:59 +02:00
J. Nick Koston
1ce02ee313 naming 2025-06-16 15:43:43 +02:00
J. Nick Koston
2a26a0188c ble pool 2025-06-16 15:29:37 +02:00
J. Nick Koston
50cb05d1b1 ble pool 2025-06-16 15:28:03 +02:00
J. Nick Koston
6e739ac453 ble pool 2025-06-16 15:23:04 +02:00
J. Nick Koston
7aa2fd9f0e ble pool 2025-06-16 15:19:10 +02:00
J. Nick Koston
8e254e1b03 ble pool 2025-06-16 15:18:19 +02:00
J. Nick Koston
1ad9d717ff ble pool 2025-06-16 15:17:57 +02:00
J. Nick Koston
104658e43a ble pool 2025-06-16 15:16:15 +02:00
J. Nick Koston
e7e4b995bf ble pool 2025-06-16 15:15:26 +02:00
J. Nick Koston
b35b54f2c2 ble pool 2025-06-16 15:11:42 +02:00
J. Nick Koston
f80aeb1d1d cleanup 2025-06-16 15:10:27 +02:00
J. Nick Koston
6a756ab3b6 cleanup 2025-06-16 15:09:49 +02:00
J. Nick Koston
58a697bed1 cleanup 2025-06-16 15:07:23 +02:00
J. Nick Koston
280960ac18 cleanup 2025-06-16 15:06:02 +02:00
J. Nick Koston
0640ff13aa ble pool 2025-06-16 15:04:40 +02:00
J. Nick Koston
545505691f ble pool 2025-06-16 15:02:10 +02:00
J. Nick Koston
11fcf81321 ble pool 2025-06-16 15:00:58 +02:00
J. Nick Koston
c565b37dc8 ble pool 2025-06-16 15:00:07 +02:00
J. Nick Koston
3d18495270 ble pool 2025-06-16 14:55:15 +02:00
J. Nick Koston
419e4e63e9 ble pool 2025-06-16 14:53:50 +02:00
J. Nick Koston
724aa2bf65 ble pool 2025-06-16 14:52:38 +02:00
J. Nick Koston
573fa8aeb3 ble pool 2025-06-16 14:52:28 +02:00
J. Nick Koston
8a672e34c5 ble pool 2025-06-16 14:47:05 +02:00
J. Nick Koston
bc49211dab ble pool 2025-06-16 14:43:29 +02:00
J. Nick Koston
4ef9c3667e Merge branch 'reduce_duplicate_gen_code_api' into integration 2025-06-16 06:06:19 -05:00
J. Nick Koston
6babe516ac move to proto.h to have less generated code 2025-06-16 06:05:19 -05:00
J. Nick Koston
e0b258ef7e Merge branch 'empty_methods' into integration 2025-06-15 22:30:02 -05:00
J. Nick Koston
ff0c3a89b1 Remove empty generated protobuf methods 2025-06-15 22:25:21 -05:00
J. Nick Koston
2511b81048 Merge branch 'reduce_duplicate_gen_code_api' into integration 2025-06-15 22:09:15 -05:00
J. Nick Koston
6ffcd94edc early return was worse for simple functions 2025-06-15 22:00:40 -05:00
J. Nick Koston
2fcf73c812 Reduce code duplication in auto-generated API protocol code 2025-06-15 21:53:33 -05:00
J. Nick Koston
dee0608af9 adjust 2025-06-15 20:47:53 -05:00
J. Nick Koston
d11860a383 Merge remote-tracking branch 'origin/loop_done' into integration 2025-06-15 20:44:24 -05:00
J. Nick Koston
1c05115bf5 Merge branch 'dev' into loop_done 2025-06-15 20:44:09 -05:00
J. Nick Koston
d7e7382d0b tests, address review comments 2025-06-15 20:43:30 -05:00
J. Nick Koston
872388f6e3 tests, address review comments 2025-06-15 20:43:01 -05:00
J. Nick Koston
1215ef920b Merge branch 'loop_done' into integration 2025-06-15 20:36:08 -05:00
J. Nick Koston
d19d5a23ea speed up test a bit 2025-06-15 20:36:00 -05:00
J. Nick Koston
f49a779f1d speed up test a bit 2025-06-15 20:35:52 -05:00
J. Nick Koston
d8bf5b80e1 Merge branch 'loop_done' into integration 2025-06-15 20:34:22 -05:00
J. Nick Koston
69483b9353 speed up test a bit 2025-06-15 20:34:13 -05:00
J. Nick Koston
14e8548989 speed up test a bit 2025-06-15 20:33:52 -05:00
J. Nick Koston
4abd93b661 tests, address review comments 2025-06-15 20:32:36 -05:00
J. Nick Koston
5d925af76f tests, address review comments 2025-06-15 20:31:25 -05:00
J. Nick Koston
b999c6064a tests, address review comments 2025-06-15 20:30:54 -05:00
J. Nick Koston
94e3576978 tests, address review comments 2025-06-15 20:30:43 -05:00
J. Nick Koston
7a22406a2d Merge remote-tracking branch 'origin/integration' into integration 2025-06-15 20:29:36 -05:00
J. Nick Koston
e60684494f Merge branch 'loop_done' into integration 2025-06-15 20:29:25 -05:00
J. Nick Koston
9db28ed779 cover 2025-06-15 20:29:12 -05:00
J. Nick Koston
6fd8c5cee7 tests, address review comments 2025-06-15 20:22:49 -05:00
J. Nick Koston
787ec43266 tests, address review comments 2025-06-15 20:22:29 -05:00
J. Nick Koston
a4efc63bf2 test 2025-06-15 19:57:20 -05:00
J. Nick Koston
80a8f1437e tests 2025-06-15 19:38:13 -05:00
J. Nick Koston
fcca94169d Merge remote-tracking branch 'origin/integration' into integration 2025-06-15 19:12:32 -05:00
J. Nick Koston
d1924088e3 Merge remote-tracking branch 'origin/loop_done' into integration 2025-06-15 19:11:57 -05:00
J. Nick Koston
fd31afe09c tidy 2025-06-15 18:58:42 -05:00
J. Nick Koston
7a763712c5 tidy 2025-06-15 18:58:32 -05:00
J. Nick Koston
7216be5da7 Merge branch 'loop_done' into integration 2025-06-15 18:44:36 -05:00
J. Nick Koston
711b0a291b comments 2025-06-15 18:44:28 -05:00
J. Nick Koston
dfc96496c8 comments 2025-06-15 18:44:15 -05:00
J. Nick Koston
2a1c5ef333 Merge branch 'loop_done' into integration 2025-06-15 18:42:49 -05:00
J. Nick Koston
9755209499 comments 2025-06-15 18:42:40 -05:00
J. Nick Koston
0b26e537d4 Merge branch 'loop_done' into integration 2025-06-15 18:40:46 -05:00
J. Nick Koston
98c6233ec3 Merge branch 'dev' into loop_done 2025-06-15 18:40:33 -05:00
J. Nick Koston
f711706b1a Fix ESP32 Improv component to re-enable loop when service starts again 2025-06-15 18:40:08 -05:00
J. Nick Koston
cee7789ab6 tweak 2025-06-15 18:37:05 -05:00
J. Nick Koston
8a06c4380d partition 2025-06-15 18:32:36 -05:00
J. Nick Koston
72ecf7a288 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-15 16:48:20 -05:00
J. Nick Koston
ef98c7502d Merge remote-tracking branch 'origin/dev' into integration 2025-06-15 13:42:11 -05:00
J. Nick Koston
03d0e74b65 Merge remote-tracking branch 'upstream/less_templates' into integration 2025-06-15 10:48:53 -05:00
J. Nick Koston
5b8fdc0364 Merge branch 'dev' into less_templates 2025-06-15 10:42:41 -05:00
J. Nick Koston
593b4bd137 Update script/api_protobuf/api_protobuf.py 2025-06-15 10:42:28 -05:00
J. Nick Koston
267e12d058 lint 2025-06-15 10:09:54 -05:00
J. Nick Koston
4a5e39b651 Add common base classes for entity protobuf messages to reduce duplicate code 2025-06-15 09:40:45 -05:00
J. Nick Koston
ea24fa5b78 Merge branch 'loop_done' into integration 2025-06-15 01:52:27 -05:00
J. Nick Koston
bb2bb128f7 remove trailing . 2025-06-15 01:52:17 -05:00
J. Nick Koston
94e8a856d7 Merge branch 'loop_done' into integration 2025-06-15 01:47:22 -05:00
J. Nick Koston
4c19fbf98e lint 2025-06-15 01:47:10 -05:00
J. Nick Koston
60f8938bfa Merge branch 'loop_done' into integration 2025-06-15 01:34:12 -05:00
J. Nick Koston
55679662b5 ordering 2025-06-15 01:34:03 -05:00
J. Nick Koston
53df959e49 Merge branch 'loop_done' into integration 2025-06-15 01:26:56 -05:00
J. Nick Koston
8e6ef9966f Merge remote-tracking branch 'upstream/loop_done' into loop_done 2025-06-15 01:26:45 -05:00
J. Nick Koston
1d52fceafa rename, cleanup 2025-06-15 01:26:25 -05:00
J. Nick Koston
99186ed864 rename, cleanup 2025-06-15 01:25:59 -05:00
J. Nick Koston
383931d484 Merge branch 'ble_events_ring_buffer' into integration 2025-06-15 00:31:34 -05:00
J. Nick Koston
0b49a54cb3 comments 2025-06-15 00:31:25 -05:00
J. Nick Koston
705c0f1891 Merge branch 'ble_events_ring_buffer' into integration 2025-06-15 00:27:13 -05:00
J. Nick Koston
544c3ffc95 comments 2025-06-15 00:26:06 -05:00
J. Nick Koston
33f252a45d Implement a lock free ring buffer for BLEEvents to avoid drops 2025-06-15 00:22:24 -05:00
J. Nick Koston
f55d82a015 Merge branch 'ble_queue_lock_free' into integration 2025-06-15 00:16:02 -05:00
J. Nick Koston
8cf33fdef0 preen 2025-06-15 00:15:48 -05:00
J. Nick Koston
f858d98811 Merge branch 'ble_queue_lock_free' into integration 2025-06-15 00:12:47 -05:00
J. Nick Koston
2a6165d440 simplify 2025-06-15 00:12:34 -05:00
J. Nick Koston
4586528c40 merge 2025-06-15 00:01:15 -05:00
J. Nick Koston
23a07baa19 Merge branch 'ble_queue_lock_free' into integration 2025-06-14 23:58:53 -05:00
J. Nick Koston
f9040ca932 cleanup 2025-06-14 23:54:42 -05:00
J. Nick Koston
4cea7f0237 Update esphome/components/esp32_ble/ble.cpp 2025-06-14 23:49:38 -05:00
J. Nick Koston
b1847d5e98 Make ble events queue lock free 2025-06-14 23:48:26 -05:00
J. Nick Koston
9ce4d2e952 Merge remote-tracking branch 'upstream/dev' into integration 2025-06-14 23:21:51 -05:00
J. Nick Koston
247078e06d Merge remote-tracking branch 'origin/loop_done' into integration 2025-06-14 23:20:20 -05:00
J. Nick Koston
a0cd72de28 revert 2025-06-14 23:19:43 -05:00
J. Nick Koston
e467f569f0 Merge branch 'loop_done' into integration 2025-06-14 23:15:49 -05:00
J. Nick Koston
e31c7b7dfc one more 2025-06-14 23:15:06 -05:00
J. Nick Koston
dc2e0c832b Merge branch 'loop_done' into integration 2025-06-14 22:37:11 -05:00
J. Nick Koston
7ddf51bb51 fix 2025-06-14 22:36:29 -05:00
J. Nick Koston
8fb3856665 small fix 2025-06-14 22:17:27 -05:00
J. Nick Koston
183dd74f3e one more 2025-06-14 22:17:27 -05:00
J. Nick Koston
4f29039b41 mark_loop_done 2025-06-14 22:17:24 -05:00
J. Nick Koston
102fcbec20 small fix 2025-06-14 22:09:19 -05:00
J. Nick Koston
d00e5212c7 one more 2025-06-14 22:04:33 -05:00
J. Nick Koston
0e6bfb62cd mark_loop_done 2025-06-14 21:58:18 -05:00
J. Nick Koston
f576e8f635 remove cap 2025-06-14 21:40:16 -05:00
J. Nick Koston
e6dc10a440 address review comments 2025-06-14 21:34:21 -05:00
J. Nick Koston
aa930fb6b6 Merge branch 'ble_queue_lock_free' into integration 2025-06-14 20:09:56 -05:00
J. Nick Koston
f327ed87e9 Make ble events queue lock free 2025-06-14 20:08:43 -05:00
J. Nick Koston
2de9be0589 Merge branch 'loop_runtime_stats' into integration 2025-06-14 19:43:45 -05:00
J. Nick Koston
345cde8645 Merge branch 'ble_events_ring_buffer' into integration 2025-06-14 19:25:57 -05:00
J. Nick Koston
cf152af9ae Implement a lock free ring buffer for BLEEvents to avoid drops 2025-06-14 19:24:57 -05:00
J. Nick Koston
d6333dcfd9 Revert "Reorder Application to reduce padding"
This reverts commit 82c39580df.
2025-06-14 18:18:45 -05:00
J. Nick Koston
0121f799f0 Merge branch 'reorder_app_reduce_padding' into integration 2025-06-14 18:16:39 -05:00
J. Nick Koston
82c39580df Reorder Application to reduce padding 2025-06-14 18:15:40 -05:00
J. Nick Koston
53a578a46f Merge branch 'area_str' into integration 2025-06-14 18:01:44 -05:00
J. Nick Koston
62612ef80b Optimize Application area_ from std::string to const char* 2025-06-14 18:00:32 -05:00
J. Nick Koston
61ac874c4c Merge branch 'parse_on_off_uint8t' into integration 2025-06-14 17:46:25 -05:00
J. Nick Koston
976b200ff6 Make ParseOnOffState enum uint8_t 2025-06-14 17:44:22 -05:00
J. Nick Koston
852343b6d8 Merge remote-tracking branch 'upstream/has_state_' into integration 2025-06-14 17:32:40 -05:00
J. Nick Koston
c56af9d52b Merge branch 'component_state_oversized' into integration 2025-06-14 17:03:31 -05:00
J. Nick Koston
05f18e2828 Optimize Component and Application state storage from uint32_t to uint8_t 2025-06-14 17:01:57 -05:00
J. Nick Koston
72804caab2 Merge branch 'warn_if_blocking_over_' into integration 2025-06-14 16:43:26 -05:00
J. Nick Koston
80cbe5c7c9 Reduce Component blocking threshold memory usage by 2 bytes per component 2025-06-14 16:42:08 -05:00
J. Nick Koston
21892d1236 Merge branch 'error_message_memory' into integration 2025-06-14 16:29:43 -05:00
J. Nick Koston
13824624f8 Reduce Component memory usage by 20 bytes per component 2025-06-14 16:27:45 -05:00
J. Nick Koston
0fd72ecbab Merge remote-tracking branch 'upstream/batch_exceeds_max_packet_size' into integration 2025-06-14 15:46:22 -05:00
J. Nick Koston
f848cb1546 Merge remote-tracking branch 'upstream/footer_not_reserved' into integration 2025-06-14 15:46:13 -05:00
J. Nick Koston
633854081a Merge remote-tracking branch 'upstream/guard_wrong_total_size' into integration 2025-06-14 15:45:35 -05:00
J. Nick Koston
4fed9a581b Merge remote-tracking branch 'upstream/missing_force' into integration 2025-06-14 15:45:28 -05:00
J. Nick Koston
e9c1202aaa Merge remote-tracking branch 'upstream/ble_events' into integration 2025-06-14 15:45:18 -05:00
J. Nick Koston
0a7ae279d0 preen 2025-06-14 11:40:50 -05:00
J. Nick Koston
0de2696543 Optimize memory usage by lazy-allocating raw callbacks in sensors 2025-06-14 11:37:11 -05:00
J. Nick Koston
a7dc239b71 cleanup 2025-06-14 10:49:23 -05:00
J. Nick Koston
fe0e6990f5 cover 2025-06-14 10:14:41 -05:00
J. Nick Koston
5ba65e92d9 cover 2025-06-14 10:12:12 -05:00
J. Nick Koston
a1452b52c9 Reduce entity memory usage by eliminating field shadowing and bit-packing 2025-06-14 10:00:49 -05:00
J. Nick Koston
dd2aa23a5f cover 2025-06-13 19:28:59 -05:00
J. Nick Koston
0e0359ba7d Fix protobuf encoding size mismatch by passing force parameter in encode_string 2025-06-13 19:20:08 -05:00
J. Nick Koston
93b1b7aded assert 2025-06-13 18:32:21 -05:00
J. Nick Koston
9472dc6a53 Fix API message encoding to return actual size instead of calculated size 2025-06-13 18:24:51 -05:00
J. Nick Koston
67b681854e Fix API message encoding to return actual size instead of calculated size 2025-06-13 18:20:01 -05:00
J. Nick Koston
7b5990833e Merge branch 'dev' into batch_exceeds_max_packet_size 2025-06-13 17:01:10 -05:00
J. Nick Koston
b6d5d04589 More coverage 2025-06-13 16:59:36 -05:00
J. Nick Koston
fdfbb3e944 Fix footer space not being reserved for batched messages
This only affects noise protocol, and its not a correctness issue, its only
fixing an inefficent reserve
2025-06-13 15:54:31 -05:00
J. Nick Koston
faa7a3e37f tweak 2025-06-13 15:14:14 -05:00
J. Nick Koston
23748b82bb Ensure api can send batches where the first message exceeds MAX_PACKET_SIZE 2025-06-13 14:58:09 -05:00
J. Nick Koston
bccb6f578a Ensure we can send batches where the first message exceeds MAX_PACKET_SIZE 2025-06-13 14:55:17 -05:00
J. Nick Koston
de8a5d6e9e Merge branch 'dev' into ble_events 2025-06-13 10:46:45 -05:00
J. Nick Koston
a8eb3f7961 lint 2025-06-13 10:46:09 -05:00
J. Nick Koston
2dc85f5a42 Merge remote-tracking branch 'upstream/esp32_touch_isr' into esp32_touch_isr 2025-06-13 10:11:49 -05:00
J. Nick Koston
82518b351d lint 2025-06-13 10:11:38 -05:00
J. Nick Koston
68f34a1683 Merge branch 'dev' into esp32_touch_isr 2025-06-12 20:19:29 -05:00
J. Nick Koston
bc6b72a422 tweaks 2025-06-12 20:16:12 -05:00
J. Nick Koston
599e28e1cb fixes 2025-06-12 20:02:39 -05:00
J. Nick Koston
ee6b2ba6c6 fixes 2025-06-12 19:56:12 -05:00
J. Nick Koston
0877b3e2af suppress unused events 2025-06-12 19:18:22 -05:00
J. Nick Koston
d1edb1e32a fix 2025-06-12 18:34:00 -05:00
J. Nick Koston
d1e6b8dd10 comment 2025-06-12 18:33:27 -05:00
J. Nick Koston
b32fc3bfdd lint 2025-06-12 18:30:53 -05:00
J. Nick Koston
1e24417db0 help with setup 2025-06-12 18:09:39 -05:00
J. Nick Koston
fb9387ecc5 help with setup 2025-06-12 17:55:21 -05:00
J. Nick Koston
6c5f4cdb70 help with setup 2025-06-12 17:49:01 -05:00
J. Nick Koston
aabacb7454 help with setup 2025-06-12 17:47:25 -05:00
J. Nick Koston
b5da84479e help with setup 2025-06-12 17:43:08 -05:00
J. Nick Koston
88d9361050 help with setup 2025-06-12 17:34:24 -05:00
J. Nick Koston
1d90388ffc help with setup 2025-06-12 17:27:09 -05:00
J. Nick Koston
b3c43ce31f help with setup 2025-06-12 17:23:10 -05:00
J. Nick Koston
6d9d22d422 help with setup 2025-06-12 17:17:16 -05:00
J. Nick Koston
86be1f56d0 preen 2025-06-12 17:14:00 -05:00
J. Nick Koston
a0c81ffd7a preen 2025-06-12 17:08:47 -05:00
J. Nick Koston
ec1dc42e58 Revert "preen"
This reverts commit 866eaed73d.
2025-06-12 17:05:06 -05:00
J. Nick Koston
866eaed73d preen 2025-06-12 16:58:24 -05:00
J. Nick Koston
a18374e1ad cleanup 2025-06-12 16:33:15 -05:00
J. Nick Koston
f7afcb3b24 cleanup 2025-06-12 16:30:41 -05:00
J. Nick Koston
3adcae783c cleanup 2025-06-12 16:19:27 -05:00
J. Nick Koston
73b40dd2e7 cleanup 2025-06-12 16:19:15 -05:00
J. Nick Koston
1e12614f9a cleanup 2025-06-12 16:14:37 -05:00
J. Nick Koston
aeaa7c699a Merge branch 'dev' into esp32_touch_isr 2025-06-12 15:57:26 -05:00
J. Nick Koston
f1c56b7254 cleanup 2025-06-12 15:56:32 -05:00
J. Nick Koston
e72e0d0646 cleanup 2025-06-12 15:56:19 -05:00
J. Nick Koston
5719d334aa cleanup 2025-06-12 15:56:04 -05:00
J. Nick Koston
bcb6b85333 cleanup 2025-06-12 15:54:15 -05:00
J. Nick Koston
5d765413ef cleanup 2025-06-12 15:53:42 -05:00
J. Nick Koston
efb2e5e7a8 cleanup 2025-06-12 15:52:38 -05:00
J. Nick Koston
5d5e346199 cleanup 2025-06-12 15:50:21 -05:00
J. Nick Koston
08a74890da cleanup 2025-06-12 15:48:29 -05:00
J. Nick Koston
0545b9c7f2 cleanup 2025-06-12 15:48:00 -05:00
J. Nick Koston
bbf7d32676 cleanup 2025-06-12 15:47:31 -05:00
J. Nick Koston
e83f4ae974 cleanup 2025-06-12 15:46:56 -05:00
J. Nick Koston
9b0d01e03f cleanup 2025-06-12 15:45:47 -05:00
J. Nick Koston
eae0d90a1e adjust 2025-06-12 15:41:41 -05:00
J. Nick Koston
90c09a7650 split 2025-06-12 13:29:12 -05:00
J. Nick Koston
aecf080211 touch ups 2025-06-12 13:16:48 -05:00
J. Nick Koston
8517420356 touch ups 2025-06-12 13:14:29 -05:00
J. Nick Koston
376be1f009 touch ups 2025-06-12 13:12:40 -05:00
J. Nick Koston
0021e76649 working 2025-06-12 13:07:25 -05:00
J. Nick Koston
d440c4bc43 derbug 2025-06-12 13:00:55 -05:00
J. Nick Koston
50840b2105 derbug 2025-06-12 13:00:39 -05:00
J. Nick Koston
7502c6b6c0 debug 2025-06-12 12:44:28 -05:00
J. Nick Koston
919c32f0cc tweak 2025-06-12 12:20:47 -05:00
J. Nick Koston
a28c951272 more debug 2025-06-12 12:13:46 -05:00
J. Nick Koston
13d7c5a9a9 more debug 2025-06-12 12:12:55 -05:00
J. Nick Koston
5f1383344d tweak 2025-06-12 12:10:50 -05:00
J. Nick Koston
48f43d3eb1 tweak 2025-06-12 11:58:21 -05:00
J. Nick Koston
4ac2141307 adjust 2025-06-12 11:52:29 -05:00
J. Nick Koston
719d8cac97 split it 2025-06-12 11:45:50 -05:00
J. Nick Koston
99cbe53a8e split it 2025-06-12 11:43:47 -05:00
J. Nick Koston
a36af1bfac s3 fixes 2025-06-12 10:59:40 -05:00
J. Nick Koston
8b6aa319bf s3 fixes 2025-06-12 10:57:46 -05:00
J. Nick Koston
a16d321e1a downgrade logging 2025-06-12 10:38:47 -05:00
J. Nick Koston
74e70278e2 fixes 2025-06-12 10:34:59 -05:00
J. Nick Koston
1332e24a2c fixes 2025-06-12 10:31:13 -05:00
J. Nick Koston
5ab78ec461 fixes 2025-06-12 10:30:58 -05:00
J. Nick Koston
ce701d3c31 fixes 2025-06-12 10:29:11 -05:00
J. Nick Koston
5fca1be44d fixes 2025-06-12 10:27:22 -05:00
J. Nick Koston
0bd4c333bd cleanup 2025-06-12 10:21:41 -05:00
J. Nick Koston
c6ed880732 fixes 2025-06-12 10:19:25 -05:00
J. Nick Koston
da0f3c6cce fixes 2025-06-12 10:12:56 -05:00
J. Nick Koston
e5d12d346a fixes 2025-06-12 10:08:29 -05:00
J. Nick Koston
478e2e726b fixes 2025-06-12 10:01:35 -05:00
J. Nick Koston
dbdac3707b fixes 2025-06-12 10:00:49 -05:00
J. Nick Koston
bd89a88e34 fixes 2025-06-12 09:23:38 -05:00
J. Nick Koston
d322d83745 fixes 2025-06-12 09:21:03 -05:00
J. Nick Koston
463a581ab9 DEBUG! 2025-06-12 00:56:42 -05:00
J. Nick Koston
eae4bd222a track pads 2025-06-11 23:29:00 -05:00
J. Nick Koston
a7bb7fc14d fix 2025-06-11 22:55:15 -05:00
J. Nick Koston
c047aa47eb use ll for all 2025-06-11 22:46:40 -05:00
J. Nick Koston
61bca56316 try touch_ll_read_raw_data 2025-06-11 22:43:41 -05:00
J. Nick Koston
9a37323eb8 Use interrupt based approach for esp32_touch 2025-06-11 22:32:25 -05:00
J. Nick Koston
99a54369bf Merge remote-tracking branch 'upstream/dev' into loop_runtime_stats 2025-06-11 22:01:22 -05:00
J. Nick Koston
f7533dfc5c review 2025-06-11 16:25:31 -05:00
J. Nick Koston
ee7d95272d lets be sure 2025-06-11 13:32:55 -05:00
J. Nick Koston
2b9b1d12e6 lets be sure 2025-06-11 13:32:47 -05:00
J. Nick Koston
2cbb5c7d8e fix error 2025-06-11 13:16:44 -05:00
J. Nick Koston
9686c7babe Merge branch 'dev' into ble_events 2025-06-11 13:09:32 -05:00
J. Nick Koston
66bd4c96c4 safety 2025-06-11 13:05:30 -05:00
J. Nick Koston
dc47faa4b6 safety 2025-06-11 13:05:01 -05:00
J. Nick Koston
55ee0b116d lint 2025-06-11 13:03:50 -05:00
J. Nick Koston
c6957c08bc lint 2025-06-11 13:02:08 -05:00
J. Nick Koston
8fe6a323d8 remove workaround 2025-06-11 13:00:55 -05:00
J. Nick Koston
8e51590c32 remove workaround 2025-06-11 12:59:57 -05:00
J. Nick Koston
ae066d5627 cleanup 2025-06-11 11:55:28 -05:00
J. Nick Koston
6760279916 cleanup compacted code 2025-06-11 11:51:43 -05:00
J. Nick Koston
3c208050b0 comments 2025-06-11 11:47:34 -05:00
J. Nick Koston
bbc7c9fb37 dry 2025-06-11 11:46:17 -05:00
J. Nick Koston
e1c3862586 preen 2025-06-11 11:36:50 -05:00
J. Nick Koston
c24b7cb7bd v->d 2025-06-11 11:34:30 -05:00
J. Nick Koston
c91e16549d lint 2025-06-11 11:27:13 -05:00
J. Nick Koston
6e70aca458 wip 2025-06-11 11:23:13 -05:00
J. Nick Koston
d9ffd0ac8e wip 2025-06-11 11:22:01 -05:00
J. Nick Koston
4641f73d19 comments 2025-06-11 11:19:36 -05:00
J. Nick Koston
9f0051c21f cleanup 2025-06-11 11:17:10 -05:00
J. Nick Koston
0331cb09e8 reduce 2025-06-11 11:17:01 -05:00
J. Nick Koston
2f8946f86c cleanup 2025-06-11 11:14:10 -05:00
J. Nick Koston
88a3df4008 cleanup 2025-06-11 11:13:34 -05:00
J. Nick Koston
0adf514bd6 preen 2025-06-11 11:09:19 -05:00
J. Nick Koston
a1b5a2abcb tweak 2025-06-11 10:58:56 -05:00
J. Nick Koston
068c62c6fe adjust 2025-06-11 10:43:48 -05:00
J. Nick Koston
0e9f14f969 wip 2025-06-11 10:20:18 -05:00
J. Nick Koston
78315fd388 preen 2025-06-11 10:08:30 -05:00
J. Nick Koston
0ab69002df preen 2025-06-11 10:05:15 -05:00
J. Nick Koston
1eec1239ec wip 2025-06-11 09:56:02 -05:00
J. Nick Koston
98a2f23024 Merge remote-tracking branch 'upstream/dev' into loop_runtime_stats 2025-05-29 11:04:14 -05:00
J. Nick Koston
c955897d1b Merge remote-tracking branch 'upstream/dev' into loop_runtime_stats 2025-05-27 11:39:45 -05:00
J. Nick Koston
cfdb0925ce Merge branch 'dev' into loop_runtime_stats 2025-05-13 23:42:19 -05:00
J. Nick Koston
83db3eddd9 revert ota 2025-05-13 01:07:43 -05:00
J. Nick Koston
cc2c5a544e revert ota 2025-05-13 01:07:38 -05:00
J. Nick Koston
8fba8c2800 revert ota 2025-05-13 01:05:37 -05:00
J. Nick Koston
51d1da8460 revert ota 2025-05-13 01:04:09 -05:00
J. Nick Koston
2f1257056d revert 2025-05-13 01:02:00 -05:00
J. Nick Koston
2f8f6967bf fix ota 2025-05-13 00:55:19 -05:00
J. Nick Koston
246527e618 runtime stats 2025-05-13 00:54:05 -05:00
J. Nick Koston
3857cc9c83 runtime stats 2025-05-13 00:51:14 -05:00
432 changed files with 8881 additions and 3984 deletions

View File

@@ -1,28 +1,11 @@
---
name: Lock
name: Lock closed issues and PRs
on:
schedule:
- cron: "30 0 * * *"
- cron: "30 0 * * *" # Run daily at 00:30 UTC
workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs:
lock:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5.0.1
with:
pr-inactive-days: "1"
pr-lock-reason: ""
exclude-any-pr-labels: keep-open
issue-inactive-days: "7"
issue-lock-reason: ""
exclude-any-issue-labels: keep-open
uses: esphome/workflows/.github/workflows/lock.yml@main

View File

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

View File

@@ -146,6 +146,7 @@ esphome/components/esp32_ble_client/* @jesserockz
esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_hosted/* @swoboda1337
esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz
@@ -247,6 +248,7 @@ esphome/components/libretiny_pwm/* @kuba2k2
esphome/components/light/* @esphome/core
esphome/components/lightwaverf/* @max246
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/ln882x/* @lamauny
esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core
esphome/components/logger/select/* @clydebarrow
@@ -325,12 +327,14 @@ esphome/components/opentherm/* @olegtarasov
esphome/components/openthread/* @mrene
esphome/components/opt3001/* @ccutrer
esphome/components/ota/* @esphome/core
esphome/components/ota_base/* @esphome/core
esphome/components/output/* @esphome/core
esphome/components/packet_transport/* @clydebarrow
esphome/components/pca6416a/* @Mat931
esphome/components/pca9554/* @clydebarrow @hwstar
esphome/components/pcf85063/* @brogon
esphome/components/pcf8563/* @KoenBreeman
esphome/components/pi4ioe5v6408/* @jesserockz
esphome/components/pid/* @OttoWinter
esphome/components/pipsolar/* @andreashergert1984
esphome/components/pm1006/* @habbie
@@ -491,7 +495,7 @@ esphome/components/vbus/* @ssieb
esphome/components/veml3235/* @kbx81
esphome/components/veml7700/* @latonita
esphome/components/version/* @esphome/core
esphome/components/voice_assistant/* @jesserockz
esphome/components/voice_assistant/* @jesserockz @kahrendt
esphome/components/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher
esphome/components/waveshare_epaper/* @clydebarrow

View File

@@ -34,11 +34,9 @@ from esphome.const import (
CONF_PORT,
CONF_SUBSTITUTIONS,
CONF_TOPIC,
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_RP2040,
PLATFORM_RTL87XX,
SECRETS_FILES,
)
from esphome.core import CORE, EsphomeError, coroutine
@@ -354,7 +352,7 @@ def upload_program(config, args, host):
if CORE.target_platform in (PLATFORM_RP2040):
return upload_using_platformio(config, args.device)
if CORE.target_platform in (PLATFORM_BK72XX, PLATFORM_RTL87XX):
if CORE.is_libretiny:
return upload_using_platformio(config, host)
return 1 # Unknown target platform

View File

@@ -4,6 +4,7 @@
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <cmath>
#include <numbers>
#ifdef USE_ESP8266
#include <core_esp8266_waveform.h>
@@ -203,7 +204,7 @@ void AcDimmer::setup() {
#endif
}
void AcDimmer::write_state(float state) {
state = std::acos(1 - (2 * state)) / 3.14159; // RMS power compensation
state = std::acos(1 - (2 * state)) / std::numbers::pi; // RMS power compensation
auto new_value = static_cast<uint16_t>(roundf(state * 65535));
if (new_value != 0 && this->store_.value == 0)
this->store_.init_cycle = this->init_with_half_cycle_;

View File

@@ -15,8 +15,7 @@ namespace adc {
#ifdef USE_ESP32
// clang-format off
#if (ESP_IDF_VERSION_MAJOR == 4 && ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 4, 7)) || \
(ESP_IDF_VERSION_MAJOR == 5 && \
#if (ESP_IDF_VERSION_MAJOR == 5 && \
((ESP_IDF_VERSION_MINOR == 0 && ESP_IDF_VERSION_PATCH >= 5) || \
(ESP_IDF_VERSION_MINOR == 1 && ESP_IDF_VERSION_PATCH >= 3) || \
(ESP_IDF_VERSION_MINOR >= 2)) \
@@ -28,19 +27,24 @@ static const adc_atten_t ADC_ATTEN_DB_12_COMPAT = ADC_ATTEN_DB_11;
#endif
#endif // USE_ESP32
enum class SamplingMode : uint8_t { AVG = 0, MIN = 1, MAX = 2 };
enum class SamplingMode : uint8_t {
AVG = 0,
MIN = 1,
MAX = 2,
};
const LogString *sampling_mode_to_str(SamplingMode mode);
class Aggregator {
public:
Aggregator(SamplingMode mode);
void add_sample(uint32_t value);
uint32_t aggregate();
Aggregator(SamplingMode mode);
protected:
SamplingMode mode_{SamplingMode::AVG};
uint32_t aggr_{0};
uint32_t samples_{0};
SamplingMode mode_{SamplingMode::AVG};
};
class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage_sampler::VoltageSampler {
@@ -81,9 +85,9 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
#endif // USE_RP2040
protected:
InternalGPIOPin *pin_;
bool output_raw_{false};
uint8_t sample_count_{1};
bool output_raw_{false};
InternalGPIOPin *pin_;
SamplingMode sampling_mode_{SamplingMode::AVG};
#ifdef USE_RP2040
@@ -95,11 +99,7 @@ class ADCSensor : public sensor::Sensor, public PollingComponent, public voltage
adc1_channel_t channel1_{ADC1_CHANNEL_MAX};
adc2_channel_t channel2_{ADC2_CHANNEL_MAX};
bool autorange_{false};
#if ESP_IDF_VERSION_MAJOR >= 5
esp_adc_cal_characteristics_t cal_characteristics_[SOC_ADC_ATTEN_NUM] = {};
#else
esp_adc_cal_characteristics_t cal_characteristics_[ADC_ATTEN_MAX] = {};
#endif // ESP_IDF_VERSION_MAJOR
#endif // USE_ESP32
};

View File

@@ -61,7 +61,7 @@ uint32_t Aggregator::aggregate() {
void ADCSensor::update() {
float value_v = this->sample();
ESP_LOGV(TAG, "'%s': Got voltage=%.4fV", this->get_name().c_str(), value_v);
ESP_LOGV(TAG, "'%s': Voltage=%.4fV", this->get_name().c_str(), value_v);
this->publish_state(value_v);
}

View File

@@ -55,32 +55,40 @@ void ADCSensor::setup() {
}
void ADCSensor::dump_config() {
static const char *const ATTEN_AUTO_STR = "auto";
static const char *const ATTEN_0DB_STR = "0 db";
static const char *const ATTEN_2_5DB_STR = "2.5 db";
static const char *const ATTEN_6DB_STR = "6 db";
static const char *const ATTEN_12DB_STR = "12 db";
const char *atten_str = ATTEN_AUTO_STR;
LOG_SENSOR("", "ADC Sensor", this);
LOG_PIN(" Pin: ", this->pin_);
if (this->autorange_) {
ESP_LOGCONFIG(TAG, " Attenuation: auto");
} else {
if (!this->autorange_) {
switch (this->attenuation_) {
case ADC_ATTEN_DB_0:
ESP_LOGCONFIG(TAG, " Attenuation: 0db");
atten_str = ATTEN_0DB_STR;
break;
case ADC_ATTEN_DB_2_5:
ESP_LOGCONFIG(TAG, " Attenuation: 2.5db");
atten_str = ATTEN_2_5DB_STR;
break;
case ADC_ATTEN_DB_6:
ESP_LOGCONFIG(TAG, " Attenuation: 6db");
atten_str = ATTEN_6DB_STR;
break;
case ADC_ATTEN_DB_12_COMPAT:
ESP_LOGCONFIG(TAG, " Attenuation: 12db");
atten_str = ATTEN_12DB_STR;
break;
default: // This is to satisfy the unused ADC_ATTEN_MAX
break;
}
}
ESP_LOGCONFIG(TAG,
" Attenuation: %s\n"
" Samples: %i\n"
" Sampling mode: %s",
this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
atten_str, this->sample_count_, LOG_STR_ARG(sampling_mode_to_str(this->sampling_mode_)));
LOG_UPDATE_INTERVAL(this);
}

View File

@@ -85,8 +85,6 @@ class ADE7880 : public i2c::I2CDevice, public PollingComponent {
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
ADE7880Store store_{};
InternalGPIOPin *irq0_pin_{nullptr};

View File

@@ -49,7 +49,6 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
void setup() override;
void dump_config() override;
/// HARDWARE_LATE setup priority
float get_setup_priority() const override { return setup_priority::DATA; }
void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
/// Helper method to request a measurement from a sensor.

View File

@@ -34,7 +34,6 @@ class ADS1118 : public Component,
ADS1118() = default;
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/// Helper method to request a measurement from a sensor.
float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode);

View File

@@ -31,8 +31,6 @@ class AGS10Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/**
* Modifies target address of AGS10.
*

View File

@@ -66,7 +66,6 @@ class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDev
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
bool set_mute_off() override;
bool set_mute_on() override;

View File

@@ -41,7 +41,6 @@ class Alpha3 : public esphome::ble_client::BLEClientNode, public PollingComponen
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; }
void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; }
void set_power_sensor(sensor::Sensor *sensor) { this->power_sensor_ = sensor; }

View File

@@ -22,7 +22,6 @@ class Am43Component : public cover::Cover, public esphome::ble_client::BLEClient
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override;
void set_pin(uint16_t pin) { this->pin_ = pin; }
void set_invert_position(bool invert_position) { this->invert_position_ = invert_position; }

View File

@@ -22,7 +22,6 @@ class Am43 : public esphome::ble_client::BLEClientNode, public PollingComponent
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_battery(sensor::Sensor *battery) { battery_ = battery; }
void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; }

View File

@@ -12,8 +12,6 @@ class AnalogThresholdBinarySensor : public Component, public binary_sensor::Bina
void dump_config() override;
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_sensor(sensor::Sensor *analog_sensor);
template<typename T> void set_upper_threshold(T upper_threshold) { this->upper_threshold_ = upper_threshold; }
template<typename T> void set_lower_threshold(T lower_threshold) { this->lower_threshold_ = lower_threshold; }

View File

@@ -26,7 +26,6 @@ class Anova : public climate::Climate, public esphome::ble_client::BLEClientNode
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
climate::ClimateTraits traits() override {
auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(true);

View File

@@ -110,9 +110,10 @@ CONFIG_SCHEMA = cv.All(
): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): _encryption_schema,
cv.Optional(
CONF_BATCH_DELAY, default="100ms"
): cv.positive_time_period_milliseconds,
cv.Optional(CONF_BATCH_DELAY, default="100ms"): cv.All(
cv.positive_time_period_milliseconds,
cv.Range(max=cv.TimePeriod(milliseconds=65535)),
),
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
single=True
),
@@ -135,23 +136,26 @@ async def to_code(config):
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
for conf in config.get(CONF_ACTIONS, []):
template_args = []
func_args = []
service_arg_names = []
for name, var_ in conf[CONF_VARIABLES].items():
native = SERVICE_ARG_NATIVE_TYPES[var_]
template_args.append(native)
func_args.append((native, name))
service_arg_names.append(name)
templ = cg.TemplateArguments(*template_args)
trigger = cg.new_Pvariable(
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
)
cg.add(var.register_user_service(trigger))
await automation.build_automation(trigger, func_args, conf)
if actions := config.get(CONF_ACTIONS, []):
cg.add_define("USE_API_YAML_SERVICES")
for conf in actions:
template_args = []
func_args = []
service_arg_names = []
for name, var_ in conf[CONF_VARIABLES].items():
native = SERVICE_ARG_NATIVE_TYPES[var_]
template_args.append(native)
func_args.append((native, name))
service_arg_names.append(name)
templ = cg.TemplateArguments(*template_args)
trigger = cg.new_Pvariable(
conf[CONF_TRIGGER_ID], templ, conf[CONF_ACTION], service_arg_names
)
cg.add(var.register_user_service(trigger))
await automation.build_automation(trigger, func_args, conf)
if CONF_ON_CLIENT_CONNECTED in config:
cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER")
await automation.build_automation(
var.get_client_connected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")],
@@ -159,6 +163,7 @@ async def to_code(config):
)
if CONF_ON_CLIENT_DISCONNECTED in config:
cg.add_define("USE_API_CLIENT_DISCONNECTED_TRIGGER")
await automation.build_automation(
var.get_client_disconnected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")],
@@ -177,7 +182,7 @@ async def to_code(config):
# and plaintext disabled. Only a factory reset can remove it.
cg.add_define("USE_API_PLAINTEXT")
cg.add_define("USE_API_NOISE")
cg.add_library("esphome/noise-c", "0.1.6")
cg.add_library("esphome/noise-c", "0.1.10")
else:
cg.add_define("USE_API_PLAINTEXT")

View File

@@ -33,9 +33,14 @@ namespace api {
// Since each message could contain multiple protobuf messages when using packet batching,
// this limits the number of messages processed, not the number of TCP packets.
static constexpr uint8_t MAX_MESSAGES_PER_LOOP = 5;
static constexpr uint8_t MAX_PING_RETRIES = 60;
static constexpr uint16_t PING_RETRY_INTERVAL = 1000;
static constexpr uint32_t KEEPALIVE_DISCONNECT_TIMEOUT = (KEEPALIVE_TIMEOUT_MS * 5) / 2;
static const char *const TAG = "api.connection";
#ifdef USE_ESP32_CAMERA
static const int ESP32_CAMERA_STOP_STREAM = 5000;
#endif
APIConnection::APIConnection(std::unique_ptr<socket::Socket> sock, APIServer *parent)
: parent_(parent), initial_state_iterator_(this), list_entities_iterator_(this) {
@@ -60,10 +65,6 @@ uint32_t APIConnection::get_batch_delay_ms_() const { return this->parent_->get_
void APIConnection::start() {
this->last_traffic_ = App.get_loop_component_start_time();
// Set next_ping_retry_ to prevent immediate ping
// This ensures the first ping happens after the keepalive period
this->next_ping_retry_ = this->last_traffic_ + KEEPALIVE_TIMEOUT_MS;
APIError err = this->helper_->init();
if (err != APIError::OK) {
on_fatal_error();
@@ -89,21 +90,24 @@ APIConnection::~APIConnection() {
#endif
}
void APIConnection::loop() {
if (this->remove_)
return;
#ifdef HAS_PROTO_MESSAGE_DUMP
void APIConnection::log_batch_item_(const DeferredBatch::BatchItem &item) {
// Set log-only mode
this->flags_.log_only_mode = true;
if (!network::is_connected()) {
// when network is disconnected force disconnect immediately
// don't wait for timeout
this->on_fatal_error();
ESP_LOGW(TAG, "%s: Network unavailable; disconnecting", this->get_client_combined_info().c_str());
return;
}
if (this->next_close_) {
// Call the creator - it will create the message and log it via encode_message_to_buffer
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
// Clear log-only mode
this->flags_.log_only_mode = false;
}
#endif
void APIConnection::loop() {
if (this->flags_.next_close) {
// requested a disconnect
this->helper_->close();
this->remove_ = true;
this->flags_.remove = true;
return;
}
@@ -144,47 +148,38 @@ void APIConnection::loop() {
} else {
this->read_message(0, buffer.type, nullptr);
}
if (this->remove_)
if (this->flags_.remove)
return;
}
}
}
// Process deferred batch if scheduled
if (this->deferred_batch_.batch_scheduled &&
App.get_loop_component_start_time() - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
if (this->flags_.batch_scheduled && now - this->deferred_batch_.batch_start_time >= this->get_batch_delay_ms_()) {
this->process_batch_();
}
if (!this->list_entities_iterator_.completed())
if (!this->list_entities_iterator_.completed()) {
this->list_entities_iterator_.advance();
if (!this->initial_state_iterator_.completed() && this->list_entities_iterator_.completed())
} else if (!this->initial_state_iterator_.completed()) {
this->initial_state_iterator_.advance();
}
static uint8_t max_ping_retries = 60;
static uint16_t ping_retry_interval = 1000;
if (this->sent_ping_) {
if (this->flags_.sent_ping) {
// Disconnect if not responded within 2.5*keepalive
if (now - this->last_traffic_ > (KEEPALIVE_TIMEOUT_MS * 5) / 2) {
if (now - this->last_traffic_ > KEEPALIVE_DISCONNECT_TIMEOUT) {
on_fatal_error();
ESP_LOGW(TAG, "%s is unresponsive; disconnecting", this->get_client_combined_info().c_str());
}
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS && now > this->next_ping_retry_) {
} else if (now - this->last_traffic_ > KEEPALIVE_TIMEOUT_MS) {
ESP_LOGVV(TAG, "Sending keepalive PING");
this->sent_ping_ = this->send_message(PingRequest());
if (!this->sent_ping_) {
this->next_ping_retry_ = now + ping_retry_interval;
this->ping_retries_++;
std::string warn_str = str_sprintf("%s: Sending keepalive failed %u time(s);",
this->get_client_combined_info().c_str(), this->ping_retries_);
if (this->ping_retries_ >= max_ping_retries) {
on_fatal_error();
ESP_LOGE(TAG, "%s disconnecting", warn_str.c_str());
} else if (this->ping_retries_ >= 10) {
ESP_LOGW(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
} else {
ESP_LOGD(TAG, "%s retrying in %u ms", warn_str.c_str(), ping_retry_interval);
}
this->flags_.sent_ping = this->send_message(PingRequest());
if (!this->flags_.sent_ping) {
// If we can't send the ping request directly (tx_buffer full),
// schedule it at the front of the batch so it will be sent with priority
ESP_LOGW(TAG, "Buffer full, ping queued");
this->schedule_message_front_(nullptr, &APIConnection::try_send_ping_request, PingRequest::MESSAGE_TYPE);
this->flags_.sent_ping = true; // Mark as sent to avoid scheduling multiple pings
}
}
@@ -207,22 +202,20 @@ void APIConnection::loop() {
// bool done = 3;
buffer.encode_bool(3, done);
bool success = this->send_buffer(buffer, 44);
bool success = this->send_buffer(buffer, CameraImageResponse::MESSAGE_TYPE);
if (success) {
this->image_reader_.consume_data(to_send);
}
if (success && done) {
this->image_reader_.return_image();
if (done) {
this->image_reader_.return_image();
}
}
}
#endif
if (state_subs_at_ != -1) {
if (state_subs_at_ >= 0) {
const auto &subs = this->parent_->get_state_subs();
if (state_subs_at_ >= (int) subs.size()) {
state_subs_at_ = -1;
} else {
if (state_subs_at_ < static_cast<int>(subs.size())) {
auto &it = subs[state_subs_at_];
SubscribeHomeAssistantStateResponse resp;
resp.entity_id = it.entity_id;
@@ -231,6 +224,8 @@ void APIConnection::loop() {
if (this->send_message(resp)) {
state_subs_at_++;
}
} else {
state_subs_at_ = -1;
}
}
}
@@ -244,19 +239,27 @@ DisconnectResponse APIConnection::disconnect(const DisconnectRequest &msg) {
// don't close yet, we still need to send the disconnect response
// close will happen on next loop
ESP_LOGD(TAG, "%s disconnected", this->get_client_combined_info().c_str());
this->next_close_ = true;
this->flags_.next_close = true;
DisconnectResponse resp;
return resp;
}
void APIConnection::on_disconnect_response(const DisconnectResponse &value) {
this->helper_->close();
this->remove_ = true;
this->flags_.remove = true;
}
// Encodes a message to the buffer and returns the total number of bytes used,
// including header and footer overhead. Returns 0 if the message doesn't fit.
uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
uint32_t remaining_size, bool is_single) {
#ifdef HAS_PROTO_MESSAGE_DUMP
// If in log-only mode, just log and return
if (conn->flags_.log_only_mode) {
conn->log_send_message_(msg.message_name(), msg.dump());
return 1; // Return non-zero to indicate "success" for logging
}
#endif
// Calculate size
uint32_t calculated_size = 0;
msg.calculate_size(calculated_size);
@@ -300,10 +303,6 @@ bool APIConnection::send_binary_sensor_state(binary_sensor::BinarySensor *binary
return this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_state,
BinarySensorStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor) {
this->schedule_message_(binary_sensor, &APIConnection::try_send_binary_sensor_info,
ListEntitiesBinarySensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -331,9 +330,6 @@ uint16_t APIConnection::try_send_binary_sensor_info(EntityBase *entity, APIConne
bool APIConnection::send_cover_state(cover::Cover *cover) {
return this->schedule_message_(cover, &APIConnection::try_send_cover_state, CoverStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_cover_info(cover::Cover *cover) {
this->schedule_message_(cover, &APIConnection::try_send_cover_info, ListEntitiesCoverResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_cover_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *cover = static_cast<cover::Cover *>(entity);
@@ -395,9 +391,6 @@ void APIConnection::cover_command(const CoverCommandRequest &msg) {
bool APIConnection::send_fan_state(fan::Fan *fan) {
return this->schedule_message_(fan, &APIConnection::try_send_fan_state, FanStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_fan_info(fan::Fan *fan) {
this->schedule_message_(fan, &APIConnection::try_send_fan_info, ListEntitiesFanResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_fan_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *fan = static_cast<fan::Fan *>(entity);
@@ -457,9 +450,6 @@ void APIConnection::fan_command(const FanCommandRequest &msg) {
bool APIConnection::send_light_state(light::LightState *light) {
return this->schedule_message_(light, &APIConnection::try_send_light_state, LightStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_light_info(light::LightState *light) {
this->schedule_message_(light, &APIConnection::try_send_light_info, ListEntitiesLightResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_light_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *light = static_cast<light::LightState *>(entity);
@@ -552,9 +542,6 @@ void APIConnection::light_command(const LightCommandRequest &msg) {
bool APIConnection::send_sensor_state(sensor::Sensor *sensor) {
return this->schedule_message_(sensor, &APIConnection::try_send_sensor_state, SensorStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_sensor_info(sensor::Sensor *sensor) {
this->schedule_message_(sensor, &APIConnection::try_send_sensor_info, ListEntitiesSensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -587,9 +574,6 @@ uint16_t APIConnection::try_send_sensor_info(EntityBase *entity, APIConnection *
bool APIConnection::send_switch_state(switch_::Switch *a_switch) {
return this->schedule_message_(a_switch, &APIConnection::try_send_switch_state, SwitchStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_switch_info(switch_::Switch *a_switch) {
this->schedule_message_(a_switch, &APIConnection::try_send_switch_info, ListEntitiesSwitchResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_switch_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -628,10 +612,6 @@ bool APIConnection::send_text_sensor_state(text_sensor::TextSensor *text_sensor)
return this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_state,
TextSensorStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_text_sensor_info(text_sensor::TextSensor *text_sensor) {
this->schedule_message_(text_sensor, &APIConnection::try_send_text_sensor_info,
ListEntitiesTextSensorResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_text_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -692,9 +672,6 @@ uint16_t APIConnection::try_send_climate_state(EntityBase *entity, APIConnection
resp.target_humidity = climate->target_humidity;
return encode_message_to_buffer(resp, ClimateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_climate_info(climate::Climate *climate) {
this->schedule_message_(climate, &APIConnection::try_send_climate_info, ListEntitiesClimateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_climate_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *climate = static_cast<climate::Climate *>(entity);
@@ -762,9 +739,6 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
bool APIConnection::send_number_state(number::Number *number) {
return this->schedule_message_(number, &APIConnection::try_send_number_state, NumberStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_number_info(number::Number *number) {
this->schedule_message_(number, &APIConnection::try_send_number_info, ListEntitiesNumberResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_number_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -816,9 +790,6 @@ uint16_t APIConnection::try_send_date_state(EntityBase *entity, APIConnection *c
fill_entity_state_base(date, resp);
return encode_message_to_buffer(resp, DateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_date_info(datetime::DateEntity *date) {
this->schedule_message_(date, &APIConnection::try_send_date_info, ListEntitiesDateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_date_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *date = static_cast<datetime::DateEntity *>(entity);
@@ -853,9 +824,6 @@ uint16_t APIConnection::try_send_time_state(EntityBase *entity, APIConnection *c
fill_entity_state_base(time, resp);
return encode_message_to_buffer(resp, TimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_time_info(datetime::TimeEntity *time) {
this->schedule_message_(time, &APIConnection::try_send_time_info, ListEntitiesTimeResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_time_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *time = static_cast<datetime::TimeEntity *>(entity);
@@ -892,9 +860,6 @@ uint16_t APIConnection::try_send_datetime_state(EntityBase *entity, APIConnectio
fill_entity_state_base(datetime, resp);
return encode_message_to_buffer(resp, DateTimeStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_datetime_info(datetime::DateTimeEntity *datetime) {
this->schedule_message_(datetime, &APIConnection::try_send_datetime_info, ListEntitiesDateTimeResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_datetime_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *datetime = static_cast<datetime::DateTimeEntity *>(entity);
@@ -918,9 +883,6 @@ void APIConnection::datetime_command(const DateTimeCommandRequest &msg) {
bool APIConnection::send_text_state(text::Text *text) {
return this->schedule_message_(text, &APIConnection::try_send_text_state, TextStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_text_info(text::Text *text) {
this->schedule_message_(text, &APIConnection::try_send_text_info, ListEntitiesTextResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_text_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -959,9 +921,6 @@ void APIConnection::text_command(const TextCommandRequest &msg) {
bool APIConnection::send_select_state(select::Select *select) {
return this->schedule_message_(select, &APIConnection::try_send_select_state, SelectStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_select_info(select::Select *select) {
this->schedule_message_(select, &APIConnection::try_send_select_info, ListEntitiesSelectResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_select_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -995,9 +954,6 @@ void APIConnection::select_command(const SelectCommandRequest &msg) {
#endif
#ifdef USE_BUTTON
void esphome::api::APIConnection::send_button_info(button::Button *button) {
this->schedule_message_(button, &APIConnection::try_send_button_info, ListEntitiesButtonResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_button_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *button = static_cast<button::Button *>(entity);
@@ -1020,9 +976,6 @@ void esphome::api::APIConnection::button_command(const ButtonCommandRequest &msg
bool APIConnection::send_lock_state(lock::Lock *a_lock) {
return this->schedule_message_(a_lock, &APIConnection::try_send_lock_state, LockStateResponse::MESSAGE_TYPE);
}
void APIConnection::send_lock_info(lock::Lock *a_lock) {
this->schedule_message_(a_lock, &APIConnection::try_send_lock_info, ListEntitiesLockResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_lock_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
@@ -1076,9 +1029,6 @@ uint16_t APIConnection::try_send_valve_state(EntityBase *entity, APIConnection *
fill_entity_state_base(valve, resp);
return encode_message_to_buffer(resp, ValveStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_valve_info(valve::Valve *valve) {
this->schedule_message_(valve, &APIConnection::try_send_valve_info, ListEntitiesValveResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_valve_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *valve = static_cast<valve::Valve *>(entity);
@@ -1124,10 +1074,6 @@ uint16_t APIConnection::try_send_media_player_state(EntityBase *entity, APIConne
fill_entity_state_base(media_player, resp);
return encode_message_to_buffer(resp, MediaPlayerStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_media_player_info(media_player::MediaPlayer *media_player) {
this->schedule_message_(media_player, &APIConnection::try_send_media_player_info,
ListEntitiesMediaPlayerResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_media_player_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *media_player = static_cast<media_player::MediaPlayer *>(entity);
@@ -1171,7 +1117,7 @@ void APIConnection::media_player_command(const MediaPlayerCommandRequest &msg) {
#ifdef USE_ESP32_CAMERA
void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image) {
if (!this->state_subscription_)
if (!this->flags_.state_subscription)
return;
if (this->image_reader_.available())
return;
@@ -1179,9 +1125,6 @@ void APIConnection::set_camera_state(std::shared_ptr<esp32_camera::CameraImage>
image->was_requested_by(esphome::esp32_camera::IDLE))
this->image_reader_.set_image(std::move(image));
}
void APIConnection::send_camera_info(esp32_camera::ESP32Camera *camera) {
this->schedule_message_(camera, &APIConnection::try_send_camera_info, ListEntitiesCameraResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *camera = static_cast<esp32_camera::ESP32Camera *>(entity);
@@ -1388,10 +1331,6 @@ uint16_t APIConnection::try_send_alarm_control_panel_state(EntityBase *entity, A
fill_entity_state_base(a_alarm_control_panel, resp);
return encode_message_to_buffer(resp, AlarmControlPanelStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
this->schedule_message_(a_alarm_control_panel, &APIConnection::try_send_alarm_control_panel_info,
ListEntitiesAlarmControlPanelResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_alarm_control_panel_info(EntityBase *entity, APIConnection *conn,
uint32_t remaining_size, bool is_single) {
auto *a_alarm_control_panel = static_cast<alarm_control_panel::AlarmControlPanel *>(entity);
@@ -1440,10 +1379,7 @@ void APIConnection::alarm_control_panel_command(const AlarmControlPanelCommandRe
#ifdef USE_EVENT
void APIConnection::send_event(event::Event *event, const std::string &event_type) {
this->schedule_message_(event, MessageCreator(event_type, EventResponse::MESSAGE_TYPE), EventResponse::MESSAGE_TYPE);
}
void APIConnection::send_event_info(event::Event *event) {
this->schedule_message_(event, &APIConnection::try_send_event_info, ListEntitiesEventResponse::MESSAGE_TYPE);
this->schedule_message_(event, MessageCreator(event_type), EventResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_event_response(event::Event *event, const std::string &event_type, APIConnection *conn,
uint32_t remaining_size, bool is_single) {
@@ -1490,9 +1426,6 @@ uint16_t APIConnection::try_send_update_state(EntityBase *entity, APIConnection
fill_entity_state_base(update, resp);
return encode_message_to_buffer(resp, UpdateStateResponse::MESSAGE_TYPE, conn, remaining_size, is_single);
}
void APIConnection::send_update_info(update::UpdateEntity *update) {
this->schedule_message_(update, &APIConnection::try_send_update_info, ListEntitiesUpdateResponse::MESSAGE_TYPE);
}
uint16_t APIConnection::try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
auto *update = static_cast<update::UpdateEntity *>(entity);
@@ -1525,7 +1458,7 @@ void APIConnection::update_command(const UpdateCommandRequest &msg) {
#endif
bool APIConnection::try_send_log_message(int level, const char *tag, const char *line) {
if (this->log_subscription_ < level)
if (this->flags_.log_subscription < level)
return false;
// Pre-calculate message size to avoid reallocations
@@ -1566,7 +1499,7 @@ HelloResponse APIConnection::hello(const HelloRequest &msg) {
resp.server_info = App.get_name() + " (esphome v" ESPHOME_VERSION ")";
resp.name = App.get_name();
this->connection_state_ = ConnectionState::CONNECTED;
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::CONNECTED);
return resp;
}
ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
@@ -1577,8 +1510,10 @@ ConnectResponse APIConnection::connect(const ConnectRequest &msg) {
resp.invalid_password = !correct;
if (correct) {
ESP_LOGD(TAG, "%s connected", this->get_client_combined_info().c_str());
this->connection_state_ = ConnectionState::AUTHENTICATED;
this->flags_.connection_state = static_cast<uint8_t>(ConnectionState::AUTHENTICATED);
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
this->parent_->get_client_connected_trigger()->trigger(this->client_info_, this->client_peername_);
#endif
#ifdef USE_HOMEASSISTANT_TIME
if (homeassistant::global_homeassistant_time != nullptr) {
this->send_time_request();
@@ -1602,6 +1537,8 @@ DeviceInfoResponse APIConnection::device_info(const DeviceInfoRequest &msg) {
resp.manufacturer = "Raspberry Pi";
#elif defined(USE_BK72XX)
resp.manufacturer = "Beken";
#elif defined(USE_LN882X)
resp.manufacturer = "Lightning";
#elif defined(USE_RTL87XX)
resp.manufacturer = "Realtek";
#elif defined(USE_HOST)
@@ -1691,7 +1628,7 @@ void APIConnection::subscribe_home_assistant_states(const SubscribeHomeAssistant
state_subs_at_ = 0;
}
bool APIConnection::try_to_clear_buffer(bool log_out_of_space) {
if (this->remove_)
if (this->flags_.remove)
return false;
if (this->helper_->can_write_without_blocking())
return true;
@@ -1741,7 +1678,7 @@ void APIConnection::on_no_setup_connection() {
}
void APIConnection::on_fatal_error() {
this->helper_->close();
this->remove_ = true;
this->flags_.remove = true;
}
void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
@@ -1750,7 +1687,9 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
// O(n) but optimized for RAM and not performance.
for (auto &item : items) {
if (item.entity == entity && item.message_type == message_type) {
// Update the existing item with the new creator
// Clean up old creator before replacing
item.creator.cleanup(message_type);
// Move assign the new creator
item.creator = std::move(creator);
return;
}
@@ -1760,9 +1699,14 @@ void APIConnection::DeferredBatch::add_item(EntityBase *entity, MessageCreator c
items.emplace_back(entity, std::move(creator), message_type);
}
void APIConnection::DeferredBatch::add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
// Insert at front for high priority messages (no deduplication check)
items.insert(items.begin(), BatchItem(entity, std::move(creator), message_type));
}
bool APIConnection::schedule_batch_() {
if (!this->deferred_batch_.batch_scheduled) {
this->deferred_batch_.batch_scheduled = true;
if (!this->flags_.batch_scheduled) {
this->flags_.batch_scheduled = true;
this->deferred_batch_.batch_start_time = App.get_loop_component_start_time();
}
return true;
@@ -1771,14 +1715,14 @@ bool APIConnection::schedule_batch_() {
ProtoWriteBuffer APIConnection::allocate_single_message_buffer(uint16_t size) { return this->create_buffer(size); }
ProtoWriteBuffer APIConnection::allocate_batch_message_buffer(uint16_t size) {
ProtoWriteBuffer result = this->prepare_message_buffer(size, this->batch_first_message_);
this->batch_first_message_ = false;
ProtoWriteBuffer result = this->prepare_message_buffer(size, this->flags_.batch_first_message);
this->flags_.batch_first_message = false;
return result;
}
void APIConnection::process_batch_() {
if (this->deferred_batch_.empty()) {
this->deferred_batch_.batch_scheduled = false;
this->flags_.batch_scheduled = false;
return;
}
@@ -1788,14 +1732,15 @@ void APIConnection::process_batch_() {
return;
}
size_t num_items = this->deferred_batch_.items.size();
size_t num_items = this->deferred_batch_.size();
// Fast path for single message - allocate exact size needed
if (num_items == 1) {
const auto &item = this->deferred_batch_.items[0];
const auto &item = this->deferred_batch_[0];
// Let the creator calculate size and encode if it fits
uint16_t payload_size = item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true);
uint16_t payload_size =
item.creator(item.entity, this, std::numeric_limits<uint16_t>::max(), true, item.message_type);
if (payload_size > 0 &&
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, item.message_type)) {
@@ -1821,7 +1766,8 @@ void APIConnection::process_batch_() {
// Pre-calculate exact buffer size needed based on message types
uint32_t total_estimated_size = 0;
for (const auto &item : this->deferred_batch_.items) {
for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
const auto &item = this->deferred_batch_[i];
total_estimated_size += get_estimated_message_size(item.message_type);
}
@@ -1830,7 +1776,7 @@ void APIConnection::process_batch_() {
// Reserve based on estimated size (much more accurate than 24-byte worst-case)
this->parent_->get_shared_buffer_ref().reserve(total_estimated_size + total_overhead);
this->batch_first_message_ = true;
this->flags_.batch_first_message = true;
size_t items_processed = 0;
uint16_t remaining_size = std::numeric_limits<uint16_t>::max();
@@ -1842,10 +1788,11 @@ void APIConnection::process_batch_() {
uint32_t current_offset = 0;
// Process items and encode directly to buffer
for (const auto &item : this->deferred_batch_.items) {
for (size_t i = 0; i < this->deferred_batch_.size(); i++) {
const auto &item = this->deferred_batch_[i];
// Try to encode message
// The creator will calculate overhead to determine if the message fits
uint16_t payload_size = item.creator(item.entity, this, remaining_size, false);
uint16_t payload_size = item.creator(item.entity, this, remaining_size, false, item.message_type);
if (payload_size == 0) {
// Message won't fit, stop processing
@@ -1893,12 +1840,19 @@ void APIConnection::process_batch_() {
}
}
// Handle remaining items more efficiently
if (items_processed < this->deferred_batch_.items.size()) {
// Remove processed items from the beginning
this->deferred_batch_.items.erase(this->deferred_batch_.items.begin(),
this->deferred_batch_.items.begin() + items_processed);
#ifdef HAS_PROTO_MESSAGE_DUMP
// Log messages after send attempt for VV debugging
// It's safe to use the buffer for logging at this point regardless of send result
for (size_t i = 0; i < items_processed; i++) {
const auto &item = this->deferred_batch_[i];
this->log_batch_item_(item);
}
#endif
// Handle remaining items more efficiently
if (items_processed < this->deferred_batch_.size()) {
// Remove processed items from the beginning with proper cleanup
this->deferred_batch_.remove_front(items_processed);
// Reschedule for remaining items
this->schedule_batch_();
} else {
@@ -1908,22 +1862,17 @@ void APIConnection::process_batch_() {
}
uint16_t APIConnection::MessageCreator::operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) const {
switch (message_type_) {
case 0: // Function pointer
return data_.ptr(entity, conn, remaining_size, is_single);
bool is_single, uint16_t message_type) const {
#ifdef USE_EVENT
case EventResponse::MESSAGE_TYPE: {
auto *e = static_cast<event::Event *>(entity);
return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single);
}
// Special case: EventResponse uses string pointer
if (message_type == EventResponse::MESSAGE_TYPE) {
auto *e = static_cast<event::Event *>(entity);
return APIConnection::try_send_event_response(e, *data_.string_ptr, conn, remaining_size, is_single);
}
#endif
default:
// Should not happen, return 0 to indicate no message
return 0;
}
// All other message types use function pointers
return data_.function_ptr(entity, conn, remaining_size, is_single);
}
uint16_t APIConnection::try_send_list_info_done(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
@@ -1938,6 +1887,12 @@ uint16_t APIConnection::try_send_disconnect_request(EntityBase *entity, APIConne
return encode_message_to_buffer(req, DisconnectRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
}
uint16_t APIConnection::try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single) {
PingRequest req;
return encode_message_to_buffer(req, PingRequest::MESSAGE_TYPE, conn, remaining_size, is_single);
}
uint16_t APIConnection::get_estimated_message_size(uint16_t message_type) {
// Use generated ESTIMATED_SIZE constants from each message type
switch (message_type) {

View File

@@ -22,6 +22,7 @@ static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
class APIConnection : public APIServerConnection {
public:
friend class APIServer;
friend class ListEntitiesIterator;
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
virtual ~APIConnection();
@@ -34,98 +35,79 @@ class APIConnection : public APIServerConnection {
}
#ifdef USE_BINARY_SENSOR
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor);
void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
#endif
#ifdef USE_COVER
bool send_cover_state(cover::Cover *cover);
void send_cover_info(cover::Cover *cover);
void cover_command(const CoverCommandRequest &msg) override;
#endif
#ifdef USE_FAN
bool send_fan_state(fan::Fan *fan);
void send_fan_info(fan::Fan *fan);
void fan_command(const FanCommandRequest &msg) override;
#endif
#ifdef USE_LIGHT
bool send_light_state(light::LightState *light);
void send_light_info(light::LightState *light);
void light_command(const LightCommandRequest &msg) override;
#endif
#ifdef USE_SENSOR
bool send_sensor_state(sensor::Sensor *sensor);
void send_sensor_info(sensor::Sensor *sensor);
#endif
#ifdef USE_SWITCH
bool send_switch_state(switch_::Switch *a_switch);
void send_switch_info(switch_::Switch *a_switch);
void switch_command(const SwitchCommandRequest &msg) override;
#endif
#ifdef USE_TEXT_SENSOR
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor);
void send_text_sensor_info(text_sensor::TextSensor *text_sensor);
#endif
#ifdef USE_ESP32_CAMERA
void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image);
void send_camera_info(esp32_camera::ESP32Camera *camera);
void camera_image(const CameraImageRequest &msg) override;
#endif
#ifdef USE_CLIMATE
bool send_climate_state(climate::Climate *climate);
void send_climate_info(climate::Climate *climate);
void climate_command(const ClimateCommandRequest &msg) override;
#endif
#ifdef USE_NUMBER
bool send_number_state(number::Number *number);
void send_number_info(number::Number *number);
void number_command(const NumberCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATE
bool send_date_state(datetime::DateEntity *date);
void send_date_info(datetime::DateEntity *date);
void date_command(const DateCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_TIME
bool send_time_state(datetime::TimeEntity *time);
void send_time_info(datetime::TimeEntity *time);
void time_command(const TimeCommandRequest &msg) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool send_datetime_state(datetime::DateTimeEntity *datetime);
void send_datetime_info(datetime::DateTimeEntity *datetime);
void datetime_command(const DateTimeCommandRequest &msg) override;
#endif
#ifdef USE_TEXT
bool send_text_state(text::Text *text);
void send_text_info(text::Text *text);
void text_command(const TextCommandRequest &msg) override;
#endif
#ifdef USE_SELECT
bool send_select_state(select::Select *select);
void send_select_info(select::Select *select);
void select_command(const SelectCommandRequest &msg) override;
#endif
#ifdef USE_BUTTON
void send_button_info(button::Button *button);
void button_command(const ButtonCommandRequest &msg) override;
#endif
#ifdef USE_LOCK
bool send_lock_state(lock::Lock *a_lock);
void send_lock_info(lock::Lock *a_lock);
void lock_command(const LockCommandRequest &msg) override;
#endif
#ifdef USE_VALVE
bool send_valve_state(valve::Valve *valve);
void send_valve_info(valve::Valve *valve);
void valve_command(const ValveCommandRequest &msg) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool send_media_player_state(media_player::MediaPlayer *media_player);
void send_media_player_info(media_player::MediaPlayer *media_player);
void media_player_command(const MediaPlayerCommandRequest &msg) override;
#endif
bool try_send_log_message(int level, const char *tag, const char *line);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
if (!this->service_call_subscription_)
if (!this->flags_.service_call_subscription)
return;
this->send_message(call);
}
@@ -167,26 +149,22 @@ class APIConnection : public APIServerConnection {
#ifdef USE_ALARM_CONTROL_PANEL
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
void send_alarm_control_panel_info(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel);
void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif
#ifdef USE_EVENT
void send_event(event::Event *event, const std::string &event_type);
void send_event_info(event::Event *event);
#endif
#ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update);
void send_update_info(update::UpdateEntity *update);
void update_command(const UpdateCommandRequest &msg) override;
#endif
void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override {
// we initiated ping
this->ping_retries_ = 0;
this->sent_ping_ = false;
this->flags_.sent_ping = false;
}
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override;
#ifdef USE_HOMEASSISTANT_TIME
@@ -199,16 +177,16 @@ class APIConnection : public APIServerConnection {
DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override;
void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); }
void subscribe_states(const SubscribeStatesRequest &msg) override {
this->state_subscription_ = true;
this->flags_.state_subscription = true;
this->initial_state_iterator_.begin();
}
void subscribe_logs(const SubscribeLogsRequest &msg) override {
this->log_subscription_ = msg.level;
this->flags_.log_subscription = msg.level;
if (msg.dump_config)
App.schedule_dump_config();
}
void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override {
this->service_call_subscription_ = true;
this->flags_.service_call_subscription = true;
}
void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
GetTimeResponse get_time(const GetTimeRequest &msg) override {
@@ -220,9 +198,12 @@ class APIConnection : public APIServerConnection {
NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override;
#endif
bool is_authenticated() override { return this->connection_state_ == ConnectionState::AUTHENTICATED; }
bool is_authenticated() override {
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::AUTHENTICATED;
}
bool is_connection_setup() override {
return this->connection_state_ == ConnectionState ::CONNECTED || this->is_authenticated();
return static_cast<ConnectionState>(this->flags_.connection_state) == ConnectionState::CONNECTED ||
this->is_authenticated();
}
void on_fatal_error() override;
void on_unauthenticated_access() override;
@@ -441,131 +422,82 @@ class APIConnection : public APIServerConnection {
// Helper function to get estimated message size for buffer pre-allocation
static uint16_t get_estimated_message_size(uint16_t message_type);
// Pointers first (4 bytes each, naturally aligned)
// Batch message method for ping requests
static uint16_t try_send_ping_request(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single);
// === Optimal member ordering for 32-bit systems ===
// Group 1: Pointers (4 bytes each on 32-bit)
std::unique_ptr<APIFrameHelper> helper_;
APIServer *parent_;
// 4-byte aligned types
uint32_t last_traffic_;
uint32_t next_ping_retry_{0};
int state_subs_at_ = -1;
// Strings (12 bytes each on 32-bit)
std::string client_info_;
std::string client_peername_;
// 2-byte aligned types
uint16_t client_api_version_major_{0};
uint16_t client_api_version_minor_{0};
// Group all 1-byte types together to minimize padding
enum class ConnectionState : uint8_t {
WAITING_FOR_HELLO,
CONNECTED,
AUTHENTICATED,
} connection_state_{ConnectionState::WAITING_FOR_HELLO};
uint8_t log_subscription_{ESPHOME_LOG_LEVEL_NONE};
bool remove_{false};
bool state_subscription_{false};
bool sent_ping_{false};
bool service_call_subscription_{false};
bool next_close_ = false;
uint8_t ping_retries_{0};
// 8 bytes used, no padding needed
// Larger objects at the end
// 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_;
#ifdef USE_ESP32_CAMERA
esp32_camera::CameraImageReader image_reader_;
#endif
// Group 3: Strings (12 bytes each on 32-bit, 4-byte aligned)
std::string client_info_;
std::string client_peername_;
// Group 4: 4-byte types
uint32_t last_traffic_;
int state_subs_at_ = -1;
// Function pointer type for message encoding
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
// Optimized MessageCreator class using union dispatch
class MessageCreator {
public:
// Constructor for function pointer (message_type = 0)
MessageCreator(MessageCreatorPtr ptr) : message_type_(0) { data_.ptr = ptr; }
// Constructor for function pointer
MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; }
// Constructor for string state capture
MessageCreator(const std::string &value, uint16_t msg_type) : message_type_(msg_type) {
data_.string_ptr = new std::string(value);
}
explicit MessageCreator(const std::string &str_value) { data_.string_ptr = new std::string(str_value); }
// Destructor
~MessageCreator() {
// Clean up string data for string-based message types
if (uses_string_data_()) {
delete data_.string_ptr;
}
}
// No destructor - cleanup must be called explicitly with message_type
// Copy constructor
MessageCreator(const MessageCreator &other) : message_type_(other.message_type_) {
if (message_type_ == 0) {
data_.ptr = other.data_.ptr;
} else if (uses_string_data_()) {
data_.string_ptr = new std::string(*other.data_.string_ptr);
} else {
data_ = other.data_; // For POD types
}
}
// 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_), message_type_(other.message_type_) {
other.message_type_ = 0; // Reset other to function pointer type
other.data_.ptr = nullptr;
}
// Assignment operators (needed for batch deduplication)
MessageCreator &operator=(const MessageCreator &other) {
if (this != &other) {
// Clean up current string data if needed
if (uses_string_data_()) {
delete data_.string_ptr;
}
// Copy new data
message_type_ = other.message_type_;
if (other.message_type_ == 0) {
data_.ptr = other.data_.ptr;
} else if (other.uses_string_data_()) {
data_.string_ptr = new std::string(*other.data_.string_ptr);
} else {
data_ = other.data_;
}
}
return *this;
}
MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.function_ptr = nullptr; }
// Move assignment
MessageCreator &operator=(MessageCreator &&other) noexcept {
if (this != &other) {
// Clean up current string data if needed
if (uses_string_data_()) {
delete data_.string_ptr;
}
// Move data
message_type_ = other.message_type_;
// IMPORTANT: Caller must ensure cleanup() was called if this contains a string!
// In our usage, this happens in add_item() deduplication and vector::erase()
data_ = other.data_;
// Reset other to safe state
other.message_type_ = 0;
other.data_.ptr = nullptr;
other.data_.function_ptr = nullptr;
}
return *this;
}
// Call operator
uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single) const;
// Call operator - uses message_type to determine union type
uint16_t operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single,
uint16_t message_type) const;
// Manual cleanup method - must be called before destruction for string types
void cleanup(uint16_t message_type) {
#ifdef USE_EVENT
if (message_type == EventResponse::MESSAGE_TYPE && data_.string_ptr != nullptr) {
delete data_.string_ptr;
data_.string_ptr = nullptr;
}
#endif
}
private:
// Helper to check if this message type uses heap-allocated strings
bool uses_string_data_() const { return message_type_ == EventResponse::MESSAGE_TYPE; }
union CreatorData {
MessageCreatorPtr ptr; // 8 bytes
std::string *string_ptr; // 8 bytes
} data_; // 8 bytes
uint16_t message_type_; // 2 bytes (0 = function ptr, >0 = state capture)
union Data {
MessageCreatorPtr function_ptr;
std::string *string_ptr;
} data_; // 4 bytes on 32-bit, 8 bytes on 64-bit - same as before
};
// Generic batching mechanism for both state updates and entity info
@@ -582,24 +514,85 @@ class APIConnection : public APIServerConnection {
std::vector<BatchItem> items;
uint32_t batch_start_time{0};
bool batch_scheduled{false};
private:
// Helper to cleanup items from the beginning
void cleanup_items_(size_t count) {
for (size_t i = 0; i < count; i++) {
items[i].creator.cleanup(items[i].message_type);
}
}
public:
DeferredBatch() {
// Pre-allocate capacity for typical batch sizes to avoid reallocation
items.reserve(8);
}
~DeferredBatch() {
// Ensure cleanup of any remaining items
clear();
}
// Add item to the batch
void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type);
// Add item to the front of the batch (for high priority messages like ping)
void add_item_front(EntityBase *entity, MessageCreator creator, uint16_t message_type);
// Clear all items with proper cleanup
void clear() {
cleanup_items_(items.size());
items.clear();
batch_scheduled = false;
batch_start_time = 0;
}
// Remove processed items from the front with proper cleanup
void remove_front(size_t count) {
cleanup_items_(count);
items.erase(items.begin(), items.begin() + count);
}
bool empty() const { return items.empty(); }
size_t size() const { return items.size(); }
const BatchItem &operator[](size_t index) const { return items[index]; }
};
// DeferredBatch here (16 bytes, 4-byte aligned)
DeferredBatch deferred_batch_;
// ConnectionState enum for type safety
enum class ConnectionState : uint8_t {
WAITING_FOR_HELLO = 0,
CONNECTED = 1,
AUTHENTICATED = 2,
};
// Group 5: Pack all small members together to minimize padding
// This group starts at a 4-byte boundary after DeferredBatch
struct APIFlags {
// Connection state only needs 2 bits (3 states)
uint8_t connection_state : 2;
// Log subscription needs 3 bits (log levels 0-7)
uint8_t log_subscription : 3;
// Boolean flags (1 bit each)
uint8_t remove : 1;
uint8_t state_subscription : 1;
uint8_t sent_ping : 1;
uint8_t service_call_subscription : 1;
uint8_t next_close : 1;
uint8_t batch_scheduled : 1;
uint8_t batch_first_message : 1; // For batch buffer allocation
#ifdef HAS_PROTO_MESSAGE_DUMP
uint8_t log_only_mode : 1;
#endif
} flags_{}; // 2 bytes total
// 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
uint32_t get_batch_delay_ms_() const;
// Message will use 8 more bytes than the minimum size, and typical
// MTU is 1500. Sometimes users will see as low as 1460 MTU.
@@ -617,8 +610,9 @@ class APIConnection : public APIServerConnection {
bool schedule_batch_();
void process_batch_();
// State for batch buffer allocation
bool batch_first_message_{false};
#ifdef HAS_PROTO_MESSAGE_DUMP
void log_batch_item_(const DeferredBatch::BatchItem &item);
#endif
// Helper function to schedule a deferred message with known message type
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
@@ -630,6 +624,12 @@ class APIConnection : public APIServerConnection {
bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
return schedule_message_(entity, MessageCreator(function_ptr), message_type);
}
// Helper function to schedule a high priority message at the front of the batch
bool schedule_message_front_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
this->deferred_batch_.add_item_front(entity, MessageCreator(function_ptr), message_type);
return this->schedule_batch_();
}
};
} // namespace api

View File

@@ -66,6 +66,17 @@ const char *api_error_to_str(APIError err) {
return "UNKNOWN";
}
// Default implementation for loop - handles sending buffered data
APIError APIFrameHelper::loop() {
if (!this->tx_buf_.empty()) {
APIError err = try_send_tx_buf_();
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
return err;
}
}
return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
}
// Helper method to buffer data from IOVs
void APIFrameHelper::buffer_data_from_iov_(const struct iovec *iov, int iovcnt, uint16_t total_write_len) {
SendBuffer buffer;
@@ -287,13 +298,8 @@ APIError APINoiseFrameHelper::loop() {
}
}
if (!this->tx_buf_.empty()) {
APIError err = try_send_tx_buf_();
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
return err;
}
}
return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
// Use base class implementation for buffer sending
return APIFrameHelper::loop();
}
/** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter
@@ -339,17 +345,15 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
return APIError::WOULD_BLOCK;
}
if (rx_header_buf_[0] != 0x01) {
state_ = State::FAILED;
HELPER_LOG("Bad indicator byte %u", rx_header_buf_[0]);
return APIError::BAD_INDICATOR;
}
// header reading done
}
// read body
uint8_t indicator = rx_header_buf_[0];
if (indicator != 0x01) {
state_ = State::FAILED;
HELPER_LOG("Bad indicator byte %u", indicator);
return APIError::BAD_INDICATOR;
}
uint16_t msg_size = (((uint16_t) rx_header_buf_[1]) << 8) | rx_header_buf_[2];
if (state_ != State::DATA && msg_size > 128) {
@@ -595,10 +599,6 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return APIError::BAD_DATA_PACKET;
}
// uint16_t type;
// uint16_t data_len;
// uint8_t *data;
// uint8_t *padding; zero or more bytes to fill up the rest of the packet
uint16_t type = (((uint16_t) msg_data[0]) << 8) | msg_data[1];
uint16_t data_len = (((uint16_t) msg_data[2]) << 8) | msg_data[3];
if (data_len > msg_size - 4) {
@@ -831,18 +831,12 @@ APIError APIPlaintextFrameHelper::init() {
state_ = State::DATA;
return APIError::OK;
}
/// Not used for plaintext
APIError APIPlaintextFrameHelper::loop() {
if (state_ != State::DATA) {
return APIError::BAD_STATE;
}
if (!this->tx_buf_.empty()) {
APIError err = try_send_tx_buf_();
if (err != APIError::OK && err != APIError::WOULD_BLOCK) {
return err;
}
}
return APIError::OK; // Convert WOULD_BLOCK to OK to avoid connection termination
// Use base class implementation for buffer sending
return APIFrameHelper::loop();
}
/** Read a packet into the rx_buf_. If successful, stores frame data in the frame parameter

View File

@@ -38,7 +38,7 @@ struct PacketInfo {
: message_type(type), offset(off), payload_size(size), padding(0) {}
};
enum class APIError : int {
enum class APIError : uint16_t {
OK = 0,
WOULD_BLOCK = 1001,
BAD_HANDSHAKE_PACKET_LEN = 1002,
@@ -74,7 +74,7 @@ class APIFrameHelper {
}
virtual ~APIFrameHelper() = default;
virtual APIError init() = 0;
virtual APIError loop() = 0;
virtual APIError loop();
virtual APIError read_packet(ReadPacketBuffer *buffer) = 0;
bool can_write_without_blocking() { return state_ == State::DATA && tx_buf_.empty(); }
std::string getpeername() { return socket_->getpeername(); }

View File

@@ -3493,7 +3493,7 @@ bool SubscribeLogsResponse::decode_length(uint32_t field_id, ProtoLengthDelimite
}
void SubscribeLogsResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_enum<enums::LogLevel>(1, this->level);
buffer.encode_string(3, this->message);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->message.data()), this->message.size());
buffer.encode_bool(4, this->send_failed);
}
void SubscribeLogsResponse::calculate_size(uint32_t &total_size) const {
@@ -3529,7 +3529,9 @@ bool NoiseEncryptionSetKeyRequest::decode_length(uint32_t field_id, ProtoLengthD
return false;
}
}
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const { buffer.encode_string(1, this->key); }
void NoiseEncryptionSetKeyRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->key.data()), this->key.size());
}
void NoiseEncryptionSetKeyRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_string_field(total_size, 1, this->key, false);
}
@@ -4266,7 +4268,7 @@ bool CameraImageResponse::decode_32bit(uint32_t field_id, Proto32Bit value) {
}
void CameraImageResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_fixed32(1, this->key);
buffer.encode_string(2, this->data);
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
buffer.encode_bool(3, this->done);
}
void CameraImageResponse::calculate_size(uint32_t &total_size) const {
@@ -6784,7 +6786,7 @@ void BluetoothServiceData::encode(ProtoWriteBuffer buffer) const {
for (auto &it : this->legacy_data) {
buffer.encode_uint32(2, it, true);
}
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothServiceData::calculate_size(uint32_t &total_size) const {
ProtoSize::add_string_field(total_size, 1, this->uuid, false);
@@ -6858,7 +6860,7 @@ bool BluetoothLEAdvertisementResponse::decode_length(uint32_t field_id, ProtoLen
}
void BluetoothLEAdvertisementResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_string(2, this->name);
buffer.encode_bytes(2, reinterpret_cast<const uint8_t *>(this->name.data()), this->name.size());
buffer.encode_sint32(3, this->rssi);
for (auto &it : this->service_uuids) {
buffer.encode_string(4, it, true);
@@ -6959,7 +6961,7 @@ void BluetoothLERawAdvertisement::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_sint32(2, this->rssi);
buffer.encode_uint32(3, this->address_type);
buffer.encode_string(4, this->data);
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothLERawAdvertisement::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7492,7 +7494,7 @@ bool BluetoothGATTReadResponse::decode_length(uint32_t field_id, ProtoLengthDeli
void BluetoothGATTReadResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTReadResponse::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7551,7 +7553,7 @@ void BluetoothGATTWriteRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_bool(3, this->response);
buffer.encode_string(4, this->data);
buffer.encode_bytes(4, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTWriteRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7648,7 +7650,7 @@ bool BluetoothGATTWriteDescriptorRequest::decode_length(uint32_t field_id, Proto
void BluetoothGATTWriteDescriptorRequest::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTWriteDescriptorRequest::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -7750,7 +7752,7 @@ bool BluetoothGATTNotifyDataResponse::decode_length(uint32_t field_id, ProtoLeng
void BluetoothGATTNotifyDataResponse::encode(ProtoWriteBuffer buffer) const {
buffer.encode_uint64(1, this->address);
buffer.encode_uint32(2, this->handle);
buffer.encode_string(3, this->data);
buffer.encode_bytes(3, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
}
void BluetoothGATTNotifyDataResponse::calculate_size(uint32_t &total_size) const {
ProtoSize::add_uint64_field(total_size, 1, this->address, false);
@@ -8480,7 +8482,7 @@ bool VoiceAssistantAudio::decode_length(uint32_t field_id, ProtoLengthDelimited
}
}
void VoiceAssistantAudio::encode(ProtoWriteBuffer buffer) const {
buffer.encode_string(1, this->data);
buffer.encode_bytes(1, reinterpret_cast<const uint8_t *>(this->data.data()), this->data.size());
buffer.encode_bool(2, this->end);
}
void VoiceAssistantAudio::calculate_size(uint32_t &total_size) const {

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ void APIServerConnectionBase::log_send_message_(const char *name, const std::str
}
#endif
bool 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, uint8_t *msg_data) {
switch (msg_type) {
case 1: {
HelloRequest msg;
@@ -106,50 +106,50 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_subscribe_logs_request(msg);
break;
}
case 30: {
#ifdef USE_COVER
case 30: {
CoverCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_cover_command_request: %s", msg.dump().c_str());
#endif
this->on_cover_command_request(msg);
#endif
break;
}
case 31: {
#endif
#ifdef USE_FAN
case 31: {
FanCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_fan_command_request: %s", msg.dump().c_str());
#endif
this->on_fan_command_request(msg);
#endif
break;
}
case 32: {
#endif
#ifdef USE_LIGHT
case 32: {
LightCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_light_command_request: %s", msg.dump().c_str());
#endif
this->on_light_command_request(msg);
#endif
break;
}
case 33: {
#endif
#ifdef USE_SWITCH
case 33: {
SwitchCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_switch_command_request: %s", msg.dump().c_str());
#endif
this->on_switch_command_request(msg);
#endif
break;
}
#endif
case 34: {
SubscribeHomeassistantServicesRequest msg;
msg.decode(msg_data, msg_size);
@@ -204,395 +204,394 @@ bool APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type,
this->on_execute_service_request(msg);
break;
}
case 45: {
#ifdef USE_ESP32_CAMERA
case 45: {
CameraImageRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_camera_image_request: %s", msg.dump().c_str());
#endif
this->on_camera_image_request(msg);
#endif
break;
}
case 48: {
#endif
#ifdef USE_CLIMATE
case 48: {
ClimateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_climate_command_request: %s", msg.dump().c_str());
#endif
this->on_climate_command_request(msg);
#endif
break;
}
case 51: {
#endif
#ifdef USE_NUMBER
case 51: {
NumberCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_number_command_request: %s", msg.dump().c_str());
#endif
this->on_number_command_request(msg);
#endif
break;
}
case 54: {
#endif
#ifdef USE_SELECT
case 54: {
SelectCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_select_command_request: %s", msg.dump().c_str());
#endif
this->on_select_command_request(msg);
#endif
break;
}
case 57: {
#endif
#ifdef USE_SIREN
case 57: {
SirenCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_siren_command_request: %s", msg.dump().c_str());
#endif
this->on_siren_command_request(msg);
#endif
break;
}
case 60: {
#endif
#ifdef USE_LOCK
case 60: {
LockCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_lock_command_request: %s", msg.dump().c_str());
#endif
this->on_lock_command_request(msg);
#endif
break;
}
case 62: {
#endif
#ifdef USE_BUTTON
case 62: {
ButtonCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_button_command_request: %s", msg.dump().c_str());
#endif
this->on_button_command_request(msg);
#endif
break;
}
case 65: {
#endif
#ifdef USE_MEDIA_PLAYER
case 65: {
MediaPlayerCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_media_player_command_request: %s", msg.dump().c_str());
#endif
this->on_media_player_command_request(msg);
#endif
break;
}
case 66: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 66: {
SubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
case 68: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 68: {
BluetoothDeviceRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_device_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_device_request(msg);
#endif
break;
}
case 70: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 70: {
BluetoothGATTGetServicesRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_get_services_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_get_services_request(msg);
#endif
break;
}
case 73: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 73: {
BluetoothGATTReadRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_read_request(msg);
#endif
break;
}
case 75: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 75: {
BluetoothGATTWriteRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_write_request(msg);
#endif
break;
}
case 76: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 76: {
BluetoothGATTReadDescriptorRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_read_descriptor_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_read_descriptor_request(msg);
#endif
break;
}
case 77: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 77: {
BluetoothGATTWriteDescriptorRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_write_descriptor_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_write_descriptor_request(msg);
#endif
break;
}
case 78: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 78: {
BluetoothGATTNotifyRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_gatt_notify_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_gatt_notify_request(msg);
#endif
break;
}
case 80: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 80: {
SubscribeBluetoothConnectionsFreeRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_bluetooth_connections_free_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_bluetooth_connections_free_request(msg);
#endif
break;
}
case 87: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 87: {
UnsubscribeBluetoothLEAdvertisementsRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_unsubscribe_bluetooth_le_advertisements_request: %s", msg.dump().c_str());
#endif
this->on_unsubscribe_bluetooth_le_advertisements_request(msg);
#endif
break;
}
case 89: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 89: {
SubscribeVoiceAssistantRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_subscribe_voice_assistant_request: %s", msg.dump().c_str());
#endif
this->on_subscribe_voice_assistant_request(msg);
#endif
break;
}
case 91: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 91: {
VoiceAssistantResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_response(msg);
#endif
break;
}
case 92: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 92: {
VoiceAssistantEventResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_event_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_event_response(msg);
#endif
break;
}
case 96: {
#endif
#ifdef USE_ALARM_CONTROL_PANEL
case 96: {
AlarmControlPanelCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_alarm_control_panel_command_request: %s", msg.dump().c_str());
#endif
this->on_alarm_control_panel_command_request(msg);
#endif
break;
}
case 99: {
#endif
#ifdef USE_TEXT
case 99: {
TextCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_text_command_request: %s", msg.dump().c_str());
#endif
this->on_text_command_request(msg);
#endif
break;
}
case 102: {
#endif
#ifdef USE_DATETIME_DATE
case 102: {
DateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_command_request: %s", msg.dump().c_str());
#endif
this->on_date_command_request(msg);
#endif
break;
}
case 105: {
#endif
#ifdef USE_DATETIME_TIME
case 105: {
TimeCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_time_command_request: %s", msg.dump().c_str());
#endif
this->on_time_command_request(msg);
#endif
break;
}
case 106: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 106: {
VoiceAssistantAudio msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_audio: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_audio(msg);
#endif
break;
}
case 111: {
#endif
#ifdef USE_VALVE
case 111: {
ValveCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_valve_command_request: %s", msg.dump().c_str());
#endif
this->on_valve_command_request(msg);
#endif
break;
}
case 114: {
#endif
#ifdef USE_DATETIME_DATETIME
case 114: {
DateTimeCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_date_time_command_request: %s", msg.dump().c_str());
#endif
this->on_date_time_command_request(msg);
#endif
break;
}
case 115: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 115: {
VoiceAssistantTimerEventResponse msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_timer_event_response: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_timer_event_response(msg);
#endif
break;
}
case 118: {
#endif
#ifdef USE_UPDATE
case 118: {
UpdateCommandRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_update_command_request: %s", msg.dump().c_str());
#endif
this->on_update_command_request(msg);
#endif
break;
}
case 119: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 119: {
VoiceAssistantAnnounceRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_announce_request: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_announce_request(msg);
#endif
break;
}
case 121: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 121: {
VoiceAssistantConfigurationRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_configuration_request: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_configuration_request(msg);
#endif
break;
}
case 123: {
#endif
#ifdef USE_VOICE_ASSISTANT
case 123: {
VoiceAssistantSetConfiguration msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_voice_assistant_set_configuration: %s", msg.dump().c_str());
#endif
this->on_voice_assistant_set_configuration(msg);
#endif
break;
}
case 124: {
#endif
#ifdef USE_API_NOISE
case 124: {
NoiseEncryptionSetKeyRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_noise_encryption_set_key_request: %s", msg.dump().c_str());
#endif
this->on_noise_encryption_set_key_request(msg);
#endif
break;
}
case 127: {
#endif
#ifdef USE_BLUETOOTH_PROXY
case 127: {
BluetoothScannerSetModeRequest msg;
msg.decode(msg_data, msg_size);
#ifdef HAS_PROTO_MESSAGE_DUMP
ESP_LOGVV(TAG, "on_bluetooth_scanner_set_mode_request: %s", msg.dump().c_str());
#endif
this->on_bluetooth_scanner_set_mode_request(msg);
#endif
break;
}
#endif
default:
return false;
break;
}
return true;
}
void APIServerConnection::on_hello_request(const HelloRequest &msg) {

View File

@@ -19,7 +19,7 @@ class APIServerConnectionBase : public ProtoService {
template<typename T> bool send_message(const T &msg) {
#ifdef HAS_PROTO_MESSAGE_DUMP
this->log_send_message_(T::message_name(), msg.dump());
this->log_send_message_(msg.message_name(), msg.dump());
#endif
return this->send_message_(msg, T::MESSAGE_TYPE);
}
@@ -199,7 +199,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif
protected:
bool 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, uint8_t *msg_data) override;
};
class APIServerConnection : public APIServerConnectionBase {

View File

@@ -316,15 +316,13 @@ class ProtoSize {
/**
* @brief Calculates and adds the size of a nested message field to the total message size
*
* This templated version directly takes a message object, calculates its size internally,
* This version takes a ProtoMessage object, calculates its size internally,
* and updates the total_size reference. This eliminates the need for a temporary variable
* at the call site.
*
* @tparam MessageType The type of the nested message (inferred from parameter)
* @param message The nested message object
*/
template<typename MessageType>
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const MessageType &message,
static inline void add_message_object(uint32_t &total_size, uint32_t field_id_size, const ProtoMessage &message,
bool force = false) {
uint32_t nested_size = 0;
message.calculate_size(nested_size);

View File

@@ -47,6 +47,11 @@ void APIServer::setup() {
}
#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");
@@ -99,21 +104,19 @@ void APIServer::setup() {
return;
}
for (auto &c : this->clients_) {
if (!c->remove_)
if (!c->flags_.remove)
c->try_send_log_message(level, tag, message);
}
});
}
#endif
this->last_connected_ = App.get_loop_component_start_time();
#ifdef USE_ESP32_CAMERA
if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) {
esp32_camera::global_esp32_camera->add_image_callback(
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) {
if (!c->remove_)
if (!c->flags_.remove)
c->set_camera_state(image);
}
});
@@ -121,6 +124,16 @@ void APIServer::setup() {
#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();
}
});
}
void APIServer::loop() {
// Accept new clients only if the socket exists and has incoming connections
if (this->socket_ && this->socket_->ready()) {
@@ -130,51 +143,63 @@ void APIServer::loop() {
auto sock = this->socket_->accept_loop_monitored((struct sockaddr *) &source_addr, &addr_len);
if (!sock)
break;
ESP_LOGD(TAG, "Accepted %s", sock->getpeername().c_str());
ESP_LOGD(TAG, "Accept %s", sock->getpeername().c_str());
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
if (this->clients_.size() == 1 && this->reboot_timeout_ != 0) {
this->status_clear_warning();
this->cancel_timeout("api_reboot");
}
}
}
if (this->clients_.empty()) {
return;
}
// Process clients and remove disconnected ones in a single pass
if (!this->clients_.empty()) {
size_t client_index = 0;
while (client_index < this->clients_.size()) {
auto &client = this->clients_[client_index];
if (client->remove_) {
// Handle disconnection
this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
ESP_LOGV(TAG, "Removing connection to %s", client->client_info_.c_str());
// Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) {
std::swap(this->clients_[client_index], this->clients_.back());
}
this->clients_.pop_back();
// Don't increment client_index since we need to process the swapped element
} else {
// Process active client
client->loop();
client_index++; // Move to next client
}
// Check network connectivity once for all clients
if (!network::is_connected()) {
// Network is down - disconnect all clients
for (auto &client : this->clients_) {
client->on_fatal_error();
ESP_LOGW(TAG, "%s: Network down; disconnect", client->get_client_combined_info().c_str());
}
// Continue to process and clean up the clients below
}
if (this->reboot_timeout_ != 0) {
const uint32_t now = App.get_loop_component_start_time();
if (!this->is_connected()) {
if (now - this->last_connected_ > this->reboot_timeout_) {
ESP_LOGE(TAG, "No client connected; rebooting");
App.reboot();
}
this->status_set_warning();
} else {
this->last_connected_ = now;
this->status_clear_warning();
size_t client_index = 0;
while (client_index < this->clients_.size()) {
auto &client = this->clients_[client_index];
if (!client->flags_.remove) {
// Common case: process active client
client->loop();
client_index++;
continue;
}
// Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
#endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str());
// Swap with the last element and pop (avoids expensive vector shifts)
if (client_index < this->clients_.size() - 1) {
std::swap(this->clients_[client_index], this->clients_.back());
}
this->clients_.pop_back();
// Schedule reboot when last client disconnects
if (this->clients_.empty() && this->reboot_timeout_ != 0) {
this->schedule_reboot_timeout_();
}
// Don't increment client_index since we need to process the swapped element
}
}
@@ -408,7 +433,7 @@ void APIServer::set_port(uint16_t port) { this->port_ = port; }
void APIServer::set_password(const std::string &password) { this->password_ = password; }
void APIServer::set_batch_delay(uint32_t batch_delay) { this->batch_delay_ = batch_delay; }
void APIServer::set_batch_delay(uint16_t batch_delay) { this->batch_delay_ = batch_delay; }
void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
for (auto &client : this->clients_) {
@@ -479,7 +504,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
#ifdef USE_HOMEASSISTANT_TIME
void APIServer::request_time() {
for (auto &client : this->clients_) {
if (!client->remove_ && client->is_authenticated())
if (!client->flags_.remove && client->is_authenticated())
client->send_time_request();
}
}
@@ -503,8 +528,8 @@ void APIServer::on_shutdown() {
for (auto &c : this->clients_) {
if (!c->send_message(DisconnectRequest())) {
// If we can't send the disconnect request directly (tx_buffer full),
// schedule it in the batch so it will be sent with the 5ms timer
c->schedule_message_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
// schedule it at the front of the batch so it will be sent with priority
c->schedule_message_front_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
}
}
}

View File

@@ -40,8 +40,8 @@ class APIServer : public Component, public Controller {
void set_port(uint16_t port);
void set_password(const std::string &password);
void set_reboot_timeout(uint32_t reboot_timeout);
void set_batch_delay(uint32_t batch_delay);
uint32_t get_batch_delay() const { return batch_delay_; }
void set_batch_delay(uint16_t batch_delay);
uint16_t get_batch_delay() const { return batch_delay_; }
// Get reference to shared buffer for API connections
std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; }
@@ -105,7 +105,18 @@ class APIServer : public Component, public Controller {
void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif
void send_homeassistant_service_call(const HomeassistantServiceResponse &call);
void register_user_service(UserServiceDescriptor *descriptor) { this->user_services_.push_back(descriptor); }
void register_user_service(UserServiceDescriptor *descriptor) {
#ifdef USE_API_YAML_SERVICES
// Vector is pre-allocated when services are defined in YAML
this->user_services_.push_back(descriptor);
#else
// Lazy allocate vector on first use for CustomAPIDevice
if (!this->user_services_) {
this->user_services_ = std::make_unique<std::vector<UserServiceDescriptor *>>();
}
this->user_services_->push_back(descriptor);
#endif
}
#ifdef USE_HOMEASSISTANT_TIME
void request_time();
#endif
@@ -134,35 +145,58 @@ class APIServer : public Component, public Controller {
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f);
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const;
const std::vector<UserServiceDescriptor *> &get_user_services() const { return this->user_services_; }
const std::vector<UserServiceDescriptor *> &get_user_services() const {
#ifdef USE_API_YAML_SERVICES
return this->user_services_;
#else
static const std::vector<UserServiceDescriptor *> EMPTY;
return this->user_services_ ? *this->user_services_ : EMPTY;
#endif
}
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->client_connected_trigger_; }
#endif
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
Trigger<std::string, std::string> *get_client_disconnected_trigger() const {
return this->client_disconnected_trigger_;
}
#endif
protected:
void schedule_reboot_timeout_();
// Pointers and pointer-like types first (4 bytes each)
std::unique_ptr<socket::Socket> socket_ = nullptr;
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>();
#endif
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
#endif
// 4-byte aligned types
uint32_t reboot_timeout_{300000};
uint32_t batch_delay_{100};
uint32_t last_connected_{0};
// Vectors and strings (12 bytes each on 32-bit)
std::vector<std::unique_ptr<APIConnection>> clients_;
std::string password_;
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
std::vector<HomeAssistantStateSubscription> state_subs_;
#ifdef USE_API_YAML_SERVICES
// When services are defined in YAML, we know at compile time that services will be registered
std::vector<UserServiceDescriptor *> user_services_;
#else
// Services can still be registered at runtime by CustomAPIDevice components even when not
// defined in YAML. Using unique_ptr allows lazy allocation, saving 12 bytes in the common
// case where no services (YAML or custom) are used.
std::unique_ptr<std::vector<UserServiceDescriptor *>> user_services_;
#endif
// Group smaller types together
uint16_t port_{6053};
uint16_t batch_delay_{100};
bool shutting_down_ = false;
// 3 bytes used, 1 byte padding
// 5 bytes used, 3 bytes padding
#ifdef USE_API_NOISE
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();

View File

@@ -4,9 +4,15 @@ import asyncio
from datetime import datetime
import logging
from typing import TYPE_CHECKING, Any
import warnings
from aioesphomeapi import APIClient, parse_log_message
from aioesphomeapi.log_runner import async_run
# Suppress protobuf version warnings
with warnings.catch_warnings():
warnings.filterwarnings(
"ignore", category=UserWarning, message=".*Protobuf gencode version.*"
)
from aioesphomeapi import APIClient, parse_log_message
from aioesphomeapi.log_runner import async_run
from esphome.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
from esphome.core import CORE
@@ -29,8 +35,8 @@ async def async_run_logs(config: dict[str, Any], address: str) -> None:
port: int = int(conf[CONF_PORT])
password: str = conf[CONF_PASSWORD]
noise_psk: str | None = None
if CONF_ENCRYPTION in conf:
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY]
if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
noise_psk = key
_LOGGER.info("Starting log output from %s using esphome API", address)
cli = APIClient(
address,

View File

@@ -1,6 +1,7 @@
#include "list_entities.h"
#ifdef USE_API
#include "api_connection.h"
#include "api_pb2.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/util.h"
@@ -8,155 +9,85 @@
namespace esphome {
namespace api {
// Generate entity handler implementations using macros
#ifdef USE_BINARY_SENSOR
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
this->client_->send_binary_sensor_info(binary_sensor);
return true;
}
LIST_ENTITIES_HANDLER(binary_sensor, binary_sensor::BinarySensor, ListEntitiesBinarySensorResponse)
#endif
#ifdef USE_COVER
bool ListEntitiesIterator::on_cover(cover::Cover *cover) {
this->client_->send_cover_info(cover);
return true;
}
LIST_ENTITIES_HANDLER(cover, cover::Cover, ListEntitiesCoverResponse)
#endif
#ifdef USE_FAN
bool ListEntitiesIterator::on_fan(fan::Fan *fan) {
this->client_->send_fan_info(fan);
return true;
}
LIST_ENTITIES_HANDLER(fan, fan::Fan, ListEntitiesFanResponse)
#endif
#ifdef USE_LIGHT
bool ListEntitiesIterator::on_light(light::LightState *light) {
this->client_->send_light_info(light);
return true;
}
LIST_ENTITIES_HANDLER(light, light::LightState, ListEntitiesLightResponse)
#endif
#ifdef USE_SENSOR
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) {
this->client_->send_sensor_info(sensor);
return true;
}
LIST_ENTITIES_HANDLER(sensor, sensor::Sensor, ListEntitiesSensorResponse)
#endif
#ifdef USE_SWITCH
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) {
this->client_->send_switch_info(a_switch);
return true;
}
LIST_ENTITIES_HANDLER(switch, switch_::Switch, ListEntitiesSwitchResponse)
#endif
#ifdef USE_BUTTON
bool ListEntitiesIterator::on_button(button::Button *button) {
this->client_->send_button_info(button);
return true;
}
LIST_ENTITIES_HANDLER(button, button::Button, ListEntitiesButtonResponse)
#endif
#ifdef USE_TEXT_SENSOR
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
this->client_->send_text_sensor_info(text_sensor);
return true;
}
LIST_ENTITIES_HANDLER(text_sensor, text_sensor::TextSensor, ListEntitiesTextSensorResponse)
#endif
#ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) {
this->client_->send_lock_info(a_lock);
return true;
}
LIST_ENTITIES_HANDLER(lock, lock::Lock, ListEntitiesLockResponse)
#endif
#ifdef USE_VALVE
bool ListEntitiesIterator::on_valve(valve::Valve *valve) {
this->client_->send_valve_info(valve);
return true;
}
LIST_ENTITIES_HANDLER(valve, valve::Valve, ListEntitiesValveResponse)
#endif
#ifdef USE_ESP32_CAMERA
LIST_ENTITIES_HANDLER(camera, esp32_camera::ESP32Camera, ListEntitiesCameraResponse)
#endif
#ifdef USE_CLIMATE
LIST_ENTITIES_HANDLER(climate, climate::Climate, ListEntitiesClimateResponse)
#endif
#ifdef USE_NUMBER
LIST_ENTITIES_HANDLER(number, number::Number, ListEntitiesNumberResponse)
#endif
#ifdef USE_DATETIME_DATE
LIST_ENTITIES_HANDLER(date, datetime::DateEntity, ListEntitiesDateResponse)
#endif
#ifdef USE_DATETIME_TIME
LIST_ENTITIES_HANDLER(time, datetime::TimeEntity, ListEntitiesTimeResponse)
#endif
#ifdef USE_DATETIME_DATETIME
LIST_ENTITIES_HANDLER(datetime, datetime::DateTimeEntity, ListEntitiesDateTimeResponse)
#endif
#ifdef USE_TEXT
LIST_ENTITIES_HANDLER(text, text::Text, ListEntitiesTextResponse)
#endif
#ifdef USE_SELECT
LIST_ENTITIES_HANDLER(select, select::Select, ListEntitiesSelectResponse)
#endif
#ifdef USE_MEDIA_PLAYER
LIST_ENTITIES_HANDLER(media_player, media_player::MediaPlayer, ListEntitiesMediaPlayerResponse)
#endif
#ifdef USE_ALARM_CONTROL_PANEL
LIST_ENTITIES_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel,
ListEntitiesAlarmControlPanelResponse)
#endif
#ifdef USE_EVENT
LIST_ENTITIES_HANDLER(event, event::Event, ListEntitiesEventResponse)
#endif
#ifdef USE_UPDATE
LIST_ENTITIES_HANDLER(update, update::UpdateEntity, ListEntitiesUpdateResponse)
#endif
// Special cases that don't follow the pattern
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
auto resp = service->encode_list_service_response();
return this->client_->send_message(resp);
}
#ifdef USE_ESP32_CAMERA
bool ListEntitiesIterator::on_camera(esp32_camera::ESP32Camera *camera) {
this->client_->send_camera_info(camera);
return true;
}
#endif
#ifdef USE_CLIMATE
bool ListEntitiesIterator::on_climate(climate::Climate *climate) {
this->client_->send_climate_info(climate);
return true;
}
#endif
#ifdef USE_NUMBER
bool ListEntitiesIterator::on_number(number::Number *number) {
this->client_->send_number_info(number);
return true;
}
#endif
#ifdef USE_DATETIME_DATE
bool ListEntitiesIterator::on_date(datetime::DateEntity *date) {
this->client_->send_date_info(date);
return true;
}
#endif
#ifdef USE_DATETIME_TIME
bool ListEntitiesIterator::on_time(datetime::TimeEntity *time) {
this->client_->send_time_info(time);
return true;
}
#endif
#ifdef USE_DATETIME_DATETIME
bool ListEntitiesIterator::on_datetime(datetime::DateTimeEntity *datetime) {
this->client_->send_datetime_info(datetime);
return true;
}
#endif
#ifdef USE_TEXT
bool ListEntitiesIterator::on_text(text::Text *text) {
this->client_->send_text_info(text);
return true;
}
#endif
#ifdef USE_SELECT
bool ListEntitiesIterator::on_select(select::Select *select) {
this->client_->send_select_info(select);
return true;
}
#endif
#ifdef USE_MEDIA_PLAYER
bool ListEntitiesIterator::on_media_player(media_player::MediaPlayer *media_player) {
this->client_->send_media_player_info(media_player);
return true;
}
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool ListEntitiesIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
this->client_->send_alarm_control_panel_info(a_alarm_control_panel);
return true;
}
#endif
#ifdef USE_EVENT
bool ListEntitiesIterator::on_event(event::Event *event) {
this->client_->send_event_info(event);
return true;
}
#endif
#ifdef USE_UPDATE
bool ListEntitiesIterator::on_update(update::UpdateEntity *update) {
this->client_->send_update_info(update);
return true;
}
#endif
} // namespace api
} // namespace esphome
#endif

View File

@@ -9,75 +9,83 @@ namespace api {
class APIConnection;
// Macro for generating ListEntitiesIterator handlers
// Calls schedule_message_ with try_send_*_info
#define LIST_ENTITIES_HANDLER(entity_type, EntityClass, ResponseType) \
bool ListEntitiesIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \
return this->client_->schedule_message_(entity, &APIConnection::try_send_##entity_type##_info, \
ResponseType::MESSAGE_TYPE); \
}
class ListEntitiesIterator : public ComponentIterator {
public:
ListEntitiesIterator(APIConnection *client);
#ifdef USE_BINARY_SENSOR
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
bool on_binary_sensor(binary_sensor::BinarySensor *entity) override;
#endif
#ifdef USE_COVER
bool on_cover(cover::Cover *cover) override;
bool on_cover(cover::Cover *entity) override;
#endif
#ifdef USE_FAN
bool on_fan(fan::Fan *fan) override;
bool on_fan(fan::Fan *entity) override;
#endif
#ifdef USE_LIGHT
bool on_light(light::LightState *light) override;
bool on_light(light::LightState *entity) override;
#endif
#ifdef USE_SENSOR
bool on_sensor(sensor::Sensor *sensor) override;
bool on_sensor(sensor::Sensor *entity) override;
#endif
#ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override;
bool on_switch(switch_::Switch *entity) override;
#endif
#ifdef USE_BUTTON
bool on_button(button::Button *button) override;
bool on_button(button::Button *entity) override;
#endif
#ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif
bool on_service(UserServiceDescriptor *service) override;
#ifdef USE_ESP32_CAMERA
bool on_camera(esp32_camera::ESP32Camera *camera) override;
bool on_camera(esp32_camera::ESP32Camera *entity) override;
#endif
#ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override;
bool on_climate(climate::Climate *entity) override;
#endif
#ifdef USE_NUMBER
bool on_number(number::Number *number) override;
bool on_number(number::Number *entity) override;
#endif
#ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override;
bool on_date(datetime::DateEntity *entity) override;
#endif
#ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override;
bool on_time(datetime::TimeEntity *entity) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override;
bool on_datetime(datetime::DateTimeEntity *entity) override;
#endif
#ifdef USE_TEXT
bool on_text(text::Text *text) override;
bool on_text(text::Text *entity) override;
#endif
#ifdef USE_SELECT
bool on_select(select::Select *select) override;
bool on_select(select::Select *entity) override;
#endif
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
bool on_lock(lock::Lock *entity) override;
#endif
#ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override;
bool on_valve(valve::Valve *entity) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override;
bool on_media_player(media_player::MediaPlayer *entity) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override;
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif
#ifdef USE_EVENT
bool on_event(event::Event *event) override;
bool on_event(event::Event *entity) override;
#endif
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
bool on_update(update::UpdateEntity *entity) override;
#endif
bool on_end() override;
bool completed() { return this->state_ == IteratorState::NONE; }

View File

@@ -335,6 +335,7 @@ class ProtoMessage {
#ifdef HAS_PROTO_MESSAGE_DUMP
std::string dump() const;
virtual void dump_to(std::string &out) const = 0;
virtual const char *message_name() const { return "unknown"; }
#endif
protected:
@@ -363,7 +364,7 @@ class ProtoService {
*/
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
virtual bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) = 0;
virtual bool 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, uint8_t *msg_data) = 0;
// Optimized method that pre-allocates buffer based on message size
bool send_message_(const ProtoMessage &msg, uint16_t message_type) {

View File

@@ -6,73 +6,67 @@
namespace esphome {
namespace api {
// Generate entity handler implementations using macros
#ifdef USE_BINARY_SENSOR
bool InitialStateIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) {
return this->client_->send_binary_sensor_state(binary_sensor);
}
INITIAL_STATE_HANDLER(binary_sensor, binary_sensor::BinarySensor)
#endif
#ifdef USE_COVER
bool InitialStateIterator::on_cover(cover::Cover *cover) { return this->client_->send_cover_state(cover); }
INITIAL_STATE_HANDLER(cover, cover::Cover)
#endif
#ifdef USE_FAN
bool InitialStateIterator::on_fan(fan::Fan *fan) { return this->client_->send_fan_state(fan); }
INITIAL_STATE_HANDLER(fan, fan::Fan)
#endif
#ifdef USE_LIGHT
bool InitialStateIterator::on_light(light::LightState *light) { return this->client_->send_light_state(light); }
INITIAL_STATE_HANDLER(light, light::LightState)
#endif
#ifdef USE_SENSOR
bool InitialStateIterator::on_sensor(sensor::Sensor *sensor) { return this->client_->send_sensor_state(sensor); }
INITIAL_STATE_HANDLER(sensor, sensor::Sensor)
#endif
#ifdef USE_SWITCH
bool InitialStateIterator::on_switch(switch_::Switch *a_switch) { return this->client_->send_switch_state(a_switch); }
INITIAL_STATE_HANDLER(switch, switch_::Switch)
#endif
#ifdef USE_TEXT_SENSOR
bool InitialStateIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) {
return this->client_->send_text_sensor_state(text_sensor);
}
INITIAL_STATE_HANDLER(text_sensor, text_sensor::TextSensor)
#endif
#ifdef USE_CLIMATE
bool InitialStateIterator::on_climate(climate::Climate *climate) { return this->client_->send_climate_state(climate); }
INITIAL_STATE_HANDLER(climate, climate::Climate)
#endif
#ifdef USE_NUMBER
bool InitialStateIterator::on_number(number::Number *number) { return this->client_->send_number_state(number); }
INITIAL_STATE_HANDLER(number, number::Number)
#endif
#ifdef USE_DATETIME_DATE
bool InitialStateIterator::on_date(datetime::DateEntity *date) { return this->client_->send_date_state(date); }
INITIAL_STATE_HANDLER(date, datetime::DateEntity)
#endif
#ifdef USE_DATETIME_TIME
bool InitialStateIterator::on_time(datetime::TimeEntity *time) { return this->client_->send_time_state(time); }
INITIAL_STATE_HANDLER(time, datetime::TimeEntity)
#endif
#ifdef USE_DATETIME_DATETIME
bool InitialStateIterator::on_datetime(datetime::DateTimeEntity *datetime) {
return this->client_->send_datetime_state(datetime);
}
INITIAL_STATE_HANDLER(datetime, datetime::DateTimeEntity)
#endif
#ifdef USE_TEXT
bool InitialStateIterator::on_text(text::Text *text) { return this->client_->send_text_state(text); }
INITIAL_STATE_HANDLER(text, text::Text)
#endif
#ifdef USE_SELECT
bool InitialStateIterator::on_select(select::Select *select) { return this->client_->send_select_state(select); }
INITIAL_STATE_HANDLER(select, select::Select)
#endif
#ifdef USE_LOCK
bool InitialStateIterator::on_lock(lock::Lock *a_lock) { return this->client_->send_lock_state(a_lock); }
INITIAL_STATE_HANDLER(lock, lock::Lock)
#endif
#ifdef USE_VALVE
bool InitialStateIterator::on_valve(valve::Valve *valve) { return this->client_->send_valve_state(valve); }
INITIAL_STATE_HANDLER(valve, valve::Valve)
#endif
#ifdef USE_MEDIA_PLAYER
bool InitialStateIterator::on_media_player(media_player::MediaPlayer *media_player) {
return this->client_->send_media_player_state(media_player);
}
INITIAL_STATE_HANDLER(media_player, media_player::MediaPlayer)
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool InitialStateIterator::on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) {
return this->client_->send_alarm_control_panel_state(a_alarm_control_panel);
}
INITIAL_STATE_HANDLER(alarm_control_panel, alarm_control_panel::AlarmControlPanel)
#endif
#ifdef USE_UPDATE
bool InitialStateIterator::on_update(update::UpdateEntity *update) { return this->client_->send_update_state(update); }
INITIAL_STATE_HANDLER(update, update::UpdateEntity)
#endif
// Special cases (button and event) are already defined inline in subscribe_state.h
InitialStateIterator::InitialStateIterator(APIConnection *client) : client_(client) {}
} // namespace api

View File

@@ -10,71 +10,78 @@ namespace api {
class APIConnection;
// Macro for generating InitialStateIterator handlers
// Calls send_*_state
#define INITIAL_STATE_HANDLER(entity_type, EntityClass) \
bool InitialStateIterator::on_##entity_type(EntityClass *entity) { /* NOLINT(bugprone-macro-parentheses) */ \
return this->client_->send_##entity_type##_state(entity); \
}
class InitialStateIterator : public ComponentIterator {
public:
InitialStateIterator(APIConnection *client);
#ifdef USE_BINARY_SENSOR
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override;
bool on_binary_sensor(binary_sensor::BinarySensor *entity) override;
#endif
#ifdef USE_COVER
bool on_cover(cover::Cover *cover) override;
bool on_cover(cover::Cover *entity) override;
#endif
#ifdef USE_FAN
bool on_fan(fan::Fan *fan) override;
bool on_fan(fan::Fan *entity) override;
#endif
#ifdef USE_LIGHT
bool on_light(light::LightState *light) override;
bool on_light(light::LightState *entity) override;
#endif
#ifdef USE_SENSOR
bool on_sensor(sensor::Sensor *sensor) override;
bool on_sensor(sensor::Sensor *entity) override;
#endif
#ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override;
bool on_switch(switch_::Switch *entity) override;
#endif
#ifdef USE_BUTTON
bool on_button(button::Button *button) override { return true; };
#endif
#ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override;
bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif
#ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override;
bool on_climate(climate::Climate *entity) override;
#endif
#ifdef USE_NUMBER
bool on_number(number::Number *number) override;
bool on_number(number::Number *entity) override;
#endif
#ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override;
bool on_date(datetime::DateEntity *entity) override;
#endif
#ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override;
bool on_time(datetime::TimeEntity *entity) override;
#endif
#ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override;
bool on_datetime(datetime::DateTimeEntity *entity) override;
#endif
#ifdef USE_TEXT
bool on_text(text::Text *text) override;
bool on_text(text::Text *entity) override;
#endif
#ifdef USE_SELECT
bool on_select(select::Select *select) override;
bool on_select(select::Select *entity) override;
#endif
#ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override;
bool on_lock(lock::Lock *entity) override;
#endif
#ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override;
bool on_valve(valve::Valve *entity) override;
#endif
#ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override;
bool on_media_player(media_player::MediaPlayer *entity) override;
#endif
#ifdef USE_ALARM_CONTROL_PANEL
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *a_alarm_control_panel) override;
bool on_alarm_control_panel(alarm_control_panel::AlarmControlPanel *entity) override;
#endif
#ifdef USE_EVENT
bool on_event(event::Event *event) override { return true; };
#endif
#ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override;
bool on_update(update::UpdateEntity *entity) override;
#endif
bool completed() { return this->state_ == IteratorState::NONE; }

View File

@@ -50,7 +50,6 @@ class AS5600Component : public Component, public i2c::I2CDevice {
void setup() override;
void dump_config() override;
/// HARDWARE_LATE setup priority
float get_setup_priority() const override { return setup_priority::DATA; }
// configuration setters
void set_dir_pin(InternalGPIOPin *pin) { this->dir_pin_ = pin; }

View File

@@ -5,6 +5,7 @@ from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_LN882X,
PLATFORM_RTL87XX,
)
from esphome.core import CORE, coroutine_with_priority
@@ -14,7 +15,15 @@ CODEOWNERS = ["@OttoWinter"]
CONFIG_SCHEMA = cv.All(
cv.Schema({}),
cv.only_with_arduino,
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]),
cv.only_on(
[
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_LN882X,
PLATFORM_RTL87XX,
]
),
)

View File

@@ -25,7 +25,6 @@ class ATCMiThermometer : public Component, public esp32_ble_tracker::ESPBTDevice
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }

View File

@@ -1,6 +1,7 @@
#include "atm90e32.h"
#include <cinttypes>
#include <cmath>
#include <numbers>
#include "esphome/core/log.h"
namespace esphome {
@@ -848,7 +849,7 @@ uint16_t ATM90E32Component::calculate_voltage_threshold(int line_freq, uint16_t
float nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
float target_voltage = nominal_voltage * multiplier;
float peak_01v = target_voltage * 100.0f * std::sqrt(2.0f); // convert RMS → peak, scale to 0.01V
float peak_01v = target_voltage * 100.0f * std::numbers::sqrt2_v<float>; // convert RMS → peak, scale to 0.01V
float divider = (2.0f * ugain) / 32768.0f;
float threshold = peak_01v / divider;

View File

@@ -312,7 +312,7 @@ FileDecoderState AudioDecoder::decode_mp3_() {
if (err) {
switch (err) {
case esp_audio_libs::helix_decoder::ERR_MP3_OUT_OF_MEMORY:
// Intentional fallthrough
[[fallthrough]];
case esp_audio_libs::helix_decoder::ERR_MP3_NULL_POINTER:
return FileDecoderState::FAILED;
break;

View File

@@ -5,6 +5,7 @@
#include "esphome/core/defines.h"
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
#include "esp_crt_bundle.h"
@@ -16,13 +17,13 @@ namespace audio {
static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
static const uint32_t CONNECTION_TIMEOUT_MS = 5000;
// The number of times the http read times out with no data before throwing an error
static const uint32_t ERROR_COUNT_NO_DATA_READ_TIMEOUT = 100;
static const uint8_t MAX_FETCHING_HEADER_ATTEMPTS = 6;
static const size_t HTTP_STREAM_BUFFER_SIZE = 2048;
static const uint8_t MAX_REDIRECTION = 5;
static const uint8_t MAX_REDIRECTIONS = 5;
static const char *const TAG = "audio_reader";
// Some common HTTP status codes - borrowed from http_request component accessed 20241224
enum HttpStatus {
@@ -94,7 +95,7 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
client_config.url = uri.c_str();
client_config.cert_pem = nullptr;
client_config.disable_auto_redirect = false;
client_config.max_redirection_count = 10;
client_config.max_redirection_count = MAX_REDIRECTIONS;
client_config.event_handler = http_event_handler;
client_config.user_data = this;
client_config.buffer_size = HTTP_STREAM_BUFFER_SIZE;
@@ -116,12 +117,29 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
esp_err_t err = esp_http_client_open(this->client_, 0);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open URL");
this->cleanup_connection_();
return err;
}
int64_t header_length = esp_http_client_fetch_headers(this->client_);
uint8_t reattempt_count = 0;
while ((header_length < 0) && (reattempt_count < MAX_FETCHING_HEADER_ATTEMPTS)) {
this->cleanup_connection_();
if (header_length != -ESP_ERR_HTTP_EAGAIN) {
// Serious error, no recovery
return ESP_FAIL;
} else {
// Reconnect from a fresh state to avoid a bug where it never reads the headers even if made available
this->client_ = esp_http_client_init(&client_config);
esp_http_client_open(this->client_, 0);
header_length = esp_http_client_fetch_headers(this->client_);
++reattempt_count;
}
}
if (header_length < 0) {
ESP_LOGE(TAG, "Failed to fetch headers");
this->cleanup_connection_();
return ESP_FAIL;
}
@@ -135,7 +153,7 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
ssize_t redirect_count = 0;
while ((esp_http_client_set_redirection(this->client_) == ESP_OK) && (redirect_count < MAX_REDIRECTION)) {
while ((esp_http_client_set_redirection(this->client_) == ESP_OK) && (redirect_count < MAX_REDIRECTIONS)) {
err = esp_http_client_open(this->client_, 0);
if (err != ESP_OK) {
this->cleanup_connection_();
@@ -267,27 +285,29 @@ AudioReaderState AudioReader::http_read_() {
return AudioReaderState::FINISHED;
}
} else if (this->output_transfer_buffer_->free() > 0) {
size_t bytes_to_read = this->output_transfer_buffer_->free();
int received_len =
esp_http_client_read(this->client_, (char *) this->output_transfer_buffer_->get_buffer_end(), bytes_to_read);
int received_len = esp_http_client_read(this->client_, (char *) this->output_transfer_buffer_->get_buffer_end(),
this->output_transfer_buffer_->free());
if (received_len > 0) {
this->output_transfer_buffer_->increase_buffer_length(received_len);
this->last_data_read_ms_ = millis();
} else if (received_len < 0) {
return AudioReaderState::READING;
} else if (received_len <= 0) {
// HTTP read error
this->cleanup_connection_();
return AudioReaderState::FAILED;
} else {
if (bytes_to_read > 0) {
// Read timed out
if ((millis() - this->last_data_read_ms_) > CONNECTION_TIMEOUT_MS) {
this->cleanup_connection_();
return AudioReaderState::FAILED;
}
delay(READ_WRITE_TIMEOUT_MS);
if (received_len == -1) {
// A true connection error occured, no chance at recovery
this->cleanup_connection_();
return AudioReaderState::FAILED;
}
// Read timed out, manually verify if it has been too long since the last successful read
if ((millis() - this->last_data_read_ms_) > MAX_FETCHING_HEADER_ATTEMPTS * CONNECTION_TIMEOUT_MS) {
ESP_LOGE(TAG, "Timed out");
this->cleanup_connection_();
return AudioReaderState::FAILED;
}
delay(READ_WRITE_TIMEOUT_MS);
}
}

View File

@@ -16,7 +16,6 @@ class BParasite : public Component, public esp32_ble_tracker::ESPBTDeviceListene
bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }

View File

@@ -148,6 +148,7 @@ BinarySensorCondition = binary_sensor_ns.class_("BinarySensorCondition", Conditi
# Filters
Filter = binary_sensor_ns.class_("Filter")
TimeoutFilter = binary_sensor_ns.class_("TimeoutFilter", Filter, cg.Component)
DelayedOnOffFilter = binary_sensor_ns.class_("DelayedOnOffFilter", Filter, cg.Component)
DelayedOnFilter = binary_sensor_ns.class_("DelayedOnFilter", Filter, cg.Component)
DelayedOffFilter = binary_sensor_ns.class_("DelayedOffFilter", Filter, cg.Component)
@@ -171,6 +172,19 @@ async def invert_filter_to_code(config, filter_id):
return cg.new_Pvariable(filter_id)
@register_filter(
"timeout",
TimeoutFilter,
cv.templatable(cv.positive_time_period_milliseconds),
)
async def timeout_filter_to_code(config, filter_id):
var = cg.new_Pvariable(filter_id)
await cg.register_component(var, {})
template_ = await cg.templatable(config, [], cg.uint32)
cg.add(var.set_timeout_value(template_))
return var
@register_filter(
"delayed_on_off",
DelayedOnOffFilter,

View File

@@ -25,6 +25,12 @@ void Filter::input(bool value) {
}
}
void TimeoutFilter::input(bool value) {
this->set_timeout("timeout", this->timeout_delay_.value(), [this]() { this->parent_->invalidate_state(); });
// we do not de-dup here otherwise changes from invalid to valid state will not be output
this->output(value);
}
optional<bool> DelayedOnOffFilter::new_value(bool value) {
if (value) {
this->set_timeout("ON_OFF", this->on_delay_.value(), [this]() { this->output(true); });

View File

@@ -16,7 +16,7 @@ class Filter {
public:
virtual optional<bool> new_value(bool value) = 0;
void input(bool value);
virtual void input(bool value);
void output(bool value);
@@ -28,6 +28,16 @@ class Filter {
Deduplicator<bool> dedup_;
};
class TimeoutFilter : public Filter, public Component {
public:
optional<bool> new_value(bool value) override { return value; }
void input(bool value) override;
template<typename T> void set_timeout_value(T timeout) { this->timeout_delay_ = timeout; }
protected:
TemplatableValue<uint32_t> timeout_delay_{};
};
class DelayedOnOffFilter : public Filter, public Component {
public:
optional<bool> new_value(bool value) override;

View File

@@ -16,7 +16,6 @@ class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, publi
public:
void dump_config() override;
void loop() override {}
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@@ -18,7 +18,6 @@ class BLEClientRSSISensor : public sensor::Sensor, public PollingComponent, publ
void loop() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) override;

View File

@@ -24,7 +24,6 @@ class BLESensor : public sensor::Sensor, public PollingComponent, public BLEClie
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@@ -19,7 +19,6 @@ class BLEClientSwitch : public switch_::Switch, public Component, public BLEClie
void loop() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void write_state(bool state) override;

View File

@@ -20,7 +20,6 @@ class BLETextSensor : public text_sensor::TextSensor, public PollingComponent, p
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_service_uuid16(uint16_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint16(uuid); }
void set_service_uuid32(uint32_t uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_uint32(uuid); }
void set_service_uuid128(uint8_t *uuid) { this->service_uuid_ = espbt::ESPBTUUID::from_raw(uuid); }

View File

@@ -105,7 +105,6 @@ class BLEPresenceDevice : public binary_sensor::BinarySensorInitiallyOff,
this->set_found_(false);
}
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void set_found_(bool state) {

View File

@@ -99,7 +99,6 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
return false;
}
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID };

View File

@@ -29,7 +29,6 @@ class BLEScanner : public text_sensor::TextSensor, public esp32_ble_tracker::ESP
return true;
}
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
};
} // namespace ble_scanner

View File

@@ -61,8 +61,6 @@ enum IIRFilter {
class BMP581Component : public PollingComponent, public i2c::I2CDevice {
public:
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
void setup() override;

View File

@@ -46,7 +46,6 @@ class CAP1188Component : public Component, public i2c::I2CDevice {
void set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void loop() override;
protected:

View File

@@ -7,6 +7,7 @@ from esphome.const import (
PLATFORM_BK72XX,
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_LN882X,
PLATFORM_RTL87XX,
)
from esphome.core import CORE, coroutine_with_priority
@@ -27,7 +28,15 @@ CONFIG_SCHEMA = cv.All(
),
}
).extend(cv.COMPONENT_SCHEMA),
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266, PLATFORM_BK72XX, PLATFORM_RTL87XX]),
cv.only_on(
[
PLATFORM_ESP32,
PLATFORM_ESP8266,
PLATFORM_BK72XX,
PLATFORM_LN882X,
PLATFORM_RTL87XX,
]
),
)

View File

@@ -47,7 +47,9 @@ void CaptivePortal::start() {
this->base_->init();
if (!this->initialized_) {
this->base_->add_handler(this);
#ifdef USE_WEBSERVER_OTA
this->base_->add_ota_handler();
#endif
}
#ifdef USE_ARDUINO

View File

@@ -25,8 +25,6 @@ class CCS811Component : public PollingComponent, public i2c::I2CDevice {
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
optional<uint8_t> read_status_() { return this->read_byte(0x00); }
bool status_has_error_() { return this->read_status_().value_or(1) & 1; }

View File

@@ -11,7 +11,6 @@ class CopyBinarySensor : public binary_sensor::BinarySensor, public Component {
void set_source(binary_sensor::BinarySensor *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
binary_sensor::BinarySensor *source_;

View File

@@ -10,7 +10,6 @@ class CopyButton : public button::Button, public Component {
public:
void set_source(button::Button *source) { source_ = source; }
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void press_action() override;

View File

@@ -11,7 +11,6 @@ class CopyCover : public cover::Cover, public Component {
void set_source(cover::Cover *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override;

View File

@@ -11,7 +11,6 @@ class CopyFan : public fan::Fan, public Component {
void set_source(fan::Fan *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
fan::FanTraits get_traits() override;

View File

@@ -11,7 +11,6 @@ class CopyLock : public lock::Lock, public Component {
void set_source(lock::Lock *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void control(const lock::LockCall &call) override;

View File

@@ -11,7 +11,6 @@ class CopyNumber : public number::Number, public Component {
void set_source(number::Number *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void control(float value) override;

View File

@@ -11,7 +11,6 @@ class CopySelect : public select::Select, public Component {
void set_source(select::Select *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void control(const std::string &value) override;

View File

@@ -11,7 +11,6 @@ class CopySensor : public sensor::Sensor, public Component {
void set_source(sensor::Sensor *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
sensor::Sensor *source_;

View File

@@ -11,7 +11,6 @@ class CopySwitch : public switch_::Switch, public Component {
void set_source(switch_::Switch *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void write_state(bool state) override;

View File

@@ -11,7 +11,6 @@ class CopyText : public text::Text, public Component {
void set_source(text::Text *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void control(const std::string &value) override;

View File

@@ -11,7 +11,6 @@ class CopyTextSensor : public text_sensor::TextSensor, public Component {
void set_source(text_sensor::TextSensor *source) { source_ = source; }
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
text_sensor::TextSensor *source_;

View File

@@ -77,7 +77,6 @@ class CS5460AComponent : public Component,
void setup() override;
void loop() override {}
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
protected:

View File

@@ -1,5 +1,6 @@
#include "display.h"
#include <utility>
#include <numbers>
#include "display_color_utils.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
@@ -424,15 +425,15 @@ void HOT Display::get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *
// hence we rotate the shape by 270° to orient the polygon up.
rotation_degrees += ROTATION_270_DEGREES;
// Convert the rotation to radians, easier to use in trigonometrical calculations
float rotation_radians = rotation_degrees * PI / 180;
float rotation_radians = rotation_degrees * std::numbers::pi / 180;
// A pointy top variation means the first vertex of the polygon is at the top center of the shape, this requires no
// additional rotation of the shape.
// A flat top variation means the first point of the polygon has to be rotated so that the first edge is horizontal,
// this requires to rotate the shape by π/edges radians counter-clockwise so that the first point is located on the
// left side of the first horizontal edge.
rotation_radians -= (variation == VARIATION_FLAT_TOP) ? PI / edges : 0.0;
rotation_radians -= (variation == VARIATION_FLAT_TOP) ? std::numbers::pi / edges : 0.0;
float vertex_angle = ((float) vertex_id) / edges * 2 * PI + rotation_radians;
float vertex_angle = ((float) vertex_id) / edges * 2 * std::numbers::pi + rotation_radians;
*vertex_x = (int) round(cos(vertex_angle) * radius) + center_x;
*vertex_y = (int) round(sin(vertex_angle) * radius) + center_y;
}

View File

@@ -138,8 +138,6 @@ enum DisplayRotation {
DISPLAY_ROTATION_270_DEGREES = 270,
};
#define PI 3.1415926535897932384626433832795
const int EDGES_TRIGON = 3;
const int EDGES_TRIANGLE = 3;
const int EDGES_TETRAGON = 4;

View File

@@ -19,7 +19,6 @@ class DutyTimeSensor : public sensor::Sensor, public PollingComponent {
void update() override;
void loop() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void start();
void stop();

View File

@@ -18,7 +18,6 @@ class ENS160Component : public PollingComponent, public sensor::Sensor {
void setup() override;
void update() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected:
void send_env_data_();

View File

@@ -25,7 +25,6 @@ class ES7210 : public audio_adc::AudioAdc, public Component, public i2c::I2CDevi
*/
public:
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
void set_bits_per_sample(ES7210BitsPerSample bits_per_sample) { this->bits_per_sample_ = bits_per_sample; }

View File

@@ -14,7 +14,6 @@ class ES7243E : public audio_adc::AudioAdc, public Component, public i2c::I2CDev
*/
public:
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
bool set_mic_gain(float mic_gain) override;

View File

@@ -14,7 +14,6 @@ class ES8156 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
/////////////////////////
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
////////////////////////

View File

@@ -50,7 +50,6 @@ class ES8311 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
/////////////////////////
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
////////////////////////

View File

@@ -38,7 +38,6 @@ class ES8388 : public audio_dac::AudioDac, public Component, public i2c::I2CDevi
/////////////////////////
void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void dump_config() override;
////////////////////////

View File

@@ -4,7 +4,7 @@ import logging
import os
from pathlib import Path
from esphome import git
from esphome import yaml_util
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import (
@@ -23,7 +23,6 @@ from esphome.const import (
CONF_REFRESH,
CONF_SOURCE,
CONF_TYPE,
CONF_URL,
CONF_VARIANT,
CONF_VERSION,
KEY_CORE,
@@ -32,14 +31,13 @@ from esphome.const import (
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PLATFORM_ESP32,
TYPE_GIT,
TYPE_LOCAL,
__version__,
)
from esphome.core import CORE, HexInt, TimePeriod
from esphome.cpp_generator import RawExpression
import esphome.final_validate as fv
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
from esphome.types import ConfigType
from .boards import BOARDS
from .const import ( # noqa
@@ -49,10 +47,8 @@ from .const import ( # noqa
KEY_EXTRA_BUILD_FILES,
KEY_PATH,
KEY_REF,
KEY_REFRESH,
KEY_REPO,
KEY_SDKCONFIG_OPTIONS,
KEY_SUBMODULES,
KEY_VARIANT,
VARIANT_ESP32,
VARIANT_ESP32C2,
@@ -235,7 +231,7 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType):
def add_idf_component(
*,
name: str,
repo: str,
repo: str = None,
ref: str = None,
path: str = None,
refresh: TimePeriod = None,
@@ -245,30 +241,27 @@ def add_idf_component(
"""Add an esp-idf component to the project."""
if not CORE.using_esp_idf:
raise ValueError("Not an esp-idf project")
if components is None:
components = []
if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]:
if not repo and not ref and not path:
raise ValueError("Requires at least one of repo, ref or path")
if refresh or submodules or components:
_LOGGER.warning(
"The refresh, components and submodules parameters in add_idf_component() are "
"deprecated and will be removed in ESPHome 2026.1. If you are seeing this, report "
"an issue to the external_component author and ask them to update it."
)
if components:
for comp in components:
CORE.data[KEY_ESP32][KEY_COMPONENTS][comp] = {
KEY_REPO: repo,
KEY_REF: ref,
KEY_PATH: f"{path}/{comp}" if path else comp,
}
else:
CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = {
KEY_REPO: repo,
KEY_REF: ref,
KEY_PATH: path,
KEY_REFRESH: refresh,
KEY_COMPONENTS: components,
KEY_SUBMODULES: submodules,
}
else:
component_config = CORE.data[KEY_ESP32][KEY_COMPONENTS][name]
if components is not None:
component_config[KEY_COMPONENTS] = list(
set(component_config[KEY_COMPONENTS] + components)
)
if submodules is not None:
if component_config[KEY_SUBMODULES] is None:
component_config[KEY_SUBMODULES] = submodules
else:
component_config[KEY_SUBMODULES] = list(
set(component_config[KEY_SUBMODULES] + submodules)
)
def add_extra_script(stage: str, filename: str, path: str):
@@ -348,6 +341,7 @@ SUPPORTED_PLATFORMIO_ESP_IDF_5X = [
# List based on https://github.com/pioarduino/esp-idf/releases
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
cv.Version(5, 5, 0),
cv.Version(5, 4, 2),
cv.Version(5, 4, 1),
cv.Version(5, 4, 0),
cv.Version(5, 3, 3),
@@ -417,8 +411,8 @@ def _esp_idf_check_versions(value):
version = cv.Version.parse(cv.version_number(value[CONF_VERSION]))
source = value.get(CONF_SOURCE, None)
if version < cv.Version(4, 0, 0):
raise cv.Invalid("Only ESP-IDF 4.0+ is supported.")
if version < cv.Version(5, 0, 0):
raise cv.Invalid("Only ESP-IDF 5.0+ is supported.")
# flag this for later *before* we set value[CONF_PLATFORM_VERSION] below
has_platform_ver = CONF_PLATFORM_VERSION in value
@@ -428,20 +422,15 @@ def _esp_idf_check_versions(value):
)
if (
(is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION]))
and version.major >= 5
and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X
):
is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])
) and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X:
raise cv.Invalid(
f"ESP-IDF {str(version)} not supported by platformio/espressif32"
)
if (
version.major < 5
or (
version in SUPPORTED_PLATFORMIO_ESP_IDF_5X
and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X
)
version in SUPPORTED_PLATFORMIO_ESP_IDF_5X
and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X
) and not has_platform_ver:
raise cv.Invalid(
f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'"
@@ -575,6 +564,17 @@ CONF_ENABLE_LWIP_DHCP_SERVER = "enable_lwip_dhcp_server"
CONF_ENABLE_LWIP_MDNS_QUERIES = "enable_lwip_mdns_queries"
CONF_ENABLE_LWIP_BRIDGE_INTERFACE = "enable_lwip_bridge_interface"
def _validate_idf_component(config: ConfigType) -> ConfigType:
"""Validate IDF component config and warn about deprecated options."""
if CONF_REFRESH in config:
_LOGGER.warning(
"The 'refresh' option for IDF components is deprecated and has no effect. "
"It will be removed in ESPHome 2026.1. Please remove it from your configuration."
)
return config
ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
cv.Schema(
{
@@ -606,7 +606,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
CONF_ENABLE_LWIP_DHCP_SERVER, "wifi", default=False
): cv.boolean,
cv.Optional(
CONF_ENABLE_LWIP_MDNS_QUERIES, default=False
CONF_ENABLE_LWIP_MDNS_QUERIES, default=True
): cv.boolean,
cv.Optional(
CONF_ENABLE_LWIP_BRIDGE_INTERFACE, default=False
@@ -614,15 +614,19 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
}
),
cv.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
cv.Schema(
{
cv.Required(CONF_NAME): cv.string_strict,
cv.Required(CONF_SOURCE): cv.SOURCE_SCHEMA,
cv.Optional(CONF_PATH): cv.string,
cv.Optional(CONF_REFRESH, default="1d"): cv.All(
cv.string, cv.source_refresh
),
}
cv.All(
cv.Schema(
{
cv.Required(CONF_NAME): cv.string_strict,
cv.Optional(CONF_SOURCE): cv.git_ref,
cv.Optional(CONF_REF): cv.string,
cv.Optional(CONF_PATH): cv.string,
cv.Optional(CONF_REFRESH): cv.All(
cv.string, cv.source_refresh
),
}
),
_validate_idf_component,
)
),
}
@@ -696,7 +700,7 @@ FINAL_VALIDATE_SCHEMA = cv.Schema(final_validate)
async def to_code(config):
cg.add_platformio_option("board", config[CONF_BOARD])
cg.add_platformio_option("board_upload.flash_size", config[CONF_FLASH_SIZE])
cg.set_cpp_standard("gnu++17")
cg.set_cpp_standard("gnu++20")
cg.add_build_flag("-DUSE_ESP32")
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}")
@@ -750,6 +754,9 @@ async def to_code(config):
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0", False)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", False)
# Disable dynamic log level control to save memory
add_idf_sdkconfig_option("CONFIG_LOG_DYNAMIC_LEVEL_CONTROL", False)
# Set default CPU frequency
add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True)
@@ -762,7 +769,7 @@ async def to_code(config):
and not advanced[CONF_ENABLE_LWIP_DHCP_SERVER]
):
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False)
if not advanced.get(CONF_ENABLE_LWIP_MDNS_QUERIES, False):
if not advanced.get(CONF_ENABLE_LWIP_MDNS_QUERIES, True):
add_idf_sdkconfig_option("CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES", False)
if not advanced.get(CONF_ENABLE_LWIP_BRIDGE_INTERFACE, False):
add_idf_sdkconfig_option("CONFIG_LWIP_BRIDGEIF_MAX_PORTS", 0)
@@ -789,14 +796,9 @@ async def to_code(config):
if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC):
add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True)
if (framework_ver.major, framework_ver.minor) >= (4, 4):
add_idf_sdkconfig_option(
"CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False
)
else:
add_idf_sdkconfig_option(
"CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False
)
add_idf_sdkconfig_option(
"CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False
)
if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES):
_LOGGER.warning(
"Using experimental features in ESP-IDF may result in unexpected failures."
@@ -814,18 +816,12 @@ async def to_code(config):
add_idf_sdkconfig_option(name, RawSdkconfigValue(value))
for component in conf[CONF_COMPONENTS]:
source = component[CONF_SOURCE]
if source[CONF_TYPE] == TYPE_GIT:
add_idf_component(
name=component[CONF_NAME],
repo=source[CONF_URL],
ref=source.get(CONF_REF),
path=component.get(CONF_PATH),
refresh=component[CONF_REFRESH],
)
elif source[CONF_TYPE] == TYPE_LOCAL:
_LOGGER.warning("Local components are not implemented yet.")
add_idf_component(
name=component[CONF_NAME],
repo=component.get(CONF_SOURCE),
ref=component.get(CONF_REF),
path=component.get(CONF_PATH),
)
elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO:
cg.add_platformio_option("framework", "arduino")
cg.add_build_flag("-DUSE_ARDUINO")
@@ -924,6 +920,26 @@ def _write_sdkconfig():
write_file_if_changed(sdk_path, contents)
def _write_idf_component_yml():
yml_path = Path(CORE.relative_build_path("src/idf_component.yml"))
if CORE.data[KEY_ESP32][KEY_COMPONENTS]:
components: dict = CORE.data[KEY_ESP32][KEY_COMPONENTS]
dependencies = {}
for name, component in components.items():
dependency = {}
if component[KEY_REF]:
dependency["version"] = component[KEY_REF]
if component[KEY_REPO]:
dependency["git"] = component[KEY_REPO]
if component[KEY_PATH]:
dependency["path"] = component[KEY_PATH]
dependencies[name] = dependency
contents = yaml_util.dump({"dependencies": dependencies})
else:
contents = ""
write_file_if_changed(yml_path, contents)
# Called by writer.py
def copy_files():
if CORE.using_arduino:
@@ -936,6 +952,7 @@ def copy_files():
)
if CORE.using_esp_idf:
_write_sdkconfig()
_write_idf_component_yml()
if "partitions.csv" not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]:
write_file_if_changed(
CORE.relative_build_path("partitions.csv"),
@@ -952,55 +969,6 @@ def copy_files():
__version__,
)
import shutil
shutil.rmtree(CORE.relative_build_path("components"), ignore_errors=True)
if CORE.data[KEY_ESP32][KEY_COMPONENTS]:
components: dict = CORE.data[KEY_ESP32][KEY_COMPONENTS]
for name, component in components.items():
repo_dir, _ = git.clone_or_update(
url=component[KEY_REPO],
ref=component[KEY_REF],
refresh=component[KEY_REFRESH],
domain="idf_components",
submodules=component[KEY_SUBMODULES],
)
mkdir_p(CORE.relative_build_path("components"))
component_dir = repo_dir
if component[KEY_PATH] is not None:
component_dir = component_dir / component[KEY_PATH]
if component[KEY_COMPONENTS] == ["*"]:
shutil.copytree(
component_dir,
CORE.relative_build_path("components"),
dirs_exist_ok=True,
ignore=shutil.ignore_patterns(".git*"),
symlinks=True,
ignore_dangling_symlinks=True,
)
elif len(component[KEY_COMPONENTS]) > 0:
for comp in component[KEY_COMPONENTS]:
shutil.copytree(
component_dir / comp,
CORE.relative_build_path(f"components/{comp}"),
dirs_exist_ok=True,
ignore=shutil.ignore_patterns(".git*"),
symlinks=True,
ignore_dangling_symlinks=True,
)
else:
shutil.copytree(
component_dir,
CORE.relative_build_path(f"components/{name}"),
dirs_exist_ok=True,
ignore=shutil.ignore_patterns(".git*"),
symlinks=True,
ignore_dangling_symlinks=True,
)
for _, file in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES].items():
if file[KEY_PATH].startswith("http"):
import requests

View File

@@ -56,11 +56,7 @@ void arch_init() {
void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; }
#if ESP_IDF_VERSION_MAJOR >= 5
uint32_t arch_get_cpu_cycle_count() { return esp_cpu_get_cycle_count(); }
#else
uint32_t arch_get_cpu_cycle_count() { return cpu_hal_get_cycle_count(); }
#endif
uint32_t arch_get_cpu_freq_hz() {
uint32_t freq = 0;
#ifdef USE_ESP_IDF

View File

@@ -29,9 +29,9 @@ class ESP32InternalGPIOPin : public InternalGPIOPin {
void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
gpio_num_t pin_;
bool inverted_;
gpio_drive_cap_t drive_strength_;
gpio::Flags flags_;
bool inverted_;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static bool isr_service_installed;
};

View File

@@ -1,9 +1,9 @@
#ifdef USE_ESP32
#include "ble.h"
#include "ble_event_pool.h"
#include "esphome/core/application.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include <esp_bt.h>
@@ -516,13 +516,12 @@ void ESP32BLE::dump_config() {
break;
}
ESP_LOGCONFIG(TAG,
"ESP32 BLE:\n"
" MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n"
"BLE:\n"
" MAC address: %s\n"
" IO Capability: %s",
mac_address[0], mac_address[1], mac_address[2], mac_address[3], mac_address[4], mac_address[5],
io_capability_s);
format_mac_address_pretty(mac_address).c_str(), io_capability_s);
} else {
ESP_LOGCONFIG(TAG, "ESP32 BLE: bluetooth stack is not enabled");
ESP_LOGCONFIG(TAG, "Bluetooth stack is not enabled");
}
}

View File

@@ -12,8 +12,8 @@
#include "esphome/core/helpers.h"
#include "ble_event.h"
#include "ble_event_pool.h"
#include "queue.h"
#include "esphome/core/lock_free_queue.h"
#include "esphome/core/event_pool.h"
#ifdef USE_ESP32
@@ -148,8 +148,8 @@ class ESP32BLE : public Component {
std::vector<BLEStatusEventHandler *> ble_status_event_handlers_;
BLEComponentState state_{BLE_COMPONENT_STATE_OFF};
LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_;
BLEEventPool<MAX_BLE_QUEUE_SIZE> ble_event_pool_;
esphome::LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_;
esphome::EventPool<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_event_pool_;
BLEAdvertising *advertising_{};
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
uint32_t advertising_cycle_time_{};

View File

@@ -134,13 +134,13 @@ class BLEEvent {
}
// Destructor to clean up heap allocations
~BLEEvent() { this->cleanup_heap_data(); }
~BLEEvent() { this->release(); }
// Default constructor for pre-allocation in pool
BLEEvent() : type_(GAP) {}
// Clean up any heap-allocated data
void cleanup_heap_data() {
// Invoked on return to EventPool - clean up any heap-allocated data
void release() {
if (this->type_ == GAP) {
return;
}
@@ -161,19 +161,19 @@ class BLEEvent {
// Load new event data for reuse (replaces previous event data)
void load_gap_event(esp_gap_ble_cb_event_t e, esp_ble_gap_cb_param_t *p) {
this->cleanup_heap_data();
this->release();
this->type_ = GAP;
this->init_gap_data_(e, p);
}
void load_gattc_event(esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
this->cleanup_heap_data();
this->release();
this->type_ = GATTC;
this->init_gattc_data_(e, i, p);
}
void load_gatts_event(esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
this->cleanup_heap_data();
this->release();
this->type_ = GATTS;
this->init_gatts_data_(e, i, p);
}

View File

@@ -1,72 +0,0 @@
#pragma once
#ifdef USE_ESP32
#include <atomic>
#include <cstddef>
#include "ble_event.h"
#include "queue.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace esp32_ble {
// BLE Event Pool - On-demand pool of BLEEvent objects to avoid heap fragmentation
// Events are allocated on first use and reused thereafter, growing to peak usage
template<uint8_t SIZE> class BLEEventPool {
public:
BLEEventPool() : total_created_(0) {}
~BLEEventPool() {
// Clean up any remaining events in the free list
BLEEvent *event;
while ((event = this->free_list_.pop()) != nullptr) {
delete event;
}
}
// Allocate an event from the pool
// Returns nullptr if pool is full
BLEEvent *allocate() {
// Try to get from free list first
BLEEvent *event = this->free_list_.pop();
if (event != nullptr)
return event;
// Need to create a new event
if (this->total_created_ >= SIZE) {
// Pool is at capacity
return nullptr;
}
// Use internal RAM for better performance
RAMAllocator<BLEEvent> allocator(RAMAllocator<BLEEvent>::ALLOC_INTERNAL);
event = allocator.allocate(1);
if (event == nullptr) {
// Memory allocation failed
return nullptr;
}
// Placement new to construct the object
new (event) BLEEvent();
this->total_created_++;
return event;
}
// Return an event to the pool for reuse
void release(BLEEvent *event) {
if (event != nullptr) {
this->free_list_.push(event);
}
}
private:
LockFreeQueue<BLEEvent, SIZE> free_list_; // Free events ready for reuse
uint8_t total_created_; // Total events created (high water mark)
};
} // namespace esp32_ble
} // namespace esphome
#endif

View File

@@ -1,85 +0,0 @@
#pragma once
#ifdef USE_ESP32
#include <atomic>
#include <cstddef>
/*
* BLE events come in from a separate Task (thread) in the ESP32 stack. Rather
* than using mutex-based locking, this lock-free queue allows the BLE
* task to enqueue events without blocking. The main loop() then processes
* these events at a safer time.
*
* This is a Single-Producer Single-Consumer (SPSC) lock-free ring buffer.
* The BLE task is the only producer, and the main loop() is the only consumer.
*/
namespace esphome {
namespace esp32_ble {
template<class T, uint8_t SIZE> class LockFreeQueue {
public:
LockFreeQueue() : head_(0), tail_(0), dropped_count_(0) {}
bool push(T *element) {
if (element == nullptr)
return false;
uint8_t current_tail = tail_.load(std::memory_order_relaxed);
uint8_t next_tail = (current_tail + 1) % SIZE;
if (next_tail == head_.load(std::memory_order_acquire)) {
// Buffer full
dropped_count_.fetch_add(1, std::memory_order_relaxed);
return false;
}
buffer_[current_tail] = element;
tail_.store(next_tail, std::memory_order_release);
return true;
}
T *pop() {
uint8_t current_head = head_.load(std::memory_order_relaxed);
if (current_head == tail_.load(std::memory_order_acquire)) {
return nullptr; // Empty
}
T *element = buffer_[current_head];
head_.store((current_head + 1) % SIZE, std::memory_order_release);
return element;
}
size_t size() const {
uint8_t tail = tail_.load(std::memory_order_acquire);
uint8_t head = head_.load(std::memory_order_acquire);
return (tail - head + SIZE) % SIZE;
}
uint16_t get_and_reset_dropped_count() { return dropped_count_.exchange(0, std::memory_order_relaxed); }
void increment_dropped_count() { dropped_count_.fetch_add(1, std::memory_order_relaxed); }
bool empty() const { return head_.load(std::memory_order_acquire) == tail_.load(std::memory_order_acquire); }
bool full() const {
uint8_t next_tail = (tail_.load(std::memory_order_relaxed) + 1) % SIZE;
return next_tail == head_.load(std::memory_order_acquire);
}
protected:
T *buffer_[SIZE];
// Atomic: written by producer (push/increment), read+reset by consumer (get_and_reset)
std::atomic<uint16_t> dropped_count_; // 65535 max - more than enough for drop tracking
// Atomic: written by consumer (pop), read by producer (push) to check if full
std::atomic<uint8_t> head_;
// Atomic: written by producer (push), read by consumer (pop) to check if empty
std::atomic<uint8_t> tail_;
};
} // namespace esp32_ble
} // namespace esphome
#endif

View File

@@ -496,17 +496,17 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
if (length > 2) {
return (float) encode_uint16(value[1], value[2]);
}
// fall through
[[fallthrough]];
case 0x7: // uint24.
if (length > 3) {
return (float) encode_uint24(value[1], value[2], value[3]);
}
// fall through
[[fallthrough]];
case 0x8: // uint32.
if (length > 4) {
return (float) encode_uint32(value[1], value[2], value[3], value[4]);
}
// fall through
[[fallthrough]];
case 0xC: // int8.
return (float) ((int8_t) value[1]);
case 0xD: // int12.
@@ -514,12 +514,12 @@ float BLEClientBase::parse_char_value(uint8_t *value, uint16_t length) {
if (length > 2) {
return (float) ((int16_t) (value[1] << 8) + (int16_t) value[2]);
}
// fall through
[[fallthrough]];
case 0xF: // int24.
if (length > 3) {
return (float) ((int32_t) (value[1] << 16) + (int32_t) (value[2] << 8) + (int32_t) (value[3]));
}
// fall through
[[fallthrough]];
case 0x10: // int32.
if (length > 4) {
return (float) ((int32_t) (value[1] << 24) + (int32_t) (value[2] << 16) + (int32_t) (value[3] << 8) +

View File

@@ -29,8 +29,6 @@ from esphome.const import (
CONF_ON_BLE_SERVICE_DATA_ADVERTISE,
CONF_SERVICE_UUID,
CONF_TRIGGER_ID,
KEY_CORE,
KEY_FRAMEWORK_VERSION,
)
from esphome.core import CORE
@@ -323,10 +321,7 @@ async def to_code(config):
# https://github.com/espressif/esp-idf/issues/2503
# Match arduino CONFIG_BTU_TASK_STACK_SIZE
# https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866
if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(4, 4, 6):
add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192)
else:
add_idf_sdkconfig_option("CONFIG_BTU_TASK_STACK_SIZE", 8192)
add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192)
add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", 9)
add_idf_sdkconfig_option(
"CONFIG_BTDM_CTRL_BLE_MAX_CONN", config[CONF_MAX_CONNECTIONS]
@@ -335,8 +330,7 @@ async def to_code(config):
# max notifications in 5.x, setting CONFIG_BT_ACL_CONNECTIONS
# is enough in 4.x
# https://github.com/esphome/issues/issues/6808
if CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] >= cv.Version(5, 0, 0):
add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9)
add_idf_sdkconfig_option("CONFIG_BT_GATTC_NOTIF_REG_MAX", 9)
cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts
cg.add_define("USE_ESP32_BLE_CLIENT")

View File

@@ -18,7 +18,7 @@
#include <cinttypes>
#ifdef USE_OTA
#include "esphome/components/ota/ota_backend.h"
#include "esphome/components/ota_base/ota_backend.h"
#endif
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
@@ -61,9 +61,9 @@ void ESP32BLETracker::setup() {
global_esp32_ble_tracker = this;
#ifdef USE_OTA
ota::get_global_ota_callback()->add_on_state_callback(
[this](ota::OTAState state, float progress, uint8_t error, ota::OTAComponent *comp) {
if (state == ota::OTA_STARTED) {
ota_base::get_global_ota_callback()->add_on_state_callback(
[this](ota_base::OTAState state, float progress, uint8_t error, ota_base::OTAComponent *comp) {
if (state == ota_base::OTA_STARTED) {
this->stop_scan();
for (auto *client : this->clients_) {
client->disconnect();

View File

@@ -310,11 +310,7 @@ async def to_code(config):
cg.add_define("USE_ESP32_CAMERA")
if CORE.using_esp_idf:
add_idf_component(
name="esp32-camera",
repo="https://github.com/espressif/esp32-camera.git",
ref="v2.0.15",
)
add_idf_component(name="espressif/esp32-camera", ref="2.0.15")
for conf in config.get(CONF_ON_STREAM_START, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)

View File

@@ -0,0 +1,5 @@
import esphome.config_validation as cv
CONFIG_SCHEMA = cv.invalid(
"The esp32_hall component has been removed as of ESPHome 2025.7.0. See https://github.com/esphome/esphome/pull/9117 for details."
)

View File

@@ -0,0 +1,101 @@
import os
from esphome import pins
from esphome.components import esp32
import esphome.config_validation as cv
from esphome.const import (
CONF_CLK_PIN,
CONF_RESET_PIN,
CONF_VARIANT,
KEY_CORE,
KEY_FRAMEWORK_VERSION,
)
from esphome.core import CORE
CODEOWNERS = ["@swoboda1337"]
CONF_ACTIVE_HIGH = "active_high"
CONF_CMD_PIN = "cmd_pin"
CONF_D0_PIN = "d0_pin"
CONF_D1_PIN = "d1_pin"
CONF_D2_PIN = "d2_pin"
CONF_D3_PIN = "d3_pin"
CONF_SLOT = "slot"
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.Required(CONF_VARIANT): cv.one_of(*esp32.VARIANTS, upper=True),
cv.Required(CONF_ACTIVE_HIGH): cv.boolean,
cv.Required(CONF_CLK_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_CMD_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D0_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D1_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D2_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_D3_PIN): pins.internal_gpio_output_pin_number,
cv.Required(CONF_RESET_PIN): pins.internal_gpio_output_pin_number,
cv.Optional(CONF_SLOT, default=1): cv.int_range(min=0, max=1),
}
),
)
async def to_code(config):
if config[CONF_ACTIVE_HIGH]:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_RESET_ACTIVE_HIGH",
True,
)
else:
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_RESET_ACTIVE_LOW",
True,
)
esp32.add_idf_sdkconfig_option(
"CONFIG_ESP_HOSTED_SDIO_GPIO_RESET_SLAVE", # NOLINT
config[CONF_RESET_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_SLAVE_IDF_TARGET_{config[CONF_VARIANT]}", # NOLINT
True,
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_SDIO_SLOT_{config[CONF_SLOT]}",
True,
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CLK_SLOT_{config[CONF_SLOT]}",
config[CONF_CLK_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_CMD_SLOT_{config[CONF_SLOT]}",
config[CONF_CMD_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D0_SLOT_{config[CONF_SLOT]}",
config[CONF_D0_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D1_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D1_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D2_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D2_PIN],
)
esp32.add_idf_sdkconfig_option(
f"CONFIG_ESP_HOSTED_PRIV_SDIO_PIN_D3_4BIT_BUS_SLOT_{config[CONF_SLOT]}",
config[CONF_D3_PIN],
)
esp32.add_idf_sdkconfig_option("CONFIG_ESP_HOSTED_CUSTOM_SDIO_PINS", True)
framework_ver: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION]
os.environ["ESP_IDF_VERSION"] = f"{framework_ver.major}.{framework_ver.minor}"
esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="0.10.2")
esp32.add_idf_component(name="espressif/eppp_link", ref="0.2.0")
esp32.add_idf_component(name="espressif/esp_hosted", ref="2.0.11")
esp32.add_extra_script(
"post",
"esp32_hosted.py",
os.path.join(os.path.dirname(__file__), "esp32_hosted.py.script"),
)

View File

@@ -0,0 +1,12 @@
# pylint: disable=E0602
Import("env") # noqa
# Workaround whole archive issue
if "__LIB_DEPS" in env and "libespressif__esp_hosted.a" in env["__LIB_DEPS"]:
env.Append(
LINKFLAGS=[
"-Wl,--whole-archive",
env["BUILD_DIR"] + "/esp-idf/espressif__esp_hosted/libespressif__esp_hosted.a",
"-Wl,--no-whole-archive",
]
)

View File

@@ -21,6 +21,43 @@ static const uint32_t RMT_CLK_FREQ = 80000000;
static const uint8_t RMT_CLK_DIV = 2;
#endif
static const size_t RMT_SYMBOLS_PER_BYTE = 8;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size_t symbols_written, size_t symbols_free,
rmt_symbol_word_t *symbols, bool *done, void *arg) {
auto *params = static_cast<LedParams *>(arg);
const auto *bytes = static_cast<const uint8_t *>(data);
size_t index = symbols_written / RMT_SYMBOLS_PER_BYTE;
// convert byte to symbols
if (index < size) {
if (symbols_free < RMT_SYMBOLS_PER_BYTE) {
return 0;
}
for (int32_t i = 0; i < RMT_SYMBOLS_PER_BYTE; i++) {
if (bytes[index] & (1 << (7 - i))) {
symbols[i] = params->bit1;
} else {
symbols[i] = params->bit0;
}
}
if ((index + 1) >= size && params->reset.duration0 == 0 && params->reset.duration1 == 0) {
*done = true;
}
return RMT_SYMBOLS_PER_BYTE;
}
// send reset
if (symbols_free < 1) {
return 0;
}
symbols[0] = params->reset;
*done = true;
return 1;
}
#endif
void ESP32RMTLEDStripLightOutput::setup() {
ESP_LOGCONFIG(TAG, "Running setup");
@@ -42,10 +79,15 @@ void ESP32RMTLEDStripLightOutput::setup() {
return;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
// copy of the led buffer
this->rmt_buf_ = allocator.allocate(buffer_size);
#else
RAMAllocator<rmt_symbol_word_t> rmt_allocator(this->use_psram_ ? 0 : RAMAllocator<rmt_symbol_word_t>::ALLOC_INTERNAL);
// 8 bits per byte, 1 rmt_symbol_word_t per bit + 1 rmt_symbol_word_t for reset
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1);
#endif
rmt_tx_channel_config_t channel;
memset(&channel, 0, sizeof(channel));
@@ -65,6 +107,18 @@ void ESP32RMTLEDStripLightOutput::setup() {
return;
}
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
rmt_simple_encoder_config_t encoder;
memset(&encoder, 0, sizeof(encoder));
encoder.callback = encoder_callback;
encoder.arg = &this->params_;
encoder.min_chunk_size = 8;
if (rmt_new_simple_encoder(&encoder, &this->encoder_) != ESP_OK) {
ESP_LOGE(TAG, "Encoder creation failed");
this->mark_failed();
return;
}
#else
rmt_copy_encoder_config_t encoder;
memset(&encoder, 0, sizeof(encoder));
if (rmt_new_copy_encoder(&encoder, &this->encoder_) != ESP_OK) {
@@ -72,6 +126,7 @@ void ESP32RMTLEDStripLightOutput::setup() {
this->mark_failed();
return;
}
#endif
if (rmt_enable(this->channel_) != ESP_OK) {
ESP_LOGE(TAG, "Enabling channel failed");
@@ -85,20 +140,20 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
float ratio = (float) RMT_CLK_FREQ / RMT_CLK_DIV / 1e09f;
// 0-bit
this->bit0_.duration0 = (uint32_t) (ratio * bit0_high);
this->bit0_.level0 = 1;
this->bit0_.duration1 = (uint32_t) (ratio * bit0_low);
this->bit0_.level1 = 0;
this->params_.bit0.duration0 = (uint32_t) (ratio * bit0_high);
this->params_.bit0.level0 = 1;
this->params_.bit0.duration1 = (uint32_t) (ratio * bit0_low);
this->params_.bit0.level1 = 0;
// 1-bit
this->bit1_.duration0 = (uint32_t) (ratio * bit1_high);
this->bit1_.level0 = 1;
this->bit1_.duration1 = (uint32_t) (ratio * bit1_low);
this->bit1_.level1 = 0;
this->params_.bit1.duration0 = (uint32_t) (ratio * bit1_high);
this->params_.bit1.level0 = 1;
this->params_.bit1.duration1 = (uint32_t) (ratio * bit1_low);
this->params_.bit1.level1 = 0;
// reset
this->reset_.duration0 = (uint32_t) (ratio * reset_time_high);
this->reset_.level0 = 1;
this->reset_.duration1 = (uint32_t) (ratio * reset_time_low);
this->reset_.level1 = 0;
this->params_.reset.duration0 = (uint32_t) (ratio * reset_time_high);
this->params_.reset.level0 = 1;
this->params_.reset.duration1 = (uint32_t) (ratio * reset_time_low);
this->params_.reset.level1 = 0;
}
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
@@ -122,6 +177,9 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
}
delayMicroseconds(50);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
memcpy(this->rmt_buf_, this->buf_, this->get_buffer_size_());
#else
size_t buffer_size = this->get_buffer_size_();
size_t size = 0;
@@ -131,7 +189,7 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
while (size < buffer_size) {
uint8_t b = *psrc;
for (int i = 0; i < 8; i++) {
pdest->val = b & (1 << (7 - i)) ? this->bit1_.val : this->bit0_.val;
pdest->val = b & (1 << (7 - i)) ? this->params_.bit1.val : this->params_.bit0.val;
pdest++;
len++;
}
@@ -139,17 +197,20 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
psrc++;
}
if (this->reset_.duration0 > 0 || this->reset_.duration1 > 0) {
pdest->val = this->reset_.val;
if (this->params_.reset.duration0 > 0 || this->params_.reset.duration1 > 0) {
pdest->val = this->params_.reset.val;
pdest++;
len++;
}
#endif
rmt_transmit_config_t config;
memset(&config, 0, sizeof(config));
config.loop_count = 0;
config.flags.eot_level = 0;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config);
#else
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config);
#endif
if (error != ESP_OK) {
ESP_LOGE(TAG, "RMT TX error");
this->status_set_warning();

View File

@@ -25,6 +25,12 @@ enum RGBOrder : uint8_t {
ORDER_BRG,
};
struct LedParams {
rmt_symbol_word_t bit0;
rmt_symbol_word_t bit1;
rmt_symbol_word_t reset;
};
class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
public:
void setup() override;
@@ -72,12 +78,15 @@ class ESP32RMTLEDStripLightOutput : public light::AddressableLight {
uint8_t *buf_{nullptr};
uint8_t *effect_data_{nullptr};
LedParams params_;
rmt_channel_handle_t channel_{nullptr};
rmt_encoder_handle_t encoder_{nullptr};
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
uint8_t *rmt_buf_{nullptr};
#else
rmt_symbol_word_t *rmt_buf_{nullptr};
rmt_symbol_word_t bit0_, bit1_, reset_;
#endif
uint32_t rmt_symbols_{48};
uint8_t pin_;
uint16_t num_leds_;
bool is_rgbw_{false};

View File

@@ -1,355 +0,0 @@
#ifdef USE_ESP32
#include "esp32_touch.h"
#include "esphome/core/application.h"
#include "esphome/core/log.h"
#include "esphome/core/hal.h"
#include <cinttypes>
namespace esphome {
namespace esp32_touch {
static const char *const TAG = "esp32_touch";
void ESP32TouchComponent::setup() {
ESP_LOGCONFIG(TAG, "Running setup");
touch_pad_init();
// set up and enable/start filtering based on ESP32 variant
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
if (this->filter_configured_()) {
touch_filter_config_t filter_info = {
.mode = this->filter_mode_,
.debounce_cnt = this->debounce_count_,
.noise_thr = this->noise_threshold_,
.jitter_step = this->jitter_step_,
.smh_lvl = this->smooth_level_,
};
touch_pad_filter_set_config(&filter_info);
touch_pad_filter_enable();
}
if (this->denoise_configured_()) {
touch_pad_denoise_t denoise = {
.grade = this->grade_,
.cap_level = this->cap_level_,
};
touch_pad_denoise_set_config(&denoise);
touch_pad_denoise_enable();
}
if (this->waterproof_configured_()) {
touch_pad_waterproof_t waterproof = {
.guard_ring_pad = this->waterproof_guard_ring_pad_,
.shield_driver = this->waterproof_shield_driver_,
};
touch_pad_waterproof_set_config(&waterproof);
touch_pad_waterproof_enable();
}
#else
if (this->iir_filter_enabled_()) {
touch_pad_filter_start(this->iir_filter_);
}
#endif
#if ESP_IDF_VERSION_MAJOR >= 5 && defined(USE_ESP32_VARIANT_ESP32)
touch_pad_set_measurement_clock_cycles(this->meas_cycle_);
touch_pad_set_measurement_interval(this->sleep_cycle_);
#else
touch_pad_set_meas_time(this->sleep_cycle_, this->meas_cycle_);
#endif
touch_pad_set_voltage(this->high_voltage_reference_, this->low_voltage_reference_, this->voltage_attenuation_);
for (auto *child : this->children_) {
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_pad_config(child->get_touch_pad());
#else
// Disable interrupt threshold
touch_pad_config(child->get_touch_pad(), 0);
#endif
}
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
touch_pad_fsm_start();
#endif
}
void ESP32TouchComponent::dump_config() {
ESP_LOGCONFIG(TAG,
"Config for ESP32 Touch Hub:\n"
" Meas cycle: %.2fms\n"
" Sleep cycle: %.2fms",
this->meas_cycle_ / (8000000.0f / 1000.0f), this->sleep_cycle_ / (150000.0f / 1000.0f));
const char *lv_s;
switch (this->low_voltage_reference_) {
case TOUCH_LVOLT_0V5:
lv_s = "0.5V";
break;
case TOUCH_LVOLT_0V6:
lv_s = "0.6V";
break;
case TOUCH_LVOLT_0V7:
lv_s = "0.7V";
break;
case TOUCH_LVOLT_0V8:
lv_s = "0.8V";
break;
default:
lv_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Low Voltage Reference: %s", lv_s);
const char *hv_s;
switch (this->high_voltage_reference_) {
case TOUCH_HVOLT_2V4:
hv_s = "2.4V";
break;
case TOUCH_HVOLT_2V5:
hv_s = "2.5V";
break;
case TOUCH_HVOLT_2V6:
hv_s = "2.6V";
break;
case TOUCH_HVOLT_2V7:
hv_s = "2.7V";
break;
default:
hv_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " High Voltage Reference: %s", hv_s);
const char *atten_s;
switch (this->voltage_attenuation_) {
case TOUCH_HVOLT_ATTEN_1V5:
atten_s = "1.5V";
break;
case TOUCH_HVOLT_ATTEN_1V:
atten_s = "1V";
break;
case TOUCH_HVOLT_ATTEN_0V5:
atten_s = "0.5V";
break;
case TOUCH_HVOLT_ATTEN_0V:
atten_s = "0V";
break;
default:
atten_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Voltage Attenuation: %s", atten_s);
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
if (this->filter_configured_()) {
const char *filter_mode_s;
switch (this->filter_mode_) {
case TOUCH_PAD_FILTER_IIR_4:
filter_mode_s = "IIR_4";
break;
case TOUCH_PAD_FILTER_IIR_8:
filter_mode_s = "IIR_8";
break;
case TOUCH_PAD_FILTER_IIR_16:
filter_mode_s = "IIR_16";
break;
case TOUCH_PAD_FILTER_IIR_32:
filter_mode_s = "IIR_32";
break;
case TOUCH_PAD_FILTER_IIR_64:
filter_mode_s = "IIR_64";
break;
case TOUCH_PAD_FILTER_IIR_128:
filter_mode_s = "IIR_128";
break;
case TOUCH_PAD_FILTER_IIR_256:
filter_mode_s = "IIR_256";
break;
case TOUCH_PAD_FILTER_JITTER:
filter_mode_s = "JITTER";
break;
default:
filter_mode_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG,
" Filter mode: %s\n"
" Debounce count: %" PRIu32 "\n"
" Noise threshold coefficient: %" PRIu32 "\n"
" Jitter filter step size: %" PRIu32,
filter_mode_s, this->debounce_count_, this->noise_threshold_, this->jitter_step_);
const char *smooth_level_s;
switch (this->smooth_level_) {
case TOUCH_PAD_SMOOTH_OFF:
smooth_level_s = "OFF";
break;
case TOUCH_PAD_SMOOTH_IIR_2:
smooth_level_s = "IIR_2";
break;
case TOUCH_PAD_SMOOTH_IIR_4:
smooth_level_s = "IIR_4";
break;
case TOUCH_PAD_SMOOTH_IIR_8:
smooth_level_s = "IIR_8";
break;
default:
smooth_level_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Smooth level: %s", smooth_level_s);
}
if (this->denoise_configured_()) {
const char *grade_s;
switch (this->grade_) {
case TOUCH_PAD_DENOISE_BIT12:
grade_s = "BIT12";
break;
case TOUCH_PAD_DENOISE_BIT10:
grade_s = "BIT10";
break;
case TOUCH_PAD_DENOISE_BIT8:
grade_s = "BIT8";
break;
case TOUCH_PAD_DENOISE_BIT4:
grade_s = "BIT4";
break;
default:
grade_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Denoise grade: %s", grade_s);
const char *cap_level_s;
switch (this->cap_level_) {
case TOUCH_PAD_DENOISE_CAP_L0:
cap_level_s = "L0";
break;
case TOUCH_PAD_DENOISE_CAP_L1:
cap_level_s = "L1";
break;
case TOUCH_PAD_DENOISE_CAP_L2:
cap_level_s = "L2";
break;
case TOUCH_PAD_DENOISE_CAP_L3:
cap_level_s = "L3";
break;
case TOUCH_PAD_DENOISE_CAP_L4:
cap_level_s = "L4";
break;
case TOUCH_PAD_DENOISE_CAP_L5:
cap_level_s = "L5";
break;
case TOUCH_PAD_DENOISE_CAP_L6:
cap_level_s = "L6";
break;
case TOUCH_PAD_DENOISE_CAP_L7:
cap_level_s = "L7";
break;
default:
cap_level_s = "UNKNOWN";
break;
}
ESP_LOGCONFIG(TAG, " Denoise capacitance level: %s", cap_level_s);
}
#else
if (this->iir_filter_enabled_()) {
ESP_LOGCONFIG(TAG, " IIR Filter: %" PRIu32 "ms", this->iir_filter_);
} else {
ESP_LOGCONFIG(TAG, " IIR Filter DISABLED");
}
#endif
if (this->setup_mode_) {
ESP_LOGCONFIG(TAG, " Setup Mode ENABLED");
}
for (auto *child : this->children_) {
LOG_BINARY_SENSOR(" ", "Touch Pad", child);
ESP_LOGCONFIG(TAG, " Pad: T%" PRIu32, (uint32_t) child->get_touch_pad());
ESP_LOGCONFIG(TAG, " Threshold: %" PRIu32, child->get_threshold());
}
}
uint32_t ESP32TouchComponent::component_touch_pad_read(touch_pad_t tp) {
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
uint32_t value = 0;
if (this->filter_configured_()) {
touch_pad_filter_read_smooth(tp, &value);
} else {
touch_pad_read_raw_data(tp, &value);
}
#else
uint16_t value = 0;
if (this->iir_filter_enabled_()) {
touch_pad_read_filtered(tp, &value);
} else {
touch_pad_read(tp, &value);
}
#endif
return value;
}
void ESP32TouchComponent::loop() {
const uint32_t now = App.get_loop_component_start_time();
bool should_print = this->setup_mode_ && now - this->setup_mode_last_log_print_ > 250;
for (auto *child : this->children_) {
child->value_ = this->component_touch_pad_read(child->get_touch_pad());
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
child->publish_state(child->value_ < child->get_threshold());
#else
child->publish_state(child->value_ > child->get_threshold());
#endif
if (should_print) {
ESP_LOGD(TAG, "Touch Pad '%s' (T%" PRIu32 "): %" PRIu32, child->get_name().c_str(),
(uint32_t) child->get_touch_pad(), child->value_);
}
App.feed_wdt();
}
if (should_print) {
// Avoid spamming logs
this->setup_mode_last_log_print_ = now;
}
}
void ESP32TouchComponent::on_shutdown() {
bool is_wakeup_source = false;
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
if (this->iir_filter_enabled_()) {
touch_pad_filter_stop();
touch_pad_filter_delete();
}
#endif
for (auto *child : this->children_) {
if (child->get_wakeup_threshold() != 0) {
if (!is_wakeup_source) {
is_wakeup_source = true;
// Touch sensor FSM mode must be 'TOUCH_FSM_MODE_TIMER' to use it to wake-up.
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
}
#if !(defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3))
// No filter available when using as wake-up source.
touch_pad_config(child->get_touch_pad(), child->get_wakeup_threshold());
#endif
}
}
if (!is_wakeup_source) {
touch_pad_deinit();
}
}
ESP32TouchBinarySensor::ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold)
: touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {}
} // namespace esp32_touch
} // namespace esphome
#endif

View File

@@ -9,10 +9,26 @@
#include <vector>
#include <driver/touch_sensor.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
namespace esphome {
namespace esp32_touch {
// IMPORTANT: Touch detection logic differs between ESP32 variants:
// - ESP32 v1 (original): Touch detected when value < threshold (capacitance increase causes value decrease)
// - ESP32-S2/S3 v2: Touch detected when value > threshold (capacitance increase causes value increase)
// This inversion is due to different hardware implementations between chip generations.
//
// INTERRUPT BEHAVIOR:
// - ESP32 v1: Interrupts fire when ANY pad is touched and continue while touched.
// Releases are detected by timeout since hardware doesn't generate release interrupts.
// - ESP32-S2/S3 v2: Hardware supports both touch and release interrupts, but release
// interrupts are unreliable and sometimes don't fire. We now only use touch interrupts
// and detect releases via timeout, similar to v1.
static const uint32_t SETUP_MODE_LOG_INTERVAL_MS = 250;
class ESP32TouchBinarySensor;
class ESP32TouchComponent : public Component {
@@ -31,6 +47,14 @@ class ESP32TouchComponent : public Component {
void set_voltage_attenuation(touch_volt_atten_t voltage_attenuation) {
this->voltage_attenuation_ = voltage_attenuation;
}
void setup() override;
void dump_config() override;
void loop() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void on_shutdown() override;
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
void set_filter_mode(touch_filter_mode_t filter_mode) { this->filter_mode_ = filter_mode; }
void set_debounce_count(uint32_t debounce_count) { this->debounce_count_ = debounce_count; }
@@ -47,17 +71,101 @@ class ESP32TouchComponent : public Component {
void set_iir_filter(uint32_t iir_filter) { this->iir_filter_ = iir_filter; }
#endif
uint32_t component_touch_pad_read(touch_pad_t tp);
protected:
// Common helper methods
void dump_config_base_();
void dump_config_sensors_();
bool create_touch_queue_();
void cleanup_touch_queue_();
void configure_wakeup_pads_();
void setup() override;
void dump_config() override;
void loop() override;
float get_setup_priority() const override { return setup_priority::DATA; }
// Helper methods for loop() logic
void process_setup_mode_logging_(uint32_t now);
bool should_check_for_releases_(uint32_t now);
void publish_initial_state_if_needed_(ESP32TouchBinarySensor *child, uint32_t now);
void check_and_disable_loop_if_all_released_(size_t pads_off);
void calculate_release_timeout_();
void on_shutdown() override;
// Common members
std::vector<ESP32TouchBinarySensor *> children_;
bool setup_mode_{false};
uint32_t setup_mode_last_log_print_{0};
uint32_t last_release_check_{0};
uint32_t release_timeout_ms_{1500};
uint32_t release_check_interval_ms_{50};
bool initial_state_published_[TOUCH_PAD_MAX] = {false};
// Common configuration parameters
uint16_t sleep_cycle_{4095};
uint16_t meas_cycle_{65535};
touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5};
touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7};
touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V};
// Common constants
static constexpr uint32_t MINIMUM_RELEASE_TIME_MS = 100;
// ==================== PLATFORM SPECIFIC ====================
#ifdef USE_ESP32_VARIANT_ESP32
// ESP32 v1 specific
static void touch_isr_handler(void *arg);
QueueHandle_t touch_queue_{nullptr};
private:
// Touch event structure for ESP32 v1
// Contains touch pad info, value, and touch state for queue communication
struct TouchPadEventV1 {
touch_pad_t pad;
uint32_t value;
bool is_touched;
};
protected:
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
// Design note: last_touch_time_ does not require synchronization primitives because:
// 1. ESP32 guarantees atomic 32-bit aligned reads/writes
// 2. ISR only writes timestamps, main loop only reads
// 3. Timing tolerance allows for occasional stale reads (50ms check interval)
// 4. Queue operations provide implicit memory barriers
// Using atomic/critical sections would add overhead without meaningful benefit
uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0};
uint32_t iir_filter_{0};
bool iir_filter_enabled_() const { return this->iir_filter_ > 0; }
#elif defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
// ESP32-S2/S3 v2 specific
static void touch_isr_handler(void *arg);
QueueHandle_t touch_queue_{nullptr};
private:
// Touch event structure for ESP32 v2 (S2/S3)
// Contains touch pad and interrupt mask for queue communication
struct TouchPadEventV2 {
touch_pad_t pad;
uint32_t intr_mask;
};
// Track last touch time for timeout-based release detection
uint32_t last_touch_time_[TOUCH_PAD_MAX] = {0};
protected:
// Filter configuration
touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX};
uint32_t debounce_count_{0};
uint32_t noise_threshold_{0};
uint32_t jitter_step_{0};
touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX};
// Denoise configuration
touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX};
touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX};
// Waterproof configuration
touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX};
touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX};
bool filter_configured_() const {
return (this->filter_mode_ != TOUCH_PAD_FILTER_MAX) && (this->smooth_level_ != TOUCH_PAD_SMOOTH_MAX);
}
@@ -68,43 +176,78 @@ class ESP32TouchComponent : public Component {
return (this->waterproof_guard_ring_pad_ != TOUCH_PAD_MAX) &&
(this->waterproof_shield_driver_ != TOUCH_PAD_SHIELD_DRV_MAX);
}
#else
bool iir_filter_enabled_() const { return this->iir_filter_ > 0; }
// Helper method to read touch values - non-blocking operation
// Returns the current touch pad value using either filtered or raw reading
// based on the filter configuration
uint32_t read_touch_value(touch_pad_t pad) const;
// Helper to update touch state with a known state
void update_touch_state_(ESP32TouchBinarySensor *child, bool is_touched);
// Helper to read touch value and update state for a given child
bool check_and_update_touch_state_(ESP32TouchBinarySensor *child);
#endif
std::vector<ESP32TouchBinarySensor *> children_;
bool setup_mode_{false};
uint32_t setup_mode_last_log_print_{0};
// common parameters
uint16_t sleep_cycle_{4095};
uint16_t meas_cycle_{65535};
touch_low_volt_t low_voltage_reference_{TOUCH_LVOLT_0V5};
touch_high_volt_t high_voltage_reference_{TOUCH_HVOLT_2V7};
touch_volt_atten_t voltage_attenuation_{TOUCH_HVOLT_ATTEN_0V};
#if defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
touch_filter_mode_t filter_mode_{TOUCH_PAD_FILTER_MAX};
uint32_t debounce_count_{0};
uint32_t noise_threshold_{0};
uint32_t jitter_step_{0};
touch_smooth_mode_t smooth_level_{TOUCH_PAD_SMOOTH_MAX};
touch_pad_denoise_grade_t grade_{TOUCH_PAD_DENOISE_MAX};
touch_pad_denoise_cap_t cap_level_{TOUCH_PAD_DENOISE_CAP_MAX};
touch_pad_t waterproof_guard_ring_pad_{TOUCH_PAD_MAX};
touch_pad_shield_driver_t waterproof_shield_driver_{TOUCH_PAD_SHIELD_DRV_MAX};
#else
uint32_t iir_filter_{0};
#endif
// Helper functions for dump_config - common to both implementations
static const char *get_low_voltage_reference_str(touch_low_volt_t ref) {
switch (ref) {
case TOUCH_LVOLT_0V5:
return "0.5V";
case TOUCH_LVOLT_0V6:
return "0.6V";
case TOUCH_LVOLT_0V7:
return "0.7V";
case TOUCH_LVOLT_0V8:
return "0.8V";
default:
return "UNKNOWN";
}
}
static const char *get_high_voltage_reference_str(touch_high_volt_t ref) {
switch (ref) {
case TOUCH_HVOLT_2V4:
return "2.4V";
case TOUCH_HVOLT_2V5:
return "2.5V";
case TOUCH_HVOLT_2V6:
return "2.6V";
case TOUCH_HVOLT_2V7:
return "2.7V";
default:
return "UNKNOWN";
}
}
static const char *get_voltage_attenuation_str(touch_volt_atten_t atten) {
switch (atten) {
case TOUCH_HVOLT_ATTEN_1V5:
return "1.5V";
case TOUCH_HVOLT_ATTEN_1V:
return "1V";
case TOUCH_HVOLT_ATTEN_0V5:
return "0.5V";
case TOUCH_HVOLT_ATTEN_0V:
return "0V";
default:
return "UNKNOWN";
}
}
};
/// Simple helper class to expose a touch pad value as a binary sensor.
class ESP32TouchBinarySensor : public binary_sensor::BinarySensor {
public:
ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold);
ESP32TouchBinarySensor(touch_pad_t touch_pad, uint32_t threshold, uint32_t wakeup_threshold)
: touch_pad_(touch_pad), threshold_(threshold), wakeup_threshold_(wakeup_threshold) {}
touch_pad_t get_touch_pad() const { return this->touch_pad_; }
uint32_t get_threshold() const { return this->threshold_; }
void set_threshold(uint32_t threshold) { this->threshold_ = threshold; }
#ifdef USE_ESP32_VARIANT_ESP32
uint32_t get_value() const { return this->value_; }
#endif
uint32_t get_wakeup_threshold() const { return this->wakeup_threshold_; }
protected:
@@ -112,7 +255,10 @@ class ESP32TouchBinarySensor : public binary_sensor::BinarySensor {
touch_pad_t touch_pad_{TOUCH_PAD_MAX};
uint32_t threshold_{0};
#ifdef USE_ESP32_VARIANT_ESP32
uint32_t value_{0};
#endif
bool last_state_{false};
const uint32_t wakeup_threshold_{0};
};

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