1
0
mirror of https://github.com/esphome/esphome.git synced 2025-11-03 16:41:50 +00:00

Compare commits

...

192 Commits

Author SHA1 Message Date
Jesse Hills
9946592196 [scheduler] Fix crash with defer 2025-07-11 22:01:39 +12:00
Thomas Rupprecht
0ffc446315 [web_server] fix Arudino typo (#9404) 2025-07-09 04:15:01 -10:00
Jesse Hills
a692bd98ef Merge branch 'beta' into dev 2025-07-09 19:34:26 +12:00
Jesse Hills
6178ab7513 Merge pull request #9394 from esphome/bump-2025.7.0b1
2025.7.0b1
2025-07-09 19:33:49 +12:00
Jesse Hills
d24e237967 Bump version to 2025.8.0-dev 2025-07-09 12:10:51 +12:00
Jesse Hills
267574f24c Bump version to 2025.7.0b1 2025-07-09 12:06:52 +12:00
dependabot[bot]
5235c80781 Bump aioesphomeapi from 34.1.0 to 34.2.0 (#9391)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-08 23:54:33 +00:00
Merikei
0ccc5e340e [apds9960] Add 0x9E ID (#9392) 2025-07-08 23:52:30 +00:00
Craig Andrews
86c6e4da2a ESP_EXT1_WAKEUP_ANY_LOW is for s2/s3/c6/h2; ESP_EXT1_WAKEUP_ALL_LOW otherwise (#9387)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-09 11:30:06 +12:00
Jesse Hills
5c8b330eaa [esp32] Improve flexibility of `only_on_variant` (#9390) 2025-07-09 10:51:17 +12:00
Petr Kejval
4158a5c2a3 Add support for GL-R01 I2C - Time of Flight sensor (#8329)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-09 10:50:45 +12:00
Jesse Hills
05c5364490 [helpers] Fix `format_hex_pretty` resize without separator (#9389)
Co-authored-by: RubenKelevra <cyrond@gmail.com>
2025-07-08 22:13:21 +00:00
Jesse Hills
78eb236a4a [nfc] Update code to use `format_hex_pretty` (#9384) 2025-07-08 16:47:42 -05:00
Simonas Kazlauskas
691cc5f7dc lps22: add a component (#7540)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
2025-07-09 09:13:58 +12:00
J. Nick Koston
b3d7f001af Fix race condition in scheduler string lifetime integration test (#9382) 2025-07-08 06:54:47 -05:00
tmpeh
3f8b691c32 Fix format string error in waveshare_epaper.cpp (#9322)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-08 04:39:07 +00:00
J. Nick Koston
a30f01d668 Fix integration test race condition by isolating PlatformIO directories (#9383) 2025-07-08 04:34:39 +00:00
Clyde Stubbs
4648804db6 [image] Add byte order option and unit tests (#9326) 2025-07-08 02:28:00 +00:00
functionpointer
51377b2625 hydreon_rgxx: remove precipitation_intensity from RG9 (#9367) 2025-07-08 14:27:33 +12:00
Jesse Hills
256f9f9943 [helpers] Improve `format_hex_pretty` (#9380) 2025-07-08 01:30:23 +00:00
J. Nick Koston
a72905191a Fix flaky test_api_conditional_memory and improve integration test patterns (#9379) 2025-07-08 11:08:21 +12:00
J. Nick Koston
7150f2806f Run integration tests only on Python 3.13 to reduce CI resource usage (#9377) 2025-07-07 22:14:34 +00:00
J. Nick Koston
ee8ee4e646 Optimize logger callback API by including message length parameter (#9368)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-07 22:00:03 +00:00
Steffen Arntz
fb357b8965 Fix brightness setting not working on SSD1305 128x32 OLEDs (#9376) 2025-07-08 09:25:11 +12:00
Edward Firmo
c4fac1a2ae [nextion] Optimize component memory usage with bitfield state management (#9373) 2025-07-08 09:21:14 +12:00
J. Nick Koston
42a1f6922f Eliminate bluetooth_proxy guard variable to save 8 bytes RAM (#9343) 2025-07-08 09:16:48 +12:00
J. Nick Koston
206659ddb8 Refactor voice assistant API methods to reduce code duplication (#9374) 2025-07-08 09:15:49 +12:00
J. Nick Koston
440de12e3f Don't compile unnecessary platform files (e.g. ESP8266 files on ESP32) (#9354) 2025-07-08 09:04:41 +12:00
J. Nick Koston
b122112d58 Refactor API entity update dispatch to reduce code duplication (#9372) 2025-07-08 08:51:17 +12:00
J. Nick Koston
fe258e1007 Refactor entity lookup methods with macros in preparation for device_id support (#9371) 2025-07-08 08:49:23 +12:00
J. Nick Koston
3976fd02ea Refactor duplicate socket read error handling in API frame helper (#9370) 2025-07-08 08:39:13 +12:00
J. Nick Koston
e58c793da2 Replace deprecated sprintf with snprintf in API protobuf code generation (#9365) 2025-07-08 08:38:41 +12:00
J. Nick Koston
90fb3680d4 Optimize logger performance by eliminating redundant strlen calls (#9369) 2025-07-08 08:36:36 +12:00
J. Nick Koston
832a787271 Fix format specifier warnings in QuantileFilter logging (#9364) 2025-07-08 08:35:27 +12:00
J. Nick Koston
29747fc730 Fix flaky test_api_conditional_memory by disabling API batch delay (#9360) 2025-07-08 08:35:11 +12:00
J. Nick Koston
e2de6ee29d Reduce core RAM usage by 40 bytes with static initialization optimizations (#9340) 2025-07-08 08:28:14 +12:00
J. Nick Koston
053feb5e3b Optimize entity icon memory usage with USE_ENTITY_ICON flag (#9337) 2025-07-08 08:22:40 +12:00
J. Nick Koston
31f36df4ba Reduce LightCall memory usage by 50 bytes per call (#9333) 2025-07-08 08:20:40 +12:00
J. Nick Koston
3ef392d433 Fix scheduler race conditions and add comprehensive test suite (#9348) 2025-07-08 07:57:55 +12:00
J. Nick Koston
138ff749f3 Optimize Bluetooth proxy batching and increase scan buffer capacity (#9328) 2025-07-08 07:34:12 +12:00
Edward Firmo
e88b8d10ec [nextion] Add optional device info storage configuration (#9366) 2025-07-07 12:04:01 -05:00
Jesse Hills
8147d117a0 [core] Move platform helper implementations into their own file (#9361) 2025-07-07 15:55:02 +00:00
Edward Firmo
c6f7e84256 [nextion] Review touch_sleep_timeout (#9345) 2025-07-07 07:30:34 -05:00
Keith Burzinski
db877e688a [ld2450] Clean-up for consistency, reduce CPU usage when idle (#9363) 2025-07-07 07:22:49 -05:00
Edward Firmo
4e25b6da7b [nextion] Optimize settings memory usage with compile-time defines (#9350)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-07 09:15:13 +00:00
Jonathan Swoboda
83512b88c4 [sx126x] Add sx126x component (#8516)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-07-07 05:41:23 +00:00
Jesse Hills
fde5f88192 [inkplate6] Require 240mhz cpu frequency (#9356) 2025-07-06 23:36:34 -05:00
Edward Firmo
2510b5ffb5 [nextion] Replace boolean flags with bitfields to optimize memory usage (#9359) 2025-07-07 04:07:03 +00:00
Keith Burzinski
364b6ca8d0 [scd4x] Memory optimization (#9358) 2025-07-07 03:54:19 +00:00
DT-art1
e49b89a051 Introduce base Camera class to support alternative camera implementations (#9285)
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2025-07-07 15:45:00 +12:00
Jonathan Swoboda
bdd52dbaa4 [sx127x] Fix shaping print in dump_config and preallocate packet (#9357) 2025-07-06 22:41:47 -05:00
J. Nick Koston
765793505d Use std::span to eliminate heap allocation for single-packet API transmissions (#9313) 2025-07-07 14:53:23 +12:00
J. Nick Koston
a303f93236 Fix bluetooth proxy busy loop when disconnecting pending BLE connections (#9332) 2025-07-07 14:50:36 +12:00
J. Nick Koston
492580edc3 Split LockFreeQueue into base and notifying variants to reduce memory usage (#9330) 2025-07-07 14:50:14 +12:00
Jan-Henrik Bruhn
1368139f4d [update, http_request_update] Implement update available trigger (#9174) 2025-07-07 12:36:09 +12:00
J. Nick Koston
b6fade7339 Fix defer() thread safety issues on multi-core platforms (#9317)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-07 10:01:51 +12:00
Jonathan Swoboda
8da322fe9e [sx127x] Improve error handling (#9351) 2025-07-06 18:04:43 +00:00
Keith Burzinski
e5a699a004 [ld2410] Reduce RAM usage, general clean-up (#9346) 2025-07-06 09:16:30 -05:00
Keith Burzinski
e061b6dc55 [scd4x] Optimize logging + minor code clean-up (#9347) 2025-07-06 08:37:50 -05:00
J. Nick Koston
4673a5b48c Eliminate web_server_idf guard variable to save 8 bytes RAM (#9344) 2025-07-06 05:06:32 -05:00
J. Nick Koston
0bc18a8281 Eliminate API component guard variable to save 8 bytes RAM (#9341) 2025-07-05 23:34:55 -05:00
J. Nick Koston
20ba035e3b Reduce RAM usage by optimizing Color constant storage (#9339) 2025-07-05 22:30:18 -05:00
Edward Firmo
f7019a4ed7 [nextion] Memory optimization (#9338) 2025-07-05 21:56:53 -05:00
J. Nick Koston
a1291c2730 [ld2450] Reduce CPU usage, eliminate redundant sensor updates (#9334) 2025-07-05 21:48:58 -05:00
Adrian Freund
b0f8922056 Mark ESPTime comparison operators as const (#9335) 2025-07-05 22:00:39 +00:00
Thomas Rupprecht
4e9e48e2e7 [rtttl] trim extraneous whitespace in "ac_dimmer" in "PWM_BAD" list (#9318) 2025-07-05 01:23:24 -05:00
J. Nick Koston
86e7013f40 Add const char overload for Component::defer() (#9324) 2025-07-04 21:52:12 -05:00
dependabot[bot]
58b4e7dab2 Bump puremagic from 1.29 to 1.30 (#9320) 2025-07-04 20:54:46 +00:00
J. Nick Koston
d686257cff Fix web_server busy loop with ungracefully disconnected clients (#9312)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-04 02:07:25 +00:00
Big Mike
adb7ccdbc7 Fix compiler warning in tsl2591 component (#9310) 2025-07-04 13:00:50 +12:00
J. Nick Koston
d00e20ccdf Reduce web_server loop overhead on ESP32 by avoiding unnecessary semaphore operations (#9308) 2025-07-04 12:53:14 +12:00
J. Nick Koston
25457da97c Fix web_server URL parsing lifetime issue (#9309) 2025-07-04 12:33:19 +12:00
J. Nick Koston
14d7c4bdbd Add device_id to entity state messages for sub-device support (#9304) 2025-07-04 12:31:03 +12:00
dependabot[bot]
eef71a79da Bump ruff from 0.12.1 to 0.12.2 (#9311)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
2025-07-03 21:49:51 +00:00
Kevin Ahrendt
547c7d6dc8 [microphone] simplify mute handling to avoid unnecessary copies (#9303) 2025-07-03 11:17:01 -05:00
Jonathan Swoboda
1ef7b2d64f [sx127x] Add sx127x component (#7490)
Co-authored-by: Jonathan Swoboda <jonathan.swoboda>
2025-07-03 10:37:18 -05:00
dependabot[bot]
107304b274 Bump aioesphomeapi from 34.0.0 to 34.1.0 (#9301)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-07-03 14:08:04 +00:00
Sergey Dudanov
b2b6f41ef3 Packages: optional base path for remote git packages (#9279)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-03 19:11:40 +12:00
J. Nick Koston
34db02661c Allow disabling API batch delay for real-time state updates (#9298) 2025-07-02 21:50:53 -05:00
DanielV
798eef41b9 [Packet transport] Ping timeout sensor (#8694) 2025-07-03 11:25:46 +10:00
Jesse Hills
658e4bac47 Merge branch 'release' into dev 2025-07-03 13:07:58 +12:00
Jesse Hills
f5aab154a6 Merge pull request #9299 from esphome/bump-2025.6.3
2025.6.3
2025-07-03 13:07:17 +12:00
J. Nick Koston
5b55e205ef Save flash and RAM by conditionally compiling unused API password code (#9297) 2025-07-03 09:42:08 +12:00
J. Nick Koston
4ef5c941c9 Fix missing ifdef guards in API protobuf generator (#9296) 2025-07-03 09:39:20 +12:00
Mariusz Kryński
b9391f2cd4 [ds2484] New component (#9147) 2025-07-03 09:15:37 +12:00
Jesse Hills
66e090ff5b Bump version to 2025.6.3 2025-07-03 08:27:46 +12:00
Craig Andrews
d41298897f [http_request] allow retrieval of more than just the first header (#9242) 2025-07-03 08:27:46 +12:00
J. Nick Koston
ba42de536c Fix crash when event last_event_type is null in web_server (#9266) 2025-07-03 08:27:46 +12:00
Jesse Hills
bdc9f5f3b2 Fix api log client crashing when api encryption is dynamic (#9245) 2025-07-03 08:27:46 +12:00
Rezoran
90f9ab0d3e [uart] fix: missing uart_config_t struct initialisation (#9235) 2025-07-03 08:27:46 +12:00
Clyde Stubbs
00eb56d8db [esp32_touch] Fix threshold (#9291)
Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-07-02 09:08:10 -05:00
tomaszduda23
60eac6ea07 [time] fix clang-tidy (#9292) 2025-07-02 14:02:56 +00:00
Jesse Hills
9b3ece4caf [time] Add `USE_TIME_TIMEZONE` define (#9290) 2025-07-02 08:51:25 -05:00
Colm
289aedcfe2 Don't compile state_to_string() unless debugging. (#7473) 2025-07-03 00:23:37 +12:00
rwrozelle
4cdc804c17 OpenThread - add Device Type (#9272)
Co-authored-by: mc <mc@debian>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-03 00:16:28 +12:00
mrtntome
56a963dfe6 [heatpumpir] Add Support for PHS32 HeatPump (#7378)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-03 00:05:54 +12:00
Aleksey Zinchenko
f6f0e52d5e [core] Deleting CMakeCache.txt for fast recompilation with ESP-IDF (#8750) 2025-07-02 17:37:31 +10:00
J. Nick Koston
eba2c82fec Use encode_bytes() for protobuf bytes fields (#9289) 2025-07-02 04:36:09 +00:00
Edward Firmo
fae96e279c [nextion] memory optimization (#9164)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-02 03:25:06 +00:00
JonasB2497
2fb23becec made qr_code elements optional (#8896) 2025-07-02 14:56:48 +12:00
Jeremy Brown
095acce3e2 Mmc5603 fix for devices that don't retrieve chip_id (#8959)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-02 02:48:42 +00:00
Craig Andrews
5fa9d22c5d [http_request] allow retrieval of more than just the first header (#9242) 2025-07-02 14:17:34 +12:00
George
785b14ac84 pulse_meter total (#9282) 2025-07-02 14:14:16 +12:00
J. Nick Koston
84ab758b22 Replace custom OTA implementation in web_server_base (#9274)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
2025-07-02 13:50:45 +12:00
J. Nick Koston
03566c34ed Reduce Component memory usage by 40% (8 bytes per component) (#9278) 2025-07-02 13:43:40 +12:00
Jesse Hills
6a096c1d5a [api] Dump bytes fields as hex instead of unreadable string (#9288) 2025-07-02 13:36:15 +12: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
Jonathan Swoboda
3470305d9d [esp32] Remove IDF 4 support and clean up code (#9145) 2025-07-01 16:22:41 +00: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
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
David Woodhouse
8014cbc71e Fixes for async MQTT (#9273) 2025-06-30 13:25:54 -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
Keith Burzinski
3930609d8b [ld2420] Move consts to cpp file, optimize memory use (#9216) 2025-06-30 01:05:59 -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
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
9890659f61 Optimize web_server UrlMatch to avoid heap allocations (#9263) 2025-06-30 04:12:03 +00: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
6a354d7c94 Reduce API component memory usage with conditional compilation (#9262) 2025-06-30 15:33:35 +12: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
0b1b8f05e1 Reduce loop enable/disable log spam by using very verbose level (#9267) 2025-06-30 11:49:31 +12: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
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
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
d78b720350 Remove single-use send_*_info wrappers in API connection (#9255) 2025-06-30 11:38:11 +12: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
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
Jesse Hills
b743577ebe Fix api log client crashing when api encryption is dynamic (#9245) 2025-06-30 08:07:29 +12: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
Rezoran
921d0888cd [uart] fix: missing uart_config_t struct initialisation (#9235) 2025-06-29 15:05:23 +00: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
86c0fb48a3 Replace ping retry timer with batch queue fallback (#9207) 2025-06-29 09:08:30 +12: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
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
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
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
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
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
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
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
648 changed files with 24824 additions and 10432 deletions

View File

@@ -214,17 +214,51 @@ jobs:
if: matrix.os == 'windows-latest' if: matrix.os == 'windows-latest'
run: | run: |
./venv/Scripts/activate ./venv/Scripts/activate
pytest -vv --cov-report=xml --tb=native -n auto tests pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/
- name: Run pytest - name: Run pytest
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest' if: matrix.os == 'ubuntu-latest' || matrix.os == 'macOS-latest'
run: | run: |
. venv/bin/activate . venv/bin/activate
pytest -vv --cov-report=xml --tb=native -n auto tests pytest -vv --cov-report=xml --tb=native -n auto tests --ignore=tests/integration/
- name: Upload coverage to Codecov - name: Upload coverage to Codecov
uses: codecov/codecov-action@v5.4.3 uses: codecov/codecov-action@v5.4.3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
integration-tests:
name: Run integration tests
runs-on: ubuntu-latest
needs:
- common
steps:
- name: Check out code from GitHub
uses: actions/checkout@v4.2.2
- name: Set up Python 3.13
id: python
uses: actions/setup-python@v5.6.0
with:
python-version: "3.13"
- name: Restore Python virtual environment
id: cache-venv
uses: actions/cache@v4.2.3
with:
path: venv
key: ${{ runner.os }}-${{ steps.python.outputs.python-version }}-venv-${{ needs.common.outputs.cache-key }}
- name: Create Python virtual environment
if: steps.cache-venv.outputs.cache-hit != 'true'
run: |
python -m venv venv
. venv/bin/activate
python --version
pip install -r requirements.txt -r requirements_test.txt
pip install -e .
- name: Register matcher
run: echo "::add-matcher::.github/workflows/matchers/pytest.json"
- name: Run integration tests
run: |
. venv/bin/activate
pytest -vv --no-cov --tb=native -n auto tests/integration/
clang-format: clang-format:
name: Check clang-format name: Check clang-format
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
@@ -494,6 +528,7 @@ jobs:
- flake8 - flake8
- pylint - pylint
- pytest - pytest
- integration-tests
- pyupgrade - pyupgrade
- clang-tidy - clang-tidy
- list-components - list-components

View File

@@ -1,28 +1,11 @@
--- ---
name: Lock name: Lock closed issues and PRs
on: on:
schedule: schedule:
- cron: "30 0 * * *" - cron: "30 0 * * *" # Run daily at 00:30 UTC
workflow_dispatch: workflow_dispatch:
permissions:
issues: write
pull-requests: write
concurrency:
group: lock
jobs: jobs:
lock: lock:
runs-on: ubuntu-latest uses: esphome/workflows/.github/workflows/lock.yml@main
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

View File

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

View File

@@ -87,6 +87,7 @@ esphome/components/bp1658cj/* @Cossid
esphome/components/bp5758d/* @Cossid esphome/components/bp5758d/* @Cossid
esphome/components/button/* @esphome/core esphome/components/button/* @esphome/core
esphome/components/bytebuffer/* @clydebarrow esphome/components/bytebuffer/* @clydebarrow
esphome/components/camera/* @DT-art1 @bdraco
esphome/components/canbus/* @danielschramm @mvturnho esphome/components/canbus/* @danielschramm @mvturnho
esphome/components/cap1188/* @mreditor97 esphome/components/cap1188/* @mreditor97
esphome/components/captive_portal/* @OttoWinter esphome/components/captive_portal/* @OttoWinter
@@ -124,6 +125,7 @@ esphome/components/dht/* @OttoWinter
esphome/components/display_menu_base/* @numo68 esphome/components/display_menu_base/* @numo68
esphome/components/dps310/* @kbx81 esphome/components/dps310/* @kbx81
esphome/components/ds1307/* @badbadc0ffee esphome/components/ds1307/* @badbadc0ffee
esphome/components/ds2484/* @mrk-its
esphome/components/dsmr/* @glmnet @zuidwijk esphome/components/dsmr/* @glmnet @zuidwijk
esphome/components/duty_time/* @dudanov esphome/components/duty_time/* @dudanov
esphome/components/ee895/* @Stock-M esphome/components/ee895/* @Stock-M
@@ -146,6 +148,7 @@ esphome/components/esp32_ble_client/* @jesserockz
esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz esphome/components/esp32_ble_server/* @Rapsssito @clydebarrow @jesserockz
esphome/components/esp32_camera_web_server/* @ayufan esphome/components/esp32_camera_web_server/* @ayufan
esphome/components/esp32_can/* @Sympatron esphome/components/esp32_can/* @Sympatron
esphome/components/esp32_hosted/* @swoboda1337
esphome/components/esp32_improv/* @jesserockz esphome/components/esp32_improv/* @jesserockz
esphome/components/esp32_rmt/* @jesserockz esphome/components/esp32_rmt/* @jesserockz
esphome/components/esp32_rmt_led_strip/* @jesserockz esphome/components/esp32_rmt_led_strip/* @jesserockz
@@ -167,6 +170,7 @@ esphome/components/ft5x06/* @clydebarrow
esphome/components/ft63x6/* @gpambrozio esphome/components/ft63x6/* @gpambrozio
esphome/components/gcja5/* @gcormier esphome/components/gcja5/* @gcormier
esphome/components/gdk101/* @Szewcson esphome/components/gdk101/* @Szewcson
esphome/components/gl_r01_i2c/* @pkejval
esphome/components/globals/* @esphome/core esphome/components/globals/* @esphome/core
esphome/components/gp2y1010au0f/* @zry98 esphome/components/gp2y1010au0f/* @zry98
esphome/components/gp8403/* @jesserockz esphome/components/gp8403/* @jesserockz
@@ -247,9 +251,11 @@ esphome/components/libretiny_pwm/* @kuba2k2
esphome/components/light/* @esphome/core esphome/components/light/* @esphome/core
esphome/components/lightwaverf/* @max246 esphome/components/lightwaverf/* @max246
esphome/components/lilygo_t5_47/touchscreen/* @jesserockz esphome/components/lilygo_t5_47/touchscreen/* @jesserockz
esphome/components/ln882x/* @lamauny
esphome/components/lock/* @esphome/core esphome/components/lock/* @esphome/core
esphome/components/logger/* @esphome/core esphome/components/logger/* @esphome/core
esphome/components/logger/select/* @clydebarrow esphome/components/logger/select/* @clydebarrow
esphome/components/lps22/* @nagisa
esphome/components/ltr390/* @latonita @sjtrny esphome/components/ltr390/* @latonita @sjtrny
esphome/components/ltr501/* @latonita esphome/components/ltr501/* @latonita
esphome/components/ltr_als_ps/* @latonita esphome/components/ltr_als_ps/* @latonita
@@ -331,6 +337,7 @@ esphome/components/pca6416a/* @Mat931
esphome/components/pca9554/* @clydebarrow @hwstar esphome/components/pca9554/* @clydebarrow @hwstar
esphome/components/pcf85063/* @brogon esphome/components/pcf85063/* @brogon
esphome/components/pcf8563/* @KoenBreeman esphome/components/pcf8563/* @KoenBreeman
esphome/components/pi4ioe5v6408/* @jesserockz
esphome/components/pid/* @OttoWinter esphome/components/pid/* @OttoWinter
esphome/components/pipsolar/* @andreashergert1984 esphome/components/pipsolar/* @andreashergert1984
esphome/components/pm1006/* @habbie esphome/components/pm1006/* @habbie
@@ -437,6 +444,8 @@ esphome/components/sun/* @OttoWinter
esphome/components/sun_gtil2/* @Mat931 esphome/components/sun_gtil2/* @Mat931
esphome/components/switch/* @esphome/core esphome/components/switch/* @esphome/core
esphome/components/switch/binary_sensor/* @ssieb esphome/components/switch/binary_sensor/* @ssieb
esphome/components/sx126x/* @swoboda1337
esphome/components/sx127x/* @swoboda1337
esphome/components/syslog/* @clydebarrow esphome/components/syslog/* @clydebarrow
esphome/components/t6615/* @tylermenezes esphome/components/t6615/* @tylermenezes
esphome/components/tc74/* @sethgirvan esphome/components/tc74/* @sethgirvan
@@ -491,10 +500,11 @@ esphome/components/vbus/* @ssieb
esphome/components/veml3235/* @kbx81 esphome/components/veml3235/* @kbx81
esphome/components/veml7700/* @latonita esphome/components/veml7700/* @latonita
esphome/components/version/* @esphome/core 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/wake_on_lan/* @clydebarrow @willwill2will54
esphome/components/watchdog/* @oarcher esphome/components/watchdog/* @oarcher
esphome/components/waveshare_epaper/* @clydebarrow esphome/components/waveshare_epaper/* @clydebarrow
esphome/components/web_server/ota/* @esphome/core
esphome/components/web_server_base/* @OttoWinter esphome/components/web_server_base/* @OttoWinter
esphome/components/web_server_idf/* @dentra esphome/components/web_server_idf/* @dentra
esphome/components/weikai/* @DrCoolZic esphome/components/weikai/* @DrCoolZic

View File

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

View File

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

View File

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

View File

@@ -10,8 +10,15 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266 from esphome.const import (
CONF_ANALOG,
CONF_INPUT,
CONF_NUMBER,
PLATFORM_ESP8266,
PlatformFramework,
)
from esphome.core import CORE from esphome.core import CORE
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
@@ -229,3 +236,20 @@ def validate_adc_pin(value):
)(value) )(value)
raise NotImplementedError raise NotImplementedError
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"adc_sensor_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"adc_sensor_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"adc_sensor_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"adc_sensor_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

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

View File

@@ -61,7 +61,7 @@ uint32_t Aggregator::aggregate() {
void ADCSensor::update() { void ADCSensor::update() {
float value_v = this->sample(); 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); this->publish_state(value_v);
} }

View File

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

View File

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

View File

@@ -49,7 +49,6 @@ class ADS1115Component : public Component, public i2c::I2CDevice {
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
/// HARDWARE_LATE setup priority /// 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; } void set_continuous_mode(bool continuous_mode) { continuous_mode_ = continuous_mode; }
/// Helper method to request a measurement from a sensor. /// Helper method to request a measurement from a sensor.

View File

@@ -34,7 +34,6 @@ class ADS1118 : public Component,
ADS1118() = default; ADS1118() = default;
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/// Helper method to request a measurement from a sensor. /// Helper method to request a measurement from a sensor.
float request_measurement(ADS1118Multiplexer multiplexer, ADS1118Gain gain, bool temperature_mode); 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; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
/** /**
* Modifies target address of AGS10. * Modifies target address of AGS10.
* *

View File

@@ -66,7 +66,6 @@ class AIC3204 : public audio_dac::AudioDac, public Component, public i2c::I2CDev
public: public:
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
bool set_mute_off() override; bool set_mute_off() override;
bool set_mute_on() 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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() 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_flow_sensor(sensor::Sensor *sensor) { this->flow_sensor_ = sensor; }
void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; } void set_head_sensor(sensor::Sensor *sensor) { this->head_sensor_ = sensor; }
void set_power_sensor(sensor::Sensor *sensor) { this->power_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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;
void set_pin(uint16_t pin) { this->pin_ = pin; } void set_pin(uint16_t pin) { this->pin_ = pin; }
void set_invert_position(bool invert_position) { this->invert_position_ = invert_position; } 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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() 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_battery(sensor::Sensor *battery) { battery_ = battery; }
void set_illuminance(sensor::Sensor *illuminance) { illuminance_ = illuminance; } 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 dump_config() override;
void setup() override; void setup() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void set_sensor(sensor::Sensor *analog_sensor); 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_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; } 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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
climate::ClimateTraits traits() override { climate::ClimateTraits traits() override {
auto traits = climate::ClimateTraits(); auto traits = climate::ClimateTraits();
traits.set_supports_current_temperature(true); traits.set_supports_current_temperature(true);

View File

@@ -23,7 +23,7 @@ void APDS9960::setup() {
return; return;
} }
if (id != 0xAB && id != 0x9C && id != 0xA8) { // APDS9960 all should have one of these IDs if (id != 0xAB && id != 0x9C && id != 0xA8 && id != 0x9E) { // APDS9960 all should have one of these IDs
this->error_code_ = WRONG_ID; this->error_code_ = WRONG_ID;
this->mark_failed(); this->mark_failed();
return; return;

View File

@@ -3,6 +3,7 @@ import base64
from esphome import automation from esphome import automation
from esphome.automation import Condition from esphome.automation import Condition
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import get_logger_level
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ACTION, CONF_ACTION,
@@ -110,9 +111,10 @@ CONFIG_SCHEMA = cv.All(
): ACTIONS_SCHEMA, ): ACTIONS_SCHEMA,
cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA, cv.Exclusive(CONF_ACTIONS, group_of_exclusion=CONF_ACTIONS): ACTIONS_SCHEMA,
cv.Optional(CONF_ENCRYPTION): _encryption_schema, cv.Optional(CONF_ENCRYPTION): _encryption_schema,
cv.Optional( cv.Optional(CONF_BATCH_DELAY, default="100ms"): cv.All(
CONF_BATCH_DELAY, default="100ms" cv.positive_time_period_milliseconds,
): cv.positive_time_period_milliseconds, cv.Range(max=cv.TimePeriod(milliseconds=65535)),
),
cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation( cv.Optional(CONF_ON_CLIENT_CONNECTED): automation.validate_automation(
single=True single=True
), ),
@@ -131,11 +133,15 @@ async def to_code(config):
await cg.register_component(var, config) await cg.register_component(var, config)
cg.add(var.set_port(config[CONF_PORT])) cg.add(var.set_port(config[CONF_PORT]))
if config[CONF_PASSWORD]:
cg.add_define("USE_API_PASSWORD")
cg.add(var.set_password(config[CONF_PASSWORD])) cg.add(var.set_password(config[CONF_PASSWORD]))
cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT])) cg.add(var.set_reboot_timeout(config[CONF_REBOOT_TIMEOUT]))
cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY])) cg.add(var.set_batch_delay(config[CONF_BATCH_DELAY]))
for conf in config.get(CONF_ACTIONS, []): if actions := config.get(CONF_ACTIONS, []):
cg.add_define("USE_API_YAML_SERVICES")
for conf in actions:
template_args = [] template_args = []
func_args = [] func_args = []
service_arg_names = [] service_arg_names = []
@@ -152,6 +158,7 @@ async def to_code(config):
await automation.build_automation(trigger, func_args, conf) await automation.build_automation(trigger, func_args, conf)
if CONF_ON_CLIENT_CONNECTED in config: if CONF_ON_CLIENT_CONNECTED in config:
cg.add_define("USE_API_CLIENT_CONNECTED_TRIGGER")
await automation.build_automation( await automation.build_automation(
var.get_client_connected_trigger(), var.get_client_connected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")], [(cg.std_string, "client_info"), (cg.std_string, "client_address")],
@@ -159,6 +166,7 @@ async def to_code(config):
) )
if CONF_ON_CLIENT_DISCONNECTED in config: if CONF_ON_CLIENT_DISCONNECTED in config:
cg.add_define("USE_API_CLIENT_DISCONNECTED_TRIGGER")
await automation.build_automation( await automation.build_automation(
var.get_client_disconnected_trigger(), var.get_client_disconnected_trigger(),
[(cg.std_string, "client_info"), (cg.std_string, "client_address")], [(cg.std_string, "client_info"), (cg.std_string, "client_address")],
@@ -177,7 +185,7 @@ async def to_code(config):
# and plaintext disabled. Only a factory reset can remove it. # and plaintext disabled. Only a factory reset can remove it.
cg.add_define("USE_API_PLAINTEXT") cg.add_define("USE_API_PLAINTEXT")
cg.add_define("USE_API_NOISE") 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: else:
cg.add_define("USE_API_PLAINTEXT") cg.add_define("USE_API_PLAINTEXT")
@@ -306,3 +314,17 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg
@automation.register_condition("api.connected", APIConnectedCondition, {}) @automation.register_condition("api.connected", APIConnectedCondition, {})
async def api_connected_to_code(config, condition_id, template_arg, args): async def api_connected_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg) return cg.new_Pvariable(condition_id, template_arg)
def FILTER_SOURCE_FILES() -> list[str]:
"""Filter out api_pb2_dump.cpp when proto message dumping is not enabled."""
# api_pb2_dump.cpp is only needed when HAS_PROTO_MESSAGE_DUMP is defined
# This is a particularly large file that still needs to be opened and read
# all the way to the end even when ifdef'd out
#
# HAS_PROTO_MESSAGE_DUMP is defined when ESPHOME_LOG_HAS_VERY_VERBOSE is set,
# which happens when the logger level is VERY_VERBOSE
if get_logger_level() != "VERY_VERBOSE":
return ["api_pb2_dump.cpp"]
return []

View File

@@ -311,6 +311,7 @@ message BinarySensorStateResponse {
// If the binary sensor does not have a valid state yet. // If the binary sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
// ==================== COVER ==================== // ==================== COVER ====================
@@ -360,6 +361,7 @@ message CoverStateResponse {
float position = 3; float position = 3;
float tilt = 4; float tilt = 4;
CoverOperation current_operation = 5; CoverOperation current_operation = 5;
uint32 device_id = 6;
} }
enum LegacyCoverCommand { enum LegacyCoverCommand {
@@ -432,6 +434,7 @@ message FanStateResponse {
FanDirection direction = 5; FanDirection direction = 5;
int32 speed_level = 6; int32 speed_level = 6;
string preset_mode = 7; string preset_mode = 7;
uint32 device_id = 8;
} }
message FanCommandRequest { message FanCommandRequest {
option (id) = 31; option (id) = 31;
@@ -513,6 +516,7 @@ message LightStateResponse {
float cold_white = 12; float cold_white = 12;
float warm_white = 13; float warm_white = 13;
string effect = 9; string effect = 9;
uint32 device_id = 14;
} }
message LightCommandRequest { message LightCommandRequest {
option (id) = 32; option (id) = 32;
@@ -598,6 +602,7 @@ message SensorStateResponse {
// If the sensor does not have a valid state yet. // If the sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
// ==================== SWITCH ==================== // ==================== SWITCH ====================
@@ -628,6 +633,7 @@ message SwitchStateResponse {
fixed32 key = 1; fixed32 key = 1;
bool state = 2; bool state = 2;
uint32 device_id = 3;
} }
message SwitchCommandRequest { message SwitchCommandRequest {
option (id) = 33; option (id) = 33;
@@ -669,6 +675,7 @@ message TextSensorStateResponse {
// If the text sensor does not have a valid state yet. // If the text sensor does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
// ==================== SUBSCRIBE LOGS ==================== // ==================== SUBSCRIBE LOGS ====================
@@ -829,7 +836,7 @@ message ListEntitiesCameraResponse {
option (id) = 43; option (id) = 43;
option (base_class) = "InfoResponseProtoMessage"; option (base_class) = "InfoResponseProtoMessage";
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
option (ifdef) = "USE_ESP32_CAMERA"; option (ifdef) = "USE_CAMERA";
string object_id = 1; string object_id = 1;
fixed32 key = 2; fixed32 key = 2;
@@ -844,7 +851,7 @@ message ListEntitiesCameraResponse {
message CameraImageResponse { message CameraImageResponse {
option (id) = 44; option (id) = 44;
option (source) = SOURCE_SERVER; option (source) = SOURCE_SERVER;
option (ifdef) = "USE_ESP32_CAMERA"; option (ifdef) = "USE_CAMERA";
fixed32 key = 1; fixed32 key = 1;
bytes data = 2; bytes data = 2;
@@ -853,7 +860,7 @@ message CameraImageResponse {
message CameraImageRequest { message CameraImageRequest {
option (id) = 45; option (id) = 45;
option (source) = SOURCE_CLIENT; option (source) = SOURCE_CLIENT;
option (ifdef) = "USE_ESP32_CAMERA"; option (ifdef) = "USE_CAMERA";
option (no_delay) = true; option (no_delay) = true;
bool single = 1; bool single = 1;
@@ -966,6 +973,7 @@ message ClimateStateResponse {
string custom_preset = 13; string custom_preset = 13;
float current_humidity = 14; float current_humidity = 14;
float target_humidity = 15; float target_humidity = 15;
uint32 device_id = 16;
} }
message ClimateCommandRequest { message ClimateCommandRequest {
option (id) = 48; option (id) = 48;
@@ -1039,6 +1047,7 @@ message NumberStateResponse {
// If the number does not have a valid state yet. // If the number does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
message NumberCommandRequest { message NumberCommandRequest {
option (id) = 51; option (id) = 51;
@@ -1080,6 +1089,7 @@ message SelectStateResponse {
// If the select does not have a valid state yet. // If the select does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
message SelectCommandRequest { message SelectCommandRequest {
option (id) = 54; option (id) = 54;
@@ -1120,6 +1130,7 @@ message SirenStateResponse {
fixed32 key = 1; fixed32 key = 1;
bool state = 2; bool state = 2;
uint32 device_id = 3;
} }
message SirenCommandRequest { message SirenCommandRequest {
option (id) = 57; option (id) = 57;
@@ -1183,6 +1194,7 @@ message LockStateResponse {
option (no_delay) = true; option (no_delay) = true;
fixed32 key = 1; fixed32 key = 1;
LockState state = 2; LockState state = 2;
uint32 device_id = 3;
} }
message LockCommandRequest { message LockCommandRequest {
option (id) = 60; option (id) = 60;
@@ -1282,6 +1294,7 @@ message MediaPlayerStateResponse {
MediaPlayerState state = 2; MediaPlayerState state = 2;
float volume = 3; float volume = 3;
bool muted = 4; bool muted = 4;
uint32 device_id = 5;
} }
message MediaPlayerCommandRequest { message MediaPlayerCommandRequest {
option (id) = 65; option (id) = 65;
@@ -1822,6 +1835,7 @@ message AlarmControlPanelStateResponse {
option (no_delay) = true; option (no_delay) = true;
fixed32 key = 1; fixed32 key = 1;
AlarmControlPanelState state = 2; AlarmControlPanelState state = 2;
uint32 device_id = 3;
} }
message AlarmControlPanelCommandRequest { message AlarmControlPanelCommandRequest {
@@ -1871,6 +1885,7 @@ message TextStateResponse {
// If the Text does not have a valid state yet. // If the Text does not have a valid state yet.
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 3; bool missing_state = 3;
uint32 device_id = 4;
} }
message TextCommandRequest { message TextCommandRequest {
option (id) = 99; option (id) = 99;
@@ -1914,6 +1929,7 @@ message DateStateResponse {
uint32 year = 3; uint32 year = 3;
uint32 month = 4; uint32 month = 4;
uint32 day = 5; uint32 day = 5;
uint32 device_id = 6;
} }
message DateCommandRequest { message DateCommandRequest {
option (id) = 102; option (id) = 102;
@@ -1958,6 +1974,7 @@ message TimeStateResponse {
uint32 hour = 3; uint32 hour = 3;
uint32 minute = 4; uint32 minute = 4;
uint32 second = 5; uint32 second = 5;
uint32 device_id = 6;
} }
message TimeCommandRequest { message TimeCommandRequest {
option (id) = 105; option (id) = 105;
@@ -1999,6 +2016,7 @@ message EventResponse {
fixed32 key = 1; fixed32 key = 1;
string event_type = 2; string event_type = 2;
uint32 device_id = 3;
} }
// ==================== VALVE ==================== // ==================== VALVE ====================
@@ -2039,6 +2057,7 @@ message ValveStateResponse {
fixed32 key = 1; fixed32 key = 1;
float position = 2; float position = 2;
ValveOperation current_operation = 3; ValveOperation current_operation = 3;
uint32 device_id = 4;
} }
message ValveCommandRequest { message ValveCommandRequest {
@@ -2082,6 +2101,7 @@ message DateTimeStateResponse {
// Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller // Equivalent to `!obj->has_state()` - inverse logic to make state packets smaller
bool missing_state = 2; bool missing_state = 2;
fixed32 epoch_seconds = 3; fixed32 epoch_seconds = 3;
uint32 device_id = 4;
} }
message DateTimeCommandRequest { message DateTimeCommandRequest {
option (id) = 114; option (id) = 114;
@@ -2128,6 +2148,7 @@ message UpdateStateResponse {
string title = 8; string title = 8;
string release_summary = 9; string release_summary = 9;
string release_url = 10; string release_url = 10;
uint32 device_id = 11;
} }
enum UpdateCommand { enum UpdateCommand {
UPDATE_COMMAND_NONE = 0; UPDATE_COMMAND_NONE = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -18,10 +18,13 @@ namespace api {
// Keepalive timeout in milliseconds // Keepalive timeout in milliseconds
static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000; static constexpr uint32_t KEEPALIVE_TIMEOUT_MS = 60000;
// Maximum number of entities to process in a single batch during initial state/info sending
static constexpr size_t MAX_INITIAL_PER_BATCH = 20;
class APIConnection : public APIServerConnection { class APIConnection : public APIServerConnection {
public: public:
friend class APIServer; friend class APIServer;
friend class ListEntitiesIterator;
APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent); APIConnection(std::unique_ptr<socket::Socket> socket, APIServer *parent);
virtual ~APIConnection(); virtual ~APIConnection();
@@ -34,98 +37,79 @@ class APIConnection : public APIServerConnection {
} }
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor); bool send_binary_sensor_state(binary_sensor::BinarySensor *binary_sensor);
void send_binary_sensor_info(binary_sensor::BinarySensor *binary_sensor);
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool send_cover_state(cover::Cover *cover); bool send_cover_state(cover::Cover *cover);
void send_cover_info(cover::Cover *cover);
void cover_command(const CoverCommandRequest &msg) override; void cover_command(const CoverCommandRequest &msg) override;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool send_fan_state(fan::Fan *fan); bool send_fan_state(fan::Fan *fan);
void send_fan_info(fan::Fan *fan);
void fan_command(const FanCommandRequest &msg) override; void fan_command(const FanCommandRequest &msg) override;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool send_light_state(light::LightState *light); bool send_light_state(light::LightState *light);
void send_light_info(light::LightState *light);
void light_command(const LightCommandRequest &msg) override; void light_command(const LightCommandRequest &msg) override;
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool send_sensor_state(sensor::Sensor *sensor); bool send_sensor_state(sensor::Sensor *sensor);
void send_sensor_info(sensor::Sensor *sensor);
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool send_switch_state(switch_::Switch *a_switch); bool send_switch_state(switch_::Switch *a_switch);
void send_switch_info(switch_::Switch *a_switch);
void switch_command(const SwitchCommandRequest &msg) override; void switch_command(const SwitchCommandRequest &msg) override;
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool send_text_sensor_state(text_sensor::TextSensor *text_sensor); bool send_text_sensor_state(text_sensor::TextSensor *text_sensor);
void send_text_sensor_info(text_sensor::TextSensor *text_sensor);
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
void set_camera_state(std::shared_ptr<esp32_camera::CameraImage> image); void set_camera_state(std::shared_ptr<camera::CameraImage> image);
void send_camera_info(esp32_camera::ESP32Camera *camera);
void camera_image(const CameraImageRequest &msg) override; void camera_image(const CameraImageRequest &msg) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool send_climate_state(climate::Climate *climate); bool send_climate_state(climate::Climate *climate);
void send_climate_info(climate::Climate *climate);
void climate_command(const ClimateCommandRequest &msg) override; void climate_command(const ClimateCommandRequest &msg) override;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool send_number_state(number::Number *number); bool send_number_state(number::Number *number);
void send_number_info(number::Number *number);
void number_command(const NumberCommandRequest &msg) override; void number_command(const NumberCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool send_date_state(datetime::DateEntity *date); bool send_date_state(datetime::DateEntity *date);
void send_date_info(datetime::DateEntity *date);
void date_command(const DateCommandRequest &msg) override; void date_command(const DateCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool send_time_state(datetime::TimeEntity *time); bool send_time_state(datetime::TimeEntity *time);
void send_time_info(datetime::TimeEntity *time);
void time_command(const TimeCommandRequest &msg) override; void time_command(const TimeCommandRequest &msg) override;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool send_datetime_state(datetime::DateTimeEntity *datetime); bool send_datetime_state(datetime::DateTimeEntity *datetime);
void send_datetime_info(datetime::DateTimeEntity *datetime);
void datetime_command(const DateTimeCommandRequest &msg) override; void datetime_command(const DateTimeCommandRequest &msg) override;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool send_text_state(text::Text *text); bool send_text_state(text::Text *text);
void send_text_info(text::Text *text);
void text_command(const TextCommandRequest &msg) override; void text_command(const TextCommandRequest &msg) override;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool send_select_state(select::Select *select); bool send_select_state(select::Select *select);
void send_select_info(select::Select *select);
void select_command(const SelectCommandRequest &msg) override; void select_command(const SelectCommandRequest &msg) override;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
void send_button_info(button::Button *button);
void button_command(const ButtonCommandRequest &msg) override; void button_command(const ButtonCommandRequest &msg) override;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool send_lock_state(lock::Lock *a_lock); bool send_lock_state(lock::Lock *a_lock);
void send_lock_info(lock::Lock *a_lock);
void lock_command(const LockCommandRequest &msg) override; void lock_command(const LockCommandRequest &msg) override;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool send_valve_state(valve::Valve *valve); bool send_valve_state(valve::Valve *valve);
void send_valve_info(valve::Valve *valve);
void valve_command(const ValveCommandRequest &msg) override; void valve_command(const ValveCommandRequest &msg) override;
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool send_media_player_state(media_player::MediaPlayer *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; void media_player_command(const MediaPlayerCommandRequest &msg) override;
#endif #endif
bool try_send_log_message(int level, const char *tag, const char *line); bool try_send_log_message(int level, const char *tag, const char *line, size_t message_len);
void send_homeassistant_service_call(const HomeassistantServiceResponse &call) { void send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
if (!this->service_call_subscription_) if (!this->flags_.service_call_subscription)
return; return;
this->send_message(call); this->send_message(call);
} }
@@ -167,26 +151,22 @@ class APIConnection : public APIServerConnection {
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
bool send_alarm_control_panel_state(alarm_control_panel::AlarmControlPanel *a_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; void alarm_control_panel_command(const AlarmControlPanelCommandRequest &msg) override;
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
void send_event(event::Event *event, const std::string &event_type); void send_event(event::Event *event, const std::string &event_type);
void send_event_info(event::Event *event);
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool send_update_state(update::UpdateEntity *update); bool send_update_state(update::UpdateEntity *update);
void send_update_info(update::UpdateEntity *update);
void update_command(const UpdateCommandRequest &msg) override; void update_command(const UpdateCommandRequest &msg) override;
#endif #endif
void on_disconnect_response(const DisconnectResponse &value) override; void on_disconnect_response(const DisconnectResponse &value) override;
void on_ping_response(const PingResponse &value) override { void on_ping_response(const PingResponse &value) override {
// we initiated ping // we initiated ping
this->ping_retries_ = 0; this->flags_.sent_ping = false;
this->sent_ping_ = false;
} }
void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override; void on_home_assistant_state_response(const HomeAssistantStateResponse &msg) override;
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
@@ -199,16 +179,16 @@ class APIConnection : public APIServerConnection {
DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override; DeviceInfoResponse device_info(const DeviceInfoRequest &msg) override;
void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); } void list_entities(const ListEntitiesRequest &msg) override { this->list_entities_iterator_.begin(); }
void subscribe_states(const SubscribeStatesRequest &msg) override { void subscribe_states(const SubscribeStatesRequest &msg) override {
this->state_subscription_ = true; this->flags_.state_subscription = true;
this->initial_state_iterator_.begin(); this->initial_state_iterator_.begin();
} }
void subscribe_logs(const SubscribeLogsRequest &msg) override { void subscribe_logs(const SubscribeLogsRequest &msg) override {
this->log_subscription_ = msg.level; this->flags_.log_subscription = msg.level;
if (msg.dump_config) if (msg.dump_config)
App.schedule_dump_config(); App.schedule_dump_config();
} }
void subscribe_homeassistant_services(const SubscribeHomeassistantServicesRequest &msg) override { 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; void subscribe_home_assistant_states(const SubscribeHomeAssistantStatesRequest &msg) override;
GetTimeResponse get_time(const GetTimeRequest &msg) override { GetTimeResponse get_time(const GetTimeRequest &msg) override {
@@ -220,9 +200,12 @@ class APIConnection : public APIServerConnection {
NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override; NoiseEncryptionSetKeyResponse noise_encryption_set_key(const NoiseEncryptionSetKeyRequest &msg) override;
#endif #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 { 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_fatal_error() override;
void on_unauthenticated_access() override; void on_unauthenticated_access() override;
@@ -309,12 +292,34 @@ class APIConnection : public APIServerConnection {
// Helper function to fill common entity state fields // Helper function to fill common entity state fields
static void fill_entity_state_base(esphome::EntityBase *entity, StateResponseProtoMessage &response) { static void fill_entity_state_base(esphome::EntityBase *entity, StateResponseProtoMessage &response) {
response.key = entity->get_object_id_hash(); response.key = entity->get_object_id_hash();
#ifdef USE_DEVICES
response.device_id = entity->get_device_id();
#endif
} }
// Non-template helper to encode any ProtoMessage // Non-template helper to encode any ProtoMessage
static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn, static uint16_t encode_message_to_buffer(ProtoMessage &msg, uint16_t message_type, APIConnection *conn,
uint32_t remaining_size, bool is_single); uint32_t remaining_size, bool is_single);
#ifdef USE_VOICE_ASSISTANT
// Helper to check voice assistant validity and connection ownership
inline bool check_voice_assistant_api_connection_() const;
#endif
// Helper method to process multiple entities from an iterator in a batch
template<typename Iterator> void process_iterator_batch_(Iterator &iterator) {
size_t initial_size = this->deferred_batch_.size();
while (!iterator.completed() && (this->deferred_batch_.size() - initial_size) < MAX_INITIAL_PER_BATCH) {
iterator.advance();
}
// If the batch is full, process it immediately
// Note: iterator.advance() already calls schedule_batch_() via schedule_message_()
if (this->deferred_batch_.size() >= MAX_INITIAL_PER_BATCH) {
this->process_batch_();
}
}
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
static uint16_t try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, static uint16_t try_send_binary_sensor_state(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single); bool is_single);
@@ -425,7 +430,7 @@ class APIConnection : public APIServerConnection {
static uint16_t try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, static uint16_t try_send_update_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single); bool is_single);
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
static uint16_t try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, static uint16_t try_send_camera_info(EntityBase *entity, APIConnection *conn, uint32_t remaining_size,
bool is_single); bool is_single);
#endif #endif
@@ -441,138 +446,82 @@ class APIConnection : public APIServerConnection {
// Helper function to get estimated message size for buffer pre-allocation // Helper function to get estimated message size for buffer pre-allocation
static uint16_t get_estimated_message_size(uint16_t message_type); 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_; std::unique_ptr<APIFrameHelper> helper_;
APIServer *parent_; APIServer *parent_;
// 4-byte aligned types // Group 2: Larger objects (must be 4-byte aligned)
uint32_t last_traffic_; // These contain vectors/pointers internally, so putting them early ensures good alignment
uint32_t next_ping_retry_{0}; InitialStateIterator initial_state_iterator_;
int state_subs_at_ = -1; ListEntitiesIterator list_entities_iterator_;
#ifdef USE_CAMERA
std::unique_ptr<camera::CameraImageReader> image_reader_;
#endif
// Strings (12 bytes each on 32-bit) // Group 3: Strings (12 bytes each on 32-bit, 4-byte aligned)
std::string client_info_; std::string client_info_;
std::string client_peername_; std::string client_peername_;
// 2-byte aligned types // Group 4: 4-byte types
uint16_t client_api_version_major_{0}; uint32_t last_traffic_;
uint16_t client_api_version_minor_{0}; int state_subs_at_ = -1;
// 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
InitialStateIterator initial_state_iterator_;
ListEntitiesIterator list_entities_iterator_;
#ifdef USE_ESP32_CAMERA
esp32_camera::CameraImageReader image_reader_;
#endif
// Function pointer type for message encoding // Function pointer type for message encoding
using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single); using MessageCreatorPtr = uint16_t (*)(EntityBase *, APIConnection *, uint32_t remaining_size, bool is_single);
// Optimized MessageCreator class using tagged pointer
class MessageCreator { class MessageCreator {
// Ensure pointer alignment allows LSB tagging
static_assert(alignof(std::string *) > 1, "String pointer alignment must be > 1 for LSB tagging");
public: public:
// Constructor for function pointer // Constructor for function pointer
MessageCreator(MessageCreatorPtr ptr) { MessageCreator(MessageCreatorPtr ptr) { data_.function_ptr = ptr; }
// Function pointers are always aligned, so LSB is 0
data_.ptr = ptr;
}
// Constructor for string state capture // Constructor for string state capture
explicit MessageCreator(const std::string &str_value) { explicit MessageCreator(const std::string &str_value) { data_.string_ptr = new std::string(str_value); }
// Allocate string and tag the pointer
auto *str = new std::string(str_value);
// Set LSB to 1 to indicate string pointer
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
}
// Destructor // No destructor - cleanup must be called explicitly with message_type
~MessageCreator() {
if (has_tagged_string_ptr_()) {
delete get_string_ptr_();
}
}
// Copy constructor // Delete copy operations - MessageCreator should only be moved
MessageCreator(const MessageCreator &other) { MessageCreator(const MessageCreator &other) = delete;
if (other.has_tagged_string_ptr_()) { MessageCreator &operator=(const MessageCreator &other) = delete;
auto *str = new std::string(*other.get_string_ptr_());
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
} else {
data_ = other.data_;
}
}
// Move constructor // Move constructor
MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.ptr = nullptr; } MessageCreator(MessageCreator &&other) noexcept : data_(other.data_) { other.data_.function_ptr = nullptr; }
// Assignment operators (needed for batch deduplication)
MessageCreator &operator=(const MessageCreator &other) {
if (this != &other) {
// Clean up current string data if needed
if (has_tagged_string_ptr_()) {
delete get_string_ptr_();
}
// Copy new data
if (other.has_tagged_string_ptr_()) {
auto *str = new std::string(*other.get_string_ptr_());
data_.tagged = reinterpret_cast<uintptr_t>(str) | 1;
} else {
data_ = other.data_;
}
}
return *this;
}
// Move assignment
MessageCreator &operator=(MessageCreator &&other) noexcept { MessageCreator &operator=(MessageCreator &&other) noexcept {
if (this != &other) { if (this != &other) {
// Clean up current string data if needed // IMPORTANT: Caller must ensure cleanup() was called if this contains a string!
if (has_tagged_string_ptr_()) { // In our usage, this happens in add_item() deduplication and vector::erase()
delete get_string_ptr_();
}
// Move data
data_ = other.data_; data_ = other.data_;
// Reset other to safe state other.data_.function_ptr = nullptr;
other.data_.ptr = nullptr;
} }
return *this; return *this;
} }
// Call operator - now accepts message_type as parameter // 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 operator()(EntityBase *entity, APIConnection *conn, uint32_t remaining_size, bool is_single,
uint16_t message_type) const; uint16_t message_type) const;
private: // Manual cleanup method - must be called before destruction for string types
// Check if this contains a string pointer void cleanup(uint16_t message_type) {
bool has_tagged_string_ptr_() const { return (data_.tagged & 1) != 0; } #ifdef USE_EVENT
if (message_type == EventResponse::MESSAGE_TYPE && data_.string_ptr != nullptr) {
// Get the actual string pointer (clears the tag bit) delete data_.string_ptr;
std::string *get_string_ptr_() const { data_.string_ptr = nullptr;
// NOLINTNEXTLINE(performance-no-int-to-ptr) }
return reinterpret_cast<std::string *>(data_.tagged & ~uintptr_t(1)); #endif
} }
union { private:
MessageCreatorPtr ptr; union Data {
uintptr_t tagged; MessageCreatorPtr function_ptr;
} data_; // 4 bytes on 32-bit 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 // Generic batching mechanism for both state updates and entity info
@@ -589,24 +538,86 @@ class APIConnection : public APIServerConnection {
std::vector<BatchItem> items; std::vector<BatchItem> items;
uint32_t batch_start_time{0}; 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() { DeferredBatch() {
// Pre-allocate capacity for typical batch sizes to avoid reallocation // Pre-allocate capacity for typical batch sizes to avoid reallocation
items.reserve(8); items.reserve(8);
} }
~DeferredBatch() {
// Ensure cleanup of any remaining items
clear();
}
// Add item to the batch // Add item to the batch
void add_item(EntityBase *entity, MessageCreator creator, uint16_t message_type); 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() { void clear() {
cleanup_items_(items.size());
items.clear(); items.clear();
batch_scheduled = false;
batch_start_time = 0; 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(); } 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_; 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
uint8_t should_try_send_immediately : 1; // True after initial states are sent
#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; uint32_t get_batch_delay_ms_() const;
// Message will use 8 more bytes than the minimum size, and typical // Message will use 8 more bytes than the minimum size, and typical
// MTU is 1500. Sometimes users will see as low as 1460 MTU. // MTU is 1500. Sometimes users will see as low as 1460 MTU.
@@ -623,9 +634,49 @@ class APIConnection : public APIServerConnection {
bool schedule_batch_(); bool schedule_batch_();
void process_batch_(); void process_batch_();
void clear_batch_() {
this->deferred_batch_.clear();
this->flags_.batch_scheduled = false;
}
// State for batch buffer allocation #ifdef HAS_PROTO_MESSAGE_DUMP
bool batch_first_message_{false}; // Helper to log a proto message from a MessageCreator object
void log_proto_message_(EntityBase *entity, const MessageCreator &creator, uint16_t message_type) {
this->flags_.log_only_mode = true;
creator(entity, this, MAX_PACKET_SIZE, true, message_type);
this->flags_.log_only_mode = false;
}
void log_batch_item_(const DeferredBatch::BatchItem &item) {
// Use the helper to log the message
this->log_proto_message_(item.entity, item.creator, item.message_type);
}
#endif
// Helper method to send a message either immediately or via batching
bool send_message_smart_(EntityBase *entity, MessageCreatorPtr creator, uint16_t message_type) {
// Try to send immediately if:
// 1. We should try to send immediately (should_try_send_immediately = true)
// 2. Batch delay is 0 (user has opted in to immediate sending)
// 3. Buffer has space available
if (this->flags_.should_try_send_immediately && this->get_batch_delay_ms_() == 0 &&
this->helper_->can_write_without_blocking()) {
// Now actually encode and send
if (creator(entity, this, MAX_PACKET_SIZE, true) &&
this->send_buffer(ProtoWriteBuffer{&this->parent_->get_shared_buffer_ref()}, message_type)) {
#ifdef HAS_PROTO_MESSAGE_DUMP
// Log the message in verbose mode
this->log_proto_message_(entity, MessageCreator(creator), message_type);
#endif
return true;
}
// If immediate send failed, fall through to batching
}
// Fall back to scheduled batching
return this->schedule_message_(entity, creator, message_type);
}
// Helper function to schedule a deferred message with known message type // Helper function to schedule a deferred message with known message type
bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) { bool schedule_message_(EntityBase *entity, MessageCreator creator, uint16_t message_type) {
@@ -637,6 +688,12 @@ class APIConnection : public APIServerConnection {
bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) { bool schedule_message_(EntityBase *entity, MessageCreatorPtr function_ptr, uint16_t message_type) {
return schedule_message_(entity, MessageCreator(function_ptr), 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 } // namespace api

View File

@@ -225,6 +225,22 @@ APIError APIFrameHelper::init_common_() {
} }
#define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->info_.c_str(), ##__VA_ARGS__) #define HELPER_LOG(msg, ...) ESP_LOGVV(TAG, "%s: " msg, this->info_.c_str(), ##__VA_ARGS__)
APIError APIFrameHelper::handle_socket_read_result_(ssize_t received) {
if (received == -1) {
if (errno == EWOULDBLOCK || errno == EAGAIN) {
return APIError::WOULD_BLOCK;
}
state_ = State::FAILED;
HELPER_LOG("Socket read failed with errno %d", errno);
return APIError::SOCKET_READ_FAILED;
} else if (received == 0) {
state_ = State::FAILED;
HELPER_LOG("Connection closed");
return APIError::CONNECTION_CLOSED;
}
return APIError::OK;
}
// uncomment to log raw packets // uncomment to log raw packets
//#define HELPER_LOG_PACKETS //#define HELPER_LOG_PACKETS
@@ -327,17 +343,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
// no header information yet // no header information yet
uint8_t to_read = 3 - rx_header_buf_len_; uint8_t to_read = 3 - rx_header_buf_len_;
ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read); ssize_t received = this->socket_->read(&rx_header_buf_[rx_header_buf_len_], to_read);
if (received == -1) { APIError err = handle_socket_read_result_(received);
if (errno == EWOULDBLOCK || errno == EAGAIN) { if (err != APIError::OK) {
return APIError::WOULD_BLOCK; return err;
}
state_ = State::FAILED;
HELPER_LOG("Socket read failed with errno %d", errno);
return APIError::SOCKET_READ_FAILED;
} else if (received == 0) {
state_ = State::FAILED;
HELPER_LOG("Connection closed");
return APIError::CONNECTION_CLOSED;
} }
rx_header_buf_len_ += static_cast<uint8_t>(received); rx_header_buf_len_ += static_cast<uint8_t>(received);
if (static_cast<uint8_t>(received) != to_read) { if (static_cast<uint8_t>(received) != to_read) {
@@ -372,17 +380,9 @@ APIError APINoiseFrameHelper::try_read_frame_(ParsedFrame *frame) {
// more data to read // more data to read
uint16_t to_read = msg_size - rx_buf_len_; uint16_t to_read = msg_size - rx_buf_len_;
ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read); ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
if (received == -1) { APIError err = handle_socket_read_result_(received);
if (errno == EWOULDBLOCK || errno == EAGAIN) { if (err != APIError::OK) {
return APIError::WOULD_BLOCK; return err;
}
state_ = State::FAILED;
HELPER_LOG("Socket read failed with errno %d", errno);
return APIError::SOCKET_READ_FAILED;
} else if (received == 0) {
state_ = State::FAILED;
HELPER_LOG("Connection closed");
return APIError::CONNECTION_CLOSED;
} }
rx_buf_len_ += static_cast<uint16_t>(received); rx_buf_len_ += static_cast<uint16_t>(received);
if (static_cast<uint16_t>(received) != to_read) { if (static_cast<uint16_t>(received) != to_read) {
@@ -614,20 +614,14 @@ APIError APINoiseFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return APIError::OK; return APIError::OK;
} }
APIError APINoiseFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) { APIError APINoiseFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) {
std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
uint16_t payload_len = static_cast<uint16_t>(raw_buffer->size() - frame_header_padding_);
// Resize to include MAC space (required for Noise encryption) // Resize to include MAC space (required for Noise encryption)
raw_buffer->resize(raw_buffer->size() + frame_footer_size_); buffer.get_buffer()->resize(buffer.get_buffer()->size() + frame_footer_size_);
PacketInfo packet{type, 0,
// Use write_protobuf_packets with a single packet static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_ - frame_footer_size_)};
std::vector<PacketInfo> packets; return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
packets.emplace_back(type, 0, payload_len);
return write_protobuf_packets(buffer, packets);
} }
APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) { APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
APIError aerr = state_action_(); APIError aerr = state_action_();
if (aerr != APIError::OK) { if (aerr != APIError::OK) {
return aerr; return aerr;
@@ -642,18 +636,15 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
} }
std::vector<uint8_t> *raw_buffer = buffer.get_buffer(); std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
this->reusable_iovs_.clear(); this->reusable_iovs_.clear();
this->reusable_iovs_.reserve(packets.size()); this->reusable_iovs_.reserve(packets.size());
// We need to encrypt each packet in place // We need to encrypt each packet in place
for (const auto &packet : packets) { for (const auto &packet : packets) {
uint16_t type = packet.message_type;
uint16_t offset = packet.offset;
uint16_t payload_len = packet.payload_size;
uint16_t msg_len = 4 + payload_len; // type(2) + data_len(2) + payload
// The buffer already has padding at offset // The buffer already has padding at offset
uint8_t *buf_start = raw_buffer->data() + offset; uint8_t *buf_start = buffer_data + packet.offset;
// Write noise header // Write noise header
buf_start[0] = 0x01; // indicator buf_start[0] = 0x01; // indicator
@@ -661,10 +652,10 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
// Write message header (to be encrypted) // Write message header (to be encrypted)
const uint8_t msg_offset = 3; const uint8_t msg_offset = 3;
buf_start[msg_offset + 0] = (uint8_t) (type >> 8); // type high byte buf_start[msg_offset] = static_cast<uint8_t>(packet.message_type >> 8); // type high byte
buf_start[msg_offset + 1] = (uint8_t) type; // type low byte buf_start[msg_offset + 1] = static_cast<uint8_t>(packet.message_type); // type low byte
buf_start[msg_offset + 2] = (uint8_t) (payload_len >> 8); // data_len high byte buf_start[msg_offset + 2] = static_cast<uint8_t>(packet.payload_size >> 8); // data_len high byte
buf_start[msg_offset + 3] = (uint8_t) payload_len; // data_len low byte buf_start[msg_offset + 3] = static_cast<uint8_t>(packet.payload_size); // data_len low byte
// payload data is already in the buffer starting at offset + 7 // payload data is already in the buffer starting at offset + 7
// Make sure we have space for MAC // Make sure we have space for MAC
@@ -673,7 +664,8 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
// Encrypt the message in place // Encrypt the message in place
NoiseBuffer mbuf; NoiseBuffer mbuf;
noise_buffer_init(mbuf); noise_buffer_init(mbuf);
noise_buffer_set_inout(mbuf, buf_start + msg_offset, msg_len, msg_len + frame_footer_size_); noise_buffer_set_inout(mbuf, buf_start + msg_offset, 4 + packet.payload_size,
4 + packet.payload_size + frame_footer_size_);
int err = noise_cipherstate_encrypt(send_cipher_, &mbuf); int err = noise_cipherstate_encrypt(send_cipher_, &mbuf);
if (err != 0) { if (err != 0) {
@@ -683,14 +675,12 @@ APIError APINoiseFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, co
} }
// Fill in the encrypted size // Fill in the encrypted size
buf_start[1] = (uint8_t) (mbuf.size >> 8); buf_start[1] = static_cast<uint8_t>(mbuf.size >> 8);
buf_start[2] = (uint8_t) mbuf.size; buf_start[2] = static_cast<uint8_t>(mbuf.size);
// Add iovec for this encrypted packet // Add iovec for this encrypted packet
struct iovec iov; this->reusable_iovs_.push_back(
iov.iov_base = buf_start; {buf_start, static_cast<size_t>(3 + mbuf.size)}); // indicator + size + encrypted data
iov.iov_len = 3 + mbuf.size; // indicator + size + encrypted data
this->reusable_iovs_.push_back(iov);
} }
// Send all encrypted packets in one writev call // Send all encrypted packets in one writev call
@@ -865,17 +855,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
// Try to get to at least 3 bytes total (indicator + 2 varint bytes), then read one byte at a time // Try to get to at least 3 bytes total (indicator + 2 varint bytes), then read one byte at a time
ssize_t received = ssize_t received =
this->socket_->read(&rx_header_buf_[rx_header_buf_pos_], rx_header_buf_pos_ < 3 ? 3 - rx_header_buf_pos_ : 1); this->socket_->read(&rx_header_buf_[rx_header_buf_pos_], rx_header_buf_pos_ < 3 ? 3 - rx_header_buf_pos_ : 1);
if (received == -1) { APIError err = handle_socket_read_result_(received);
if (errno == EWOULDBLOCK || errno == EAGAIN) { if (err != APIError::OK) {
return APIError::WOULD_BLOCK; return err;
}
state_ = State::FAILED;
HELPER_LOG("Socket read failed with errno %d", errno);
return APIError::SOCKET_READ_FAILED;
} else if (received == 0) {
state_ = State::FAILED;
HELPER_LOG("Connection closed");
return APIError::CONNECTION_CLOSED;
} }
// If this was the first read, validate the indicator byte // If this was the first read, validate the indicator byte
@@ -959,17 +941,9 @@ APIError APIPlaintextFrameHelper::try_read_frame_(ParsedFrame *frame) {
// more data to read // more data to read
uint16_t to_read = rx_header_parsed_len_ - rx_buf_len_; uint16_t to_read = rx_header_parsed_len_ - rx_buf_len_;
ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read); ssize_t received = this->socket_->read(&rx_buf_[rx_buf_len_], to_read);
if (received == -1) { APIError err = handle_socket_read_result_(received);
if (errno == EWOULDBLOCK || errno == EAGAIN) { if (err != APIError::OK) {
return APIError::WOULD_BLOCK; return err;
}
state_ = State::FAILED;
HELPER_LOG("Socket read failed with errno %d", errno);
return APIError::SOCKET_READ_FAILED;
} else if (received == 0) {
state_ = State::FAILED;
HELPER_LOG("Connection closed");
return APIError::CONNECTION_CLOSED;
} }
rx_buf_len_ += static_cast<uint16_t>(received); rx_buf_len_ += static_cast<uint16_t>(received);
if (static_cast<uint16_t>(received) != to_read) { if (static_cast<uint16_t>(received) != to_read) {
@@ -1029,18 +1003,11 @@ APIError APIPlaintextFrameHelper::read_packet(ReadPacketBuffer *buffer) {
return APIError::OK; return APIError::OK;
} }
APIError APIPlaintextFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) { APIError APIPlaintextFrameHelper::write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) {
std::vector<uint8_t> *raw_buffer = buffer.get_buffer(); PacketInfo packet{type, 0, static_cast<uint16_t>(buffer.get_buffer()->size() - frame_header_padding_)};
uint16_t payload_len = static_cast<uint16_t>(raw_buffer->size() - frame_header_padding_); return write_protobuf_packets(buffer, std::span<const PacketInfo>(&packet, 1));
// Use write_protobuf_packets with a single packet
std::vector<PacketInfo> packets;
packets.emplace_back(type, 0, payload_len);
return write_protobuf_packets(buffer, packets);
} }
APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) {
const std::vector<PacketInfo> &packets) {
if (state_ != State::DATA) { if (state_ != State::DATA) {
return APIError::BAD_STATE; return APIError::BAD_STATE;
} }
@@ -1050,17 +1017,15 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
} }
std::vector<uint8_t> *raw_buffer = buffer.get_buffer(); std::vector<uint8_t> *raw_buffer = buffer.get_buffer();
uint8_t *buffer_data = raw_buffer->data(); // Cache buffer pointer
this->reusable_iovs_.clear(); this->reusable_iovs_.clear();
this->reusable_iovs_.reserve(packets.size()); this->reusable_iovs_.reserve(packets.size());
for (const auto &packet : packets) { for (const auto &packet : packets) {
uint16_t type = packet.message_type;
uint16_t offset = packet.offset;
uint16_t payload_len = packet.payload_size;
// Calculate varint sizes for header layout // Calculate varint sizes for header layout
uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(payload_len)); uint8_t size_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.payload_size));
uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(type)); uint8_t type_varint_len = api::ProtoSize::varint(static_cast<uint32_t>(packet.message_type));
uint8_t total_header_len = 1 + size_varint_len + type_varint_len; uint8_t total_header_len = 1 + size_varint_len + type_varint_len;
// Calculate where to start writing the header // Calculate where to start writing the header
@@ -1088,23 +1053,20 @@ APIError APIPlaintextFrameHelper::write_protobuf_packets(ProtoWriteBuffer buffer
// //
// The message starts at offset + frame_header_padding_ // The message starts at offset + frame_header_padding_
// So we write the header starting at offset + frame_header_padding_ - total_header_len // So we write the header starting at offset + frame_header_padding_ - total_header_len
uint8_t *buf_start = raw_buffer->data() + offset; uint8_t *buf_start = buffer_data + packet.offset;
uint32_t header_offset = frame_header_padding_ - total_header_len; uint32_t header_offset = frame_header_padding_ - total_header_len;
// Write the plaintext header // Write the plaintext header
buf_start[header_offset] = 0x00; // indicator buf_start[header_offset] = 0x00; // indicator
// Encode size varint directly into buffer // Encode varints directly into buffer
ProtoVarInt(payload_len).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len); ProtoVarInt(packet.payload_size).encode_to_buffer_unchecked(buf_start + header_offset + 1, size_varint_len);
ProtoVarInt(packet.message_type)
// Encode type varint directly into buffer .encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
ProtoVarInt(type).encode_to_buffer_unchecked(buf_start + header_offset + 1 + size_varint_len, type_varint_len);
// Add iovec for this packet (header + payload) // Add iovec for this packet (header + payload)
struct iovec iov; this->reusable_iovs_.push_back(
iov.iov_base = buf_start + header_offset; {buf_start + header_offset, static_cast<size_t>(total_header_len + packet.payload_size)});
iov.iov_len = total_header_len + payload_len;
this->reusable_iovs_.push_back(iov);
} }
// Send all packets in one writev call // Send all packets in one writev call

View File

@@ -2,6 +2,7 @@
#include <cstdint> #include <cstdint>
#include <deque> #include <deque>
#include <limits> #include <limits>
#include <span>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -101,7 +102,7 @@ class APIFrameHelper {
// Write multiple protobuf packets in a single operation // Write multiple protobuf packets in a single operation
// packets contains (message_type, offset, length) for each message in the buffer // packets contains (message_type, offset, length) for each message in the buffer
// The buffer contains all messages with appropriate padding before each // The buffer contains all messages with appropriate padding before each
virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) = 0; virtual APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) = 0;
// Get the frame header padding required by this protocol // Get the frame header padding required by this protocol
virtual uint8_t frame_header_padding() = 0; virtual uint8_t frame_header_padding() = 0;
// Get the frame footer size required by this protocol // Get the frame footer size required by this protocol
@@ -175,6 +176,9 @@ class APIFrameHelper {
// Common initialization for both plaintext and noise protocols // Common initialization for both plaintext and noise protocols
APIError init_common_(); APIError init_common_();
// Helper method to handle socket read results
APIError handle_socket_read_result_(ssize_t received);
}; };
#ifdef USE_API_NOISE #ifdef USE_API_NOISE
@@ -194,7 +198,7 @@ class APINoiseFrameHelper : public APIFrameHelper {
APIError loop() override; APIError loop() override;
APIError read_packet(ReadPacketBuffer *buffer) override; APIError read_packet(ReadPacketBuffer *buffer) override;
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override; APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override; APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
// Get the frame header padding required by this protocol // Get the frame header padding required by this protocol
uint8_t frame_header_padding() override { return frame_header_padding_; } uint8_t frame_header_padding() override { return frame_header_padding_; }
// Get the frame footer size required by this protocol // Get the frame footer size required by this protocol
@@ -248,7 +252,7 @@ class APIPlaintextFrameHelper : public APIFrameHelper {
APIError loop() override; APIError loop() override;
APIError read_packet(ReadPacketBuffer *buffer) override; APIError read_packet(ReadPacketBuffer *buffer) override;
APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override; APIError write_protobuf_packet(uint16_t type, ProtoWriteBuffer buffer) override;
APIError write_protobuf_packets(ProtoWriteBuffer buffer, const std::vector<PacketInfo> &packets) override; APIError write_protobuf_packets(ProtoWriteBuffer buffer, std::span<const PacketInfo> packets) override;
uint8_t frame_header_padding() override { return frame_header_padding_; } uint8_t frame_header_padding() override { return frame_header_padding_; }
// Get the frame footer size required by this protocol // Get the frame footer size required by this protocol
uint8_t frame_footer_size() override { return frame_footer_size_; } uint8_t frame_footer_size() override { return frame_footer_size_; }

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@
// See script/api_protobuf/api_protobuf.py // See script/api_protobuf/api_protobuf.py
#pragma once #pragma once
#include "esphome/core/defines.h"
#include "proto.h" #include "proto.h"
#include "api_pb2_size.h" #include "api_pb2_size.h"
@@ -15,6 +17,7 @@ enum EntityCategory : uint32_t {
ENTITY_CATEGORY_CONFIG = 1, ENTITY_CATEGORY_CONFIG = 1,
ENTITY_CATEGORY_DIAGNOSTIC = 2, ENTITY_CATEGORY_DIAGNOSTIC = 2,
}; };
#ifdef USE_COVER
enum LegacyCoverState : uint32_t { enum LegacyCoverState : uint32_t {
LEGACY_COVER_STATE_OPEN = 0, LEGACY_COVER_STATE_OPEN = 0,
LEGACY_COVER_STATE_CLOSED = 1, LEGACY_COVER_STATE_CLOSED = 1,
@@ -29,6 +32,8 @@ enum LegacyCoverCommand : uint32_t {
LEGACY_COVER_COMMAND_CLOSE = 1, LEGACY_COVER_COMMAND_CLOSE = 1,
LEGACY_COVER_COMMAND_STOP = 2, LEGACY_COVER_COMMAND_STOP = 2,
}; };
#endif
#ifdef USE_FAN
enum FanSpeed : uint32_t { enum FanSpeed : uint32_t {
FAN_SPEED_LOW = 0, FAN_SPEED_LOW = 0,
FAN_SPEED_MEDIUM = 1, FAN_SPEED_MEDIUM = 1,
@@ -38,6 +43,8 @@ enum FanDirection : uint32_t {
FAN_DIRECTION_FORWARD = 0, FAN_DIRECTION_FORWARD = 0,
FAN_DIRECTION_REVERSE = 1, FAN_DIRECTION_REVERSE = 1,
}; };
#endif
#ifdef USE_LIGHT
enum ColorMode : uint32_t { enum ColorMode : uint32_t {
COLOR_MODE_UNKNOWN = 0, COLOR_MODE_UNKNOWN = 0,
COLOR_MODE_ON_OFF = 1, COLOR_MODE_ON_OFF = 1,
@@ -51,6 +58,8 @@ enum ColorMode : uint32_t {
COLOR_MODE_RGB_COLOR_TEMPERATURE = 47, COLOR_MODE_RGB_COLOR_TEMPERATURE = 47,
COLOR_MODE_RGB_COLD_WARM_WHITE = 51, COLOR_MODE_RGB_COLD_WARM_WHITE = 51,
}; };
#endif
#ifdef USE_SENSOR
enum SensorStateClass : uint32_t { enum SensorStateClass : uint32_t {
STATE_CLASS_NONE = 0, STATE_CLASS_NONE = 0,
STATE_CLASS_MEASUREMENT = 1, STATE_CLASS_MEASUREMENT = 1,
@@ -62,6 +71,7 @@ enum SensorLastResetType : uint32_t {
LAST_RESET_NEVER = 1, LAST_RESET_NEVER = 1,
LAST_RESET_AUTO = 2, LAST_RESET_AUTO = 2,
}; };
#endif
enum LogLevel : uint32_t { enum LogLevel : uint32_t {
LOG_LEVEL_NONE = 0, LOG_LEVEL_NONE = 0,
LOG_LEVEL_ERROR = 1, LOG_LEVEL_ERROR = 1,
@@ -82,6 +92,7 @@ enum ServiceArgType : uint32_t {
SERVICE_ARG_TYPE_FLOAT_ARRAY = 6, SERVICE_ARG_TYPE_FLOAT_ARRAY = 6,
SERVICE_ARG_TYPE_STRING_ARRAY = 7, SERVICE_ARG_TYPE_STRING_ARRAY = 7,
}; };
#ifdef USE_CLIMATE
enum ClimateMode : uint32_t { enum ClimateMode : uint32_t {
CLIMATE_MODE_OFF = 0, CLIMATE_MODE_OFF = 0,
CLIMATE_MODE_HEAT_COOL = 1, CLIMATE_MODE_HEAT_COOL = 1,
@@ -127,11 +138,15 @@ enum ClimatePreset : uint32_t {
CLIMATE_PRESET_SLEEP = 6, CLIMATE_PRESET_SLEEP = 6,
CLIMATE_PRESET_ACTIVITY = 7, CLIMATE_PRESET_ACTIVITY = 7,
}; };
#endif
#ifdef USE_NUMBER
enum NumberMode : uint32_t { enum NumberMode : uint32_t {
NUMBER_MODE_AUTO = 0, NUMBER_MODE_AUTO = 0,
NUMBER_MODE_BOX = 1, NUMBER_MODE_BOX = 1,
NUMBER_MODE_SLIDER = 2, NUMBER_MODE_SLIDER = 2,
}; };
#endif
#ifdef USE_LOCK
enum LockState : uint32_t { enum LockState : uint32_t {
LOCK_STATE_NONE = 0, LOCK_STATE_NONE = 0,
LOCK_STATE_LOCKED = 1, LOCK_STATE_LOCKED = 1,
@@ -145,6 +160,8 @@ enum LockCommand : uint32_t {
LOCK_LOCK = 1, LOCK_LOCK = 1,
LOCK_OPEN = 2, LOCK_OPEN = 2,
}; };
#endif
#ifdef USE_MEDIA_PLAYER
enum MediaPlayerState : uint32_t { enum MediaPlayerState : uint32_t {
MEDIA_PLAYER_STATE_NONE = 0, MEDIA_PLAYER_STATE_NONE = 0,
MEDIA_PLAYER_STATE_IDLE = 1, MEDIA_PLAYER_STATE_IDLE = 1,
@@ -162,6 +179,8 @@ enum MediaPlayerFormatPurpose : uint32_t {
MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0, MEDIA_PLAYER_FORMAT_PURPOSE_DEFAULT = 0,
MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1, MEDIA_PLAYER_FORMAT_PURPOSE_ANNOUNCEMENT = 1,
}; };
#endif
#ifdef USE_BLUETOOTH_PROXY
enum BluetoothDeviceRequestType : uint32_t { enum BluetoothDeviceRequestType : uint32_t {
BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0, BLUETOOTH_DEVICE_REQUEST_TYPE_CONNECT = 0,
BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1, BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT = 1,
@@ -183,6 +202,7 @@ enum BluetoothScannerMode : uint32_t {
BLUETOOTH_SCANNER_MODE_PASSIVE = 0, BLUETOOTH_SCANNER_MODE_PASSIVE = 0,
BLUETOOTH_SCANNER_MODE_ACTIVE = 1, BLUETOOTH_SCANNER_MODE_ACTIVE = 1,
}; };
#endif
enum VoiceAssistantSubscribeFlag : uint32_t { enum VoiceAssistantSubscribeFlag : uint32_t {
VOICE_ASSISTANT_SUBSCRIBE_NONE = 0, VOICE_ASSISTANT_SUBSCRIBE_NONE = 0,
VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1, VOICE_ASSISTANT_SUBSCRIBE_API_AUDIO = 1,
@@ -192,6 +212,7 @@ enum VoiceAssistantRequestFlag : uint32_t {
VOICE_ASSISTANT_REQUEST_USE_VAD = 1, VOICE_ASSISTANT_REQUEST_USE_VAD = 1,
VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2, VOICE_ASSISTANT_REQUEST_USE_WAKE_WORD = 2,
}; };
#ifdef USE_VOICE_ASSISTANT
enum VoiceAssistantEvent : uint32_t { enum VoiceAssistantEvent : uint32_t {
VOICE_ASSISTANT_ERROR = 0, VOICE_ASSISTANT_ERROR = 0,
VOICE_ASSISTANT_RUN_START = 1, VOICE_ASSISTANT_RUN_START = 1,
@@ -216,6 +237,8 @@ enum VoiceAssistantTimerEvent : uint32_t {
VOICE_ASSISTANT_TIMER_CANCELLED = 2, VOICE_ASSISTANT_TIMER_CANCELLED = 2,
VOICE_ASSISTANT_TIMER_FINISHED = 3, VOICE_ASSISTANT_TIMER_FINISHED = 3,
}; };
#endif
#ifdef USE_ALARM_CONTROL_PANEL
enum AlarmControlPanelState : uint32_t { enum AlarmControlPanelState : uint32_t {
ALARM_STATE_DISARMED = 0, ALARM_STATE_DISARMED = 0,
ALARM_STATE_ARMED_HOME = 1, ALARM_STATE_ARMED_HOME = 1,
@@ -237,20 +260,27 @@ enum AlarmControlPanelStateCommand : uint32_t {
ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5, ALARM_CONTROL_PANEL_ARM_CUSTOM_BYPASS = 5,
ALARM_CONTROL_PANEL_TRIGGER = 6, ALARM_CONTROL_PANEL_TRIGGER = 6,
}; };
#endif
#ifdef USE_TEXT
enum TextMode : uint32_t { enum TextMode : uint32_t {
TEXT_MODE_TEXT = 0, TEXT_MODE_TEXT = 0,
TEXT_MODE_PASSWORD = 1, TEXT_MODE_PASSWORD = 1,
}; };
#endif
#ifdef USE_VALVE
enum ValveOperation : uint32_t { enum ValveOperation : uint32_t {
VALVE_OPERATION_IDLE = 0, VALVE_OPERATION_IDLE = 0,
VALVE_OPERATION_IS_OPENING = 1, VALVE_OPERATION_IS_OPENING = 1,
VALVE_OPERATION_IS_CLOSING = 2, VALVE_OPERATION_IS_CLOSING = 2,
}; };
#endif
#ifdef USE_UPDATE
enum UpdateCommand : uint32_t { enum UpdateCommand : uint32_t {
UPDATE_COMMAND_NONE = 0, UPDATE_COMMAND_NONE = 0,
UPDATE_COMMAND_UPDATE = 1, UPDATE_COMMAND_UPDATE = 1,
UPDATE_COMMAND_CHECK = 2, UPDATE_COMMAND_CHECK = 2,
}; };
#endif
} // namespace enums } // namespace enums
@@ -273,6 +303,7 @@ class StateResponseProtoMessage : public ProtoMessage {
public: public:
~StateResponseProtoMessage() override = default; ~StateResponseProtoMessage() override = default;
uint32_t key{0}; uint32_t key{0};
uint32_t device_id{0};
protected: protected:
}; };
@@ -523,6 +554,7 @@ class SubscribeStatesRequest : public ProtoMessage {
protected: protected:
}; };
#ifdef USE_BINARY_SENSOR
class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage { class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 12; static constexpr uint16_t MESSAGE_TYPE = 12;
@@ -546,7 +578,7 @@ class ListEntitiesBinarySensorResponse : public InfoResponseProtoMessage {
class BinarySensorStateResponse : public StateResponseProtoMessage { class BinarySensorStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 21; static constexpr uint16_t MESSAGE_TYPE = 21;
static constexpr uint16_t ESTIMATED_SIZE = 9; static constexpr uint16_t ESTIMATED_SIZE = 13;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "binary_sensor_state_response"; } const char *message_name() const override { return "binary_sensor_state_response"; }
#endif #endif
@@ -562,6 +594,8 @@ class BinarySensorStateResponse : public StateResponseProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_COVER
class ListEntitiesCoverResponse : public InfoResponseProtoMessage { class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 13; static constexpr uint16_t MESSAGE_TYPE = 13;
@@ -588,7 +622,7 @@ class ListEntitiesCoverResponse : public InfoResponseProtoMessage {
class CoverStateResponse : public StateResponseProtoMessage { class CoverStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 22; static constexpr uint16_t MESSAGE_TYPE = 22;
static constexpr uint16_t ESTIMATED_SIZE = 19; static constexpr uint16_t ESTIMATED_SIZE = 23;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "cover_state_response"; } const char *message_name() const override { return "cover_state_response"; }
#endif #endif
@@ -631,6 +665,8 @@ class CoverCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_FAN
class ListEntitiesFanResponse : public InfoResponseProtoMessage { class ListEntitiesFanResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 14; static constexpr uint16_t MESSAGE_TYPE = 14;
@@ -657,7 +693,7 @@ class ListEntitiesFanResponse : public InfoResponseProtoMessage {
class FanStateResponse : public StateResponseProtoMessage { class FanStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 23; static constexpr uint16_t MESSAGE_TYPE = 23;
static constexpr uint16_t ESTIMATED_SIZE = 26; static constexpr uint16_t ESTIMATED_SIZE = 30;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "fan_state_response"; } const char *message_name() const override { return "fan_state_response"; }
#endif #endif
@@ -709,6 +745,8 @@ class FanCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_LIGHT
class ListEntitiesLightResponse : public InfoResponseProtoMessage { class ListEntitiesLightResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 15; static constexpr uint16_t MESSAGE_TYPE = 15;
@@ -738,7 +776,7 @@ class ListEntitiesLightResponse : public InfoResponseProtoMessage {
class LightStateResponse : public StateResponseProtoMessage { class LightStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 24; static constexpr uint16_t MESSAGE_TYPE = 24;
static constexpr uint16_t ESTIMATED_SIZE = 63; static constexpr uint16_t ESTIMATED_SIZE = 67;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "light_state_response"; } const char *message_name() const override { return "light_state_response"; }
#endif #endif
@@ -810,6 +848,8 @@ class LightCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_SENSOR
class ListEntitiesSensorResponse : public InfoResponseProtoMessage { class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 16; static constexpr uint16_t MESSAGE_TYPE = 16;
@@ -837,7 +877,7 @@ class ListEntitiesSensorResponse : public InfoResponseProtoMessage {
class SensorStateResponse : public StateResponseProtoMessage { class SensorStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 25; static constexpr uint16_t MESSAGE_TYPE = 25;
static constexpr uint16_t ESTIMATED_SIZE = 12; static constexpr uint16_t ESTIMATED_SIZE = 16;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "sensor_state_response"; } const char *message_name() const override { return "sensor_state_response"; }
#endif #endif
@@ -853,6 +893,8 @@ class SensorStateResponse : public StateResponseProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_SWITCH
class ListEntitiesSwitchResponse : public InfoResponseProtoMessage { class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 17; static constexpr uint16_t MESSAGE_TYPE = 17;
@@ -876,7 +918,7 @@ class ListEntitiesSwitchResponse : public InfoResponseProtoMessage {
class SwitchStateResponse : public StateResponseProtoMessage { class SwitchStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 26; static constexpr uint16_t MESSAGE_TYPE = 26;
static constexpr uint16_t ESTIMATED_SIZE = 7; static constexpr uint16_t ESTIMATED_SIZE = 11;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "switch_state_response"; } const char *message_name() const override { return "switch_state_response"; }
#endif #endif
@@ -910,6 +952,8 @@ class SwitchCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_TEXT_SENSOR
class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage { class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 18; static constexpr uint16_t MESSAGE_TYPE = 18;
@@ -932,7 +976,7 @@ class ListEntitiesTextSensorResponse : public InfoResponseProtoMessage {
class TextSensorStateResponse : public StateResponseProtoMessage { class TextSensorStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 27; static constexpr uint16_t MESSAGE_TYPE = 27;
static constexpr uint16_t ESTIMATED_SIZE = 16; static constexpr uint16_t ESTIMATED_SIZE = 20;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "text_sensor_state_response"; } const char *message_name() const override { return "text_sensor_state_response"; }
#endif #endif
@@ -949,6 +993,7 @@ class TextSensorStateResponse : public StateResponseProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
class SubscribeLogsRequest : public ProtoMessage { class SubscribeLogsRequest : public ProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 28; static constexpr uint16_t MESSAGE_TYPE = 28;
@@ -987,6 +1032,7 @@ class SubscribeLogsResponse : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#ifdef USE_API_NOISE
class NoiseEncryptionSetKeyRequest : public ProtoMessage { class NoiseEncryptionSetKeyRequest : public ProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 124; static constexpr uint16_t MESSAGE_TYPE = 124;
@@ -1021,6 +1067,7 @@ class NoiseEncryptionSetKeyResponse : public ProtoMessage {
protected: protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
class SubscribeHomeassistantServicesRequest : public ProtoMessage { class SubscribeHomeassistantServicesRequest : public ProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 34; static constexpr uint16_t MESSAGE_TYPE = 34;
@@ -1226,6 +1273,7 @@ class ExecuteServiceRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
}; };
#ifdef USE_CAMERA
class ListEntitiesCameraResponse : public InfoResponseProtoMessage { class ListEntitiesCameraResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 43; static constexpr uint16_t MESSAGE_TYPE = 43;
@@ -1283,6 +1331,8 @@ class CameraImageRequest : public ProtoMessage {
protected: protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_CLIMATE
class ListEntitiesClimateResponse : public InfoResponseProtoMessage { class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 46; static constexpr uint16_t MESSAGE_TYPE = 46;
@@ -1322,7 +1372,7 @@ class ListEntitiesClimateResponse : public InfoResponseProtoMessage {
class ClimateStateResponse : public StateResponseProtoMessage { class ClimateStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 47; static constexpr uint16_t MESSAGE_TYPE = 47;
static constexpr uint16_t ESTIMATED_SIZE = 65; static constexpr uint16_t ESTIMATED_SIZE = 70;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "climate_state_response"; } const char *message_name() const override { return "climate_state_response"; }
#endif #endif
@@ -1392,6 +1442,8 @@ class ClimateCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_NUMBER
class ListEntitiesNumberResponse : public InfoResponseProtoMessage { class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 49; static constexpr uint16_t MESSAGE_TYPE = 49;
@@ -1419,7 +1471,7 @@ class ListEntitiesNumberResponse : public InfoResponseProtoMessage {
class NumberStateResponse : public StateResponseProtoMessage { class NumberStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 50; static constexpr uint16_t MESSAGE_TYPE = 50;
static constexpr uint16_t ESTIMATED_SIZE = 12; static constexpr uint16_t ESTIMATED_SIZE = 16;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "number_state_response"; } const char *message_name() const override { return "number_state_response"; }
#endif #endif
@@ -1453,6 +1505,8 @@ class NumberCommandRequest : public ProtoMessage {
protected: protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
}; };
#endif
#ifdef USE_SELECT
class ListEntitiesSelectResponse : public InfoResponseProtoMessage { class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 52; static constexpr uint16_t MESSAGE_TYPE = 52;
@@ -1475,7 +1529,7 @@ class ListEntitiesSelectResponse : public InfoResponseProtoMessage {
class SelectStateResponse : public StateResponseProtoMessage { class SelectStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 53; static constexpr uint16_t MESSAGE_TYPE = 53;
static constexpr uint16_t ESTIMATED_SIZE = 16; static constexpr uint16_t ESTIMATED_SIZE = 20;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "select_state_response"; } const char *message_name() const override { return "select_state_response"; }
#endif #endif
@@ -1511,6 +1565,8 @@ class SelectCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
}; };
#endif
#ifdef USE_SIREN
class ListEntitiesSirenResponse : public InfoResponseProtoMessage { class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 55; static constexpr uint16_t MESSAGE_TYPE = 55;
@@ -1535,7 +1591,7 @@ class ListEntitiesSirenResponse : public InfoResponseProtoMessage {
class SirenStateResponse : public StateResponseProtoMessage { class SirenStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 56; static constexpr uint16_t MESSAGE_TYPE = 56;
static constexpr uint16_t ESTIMATED_SIZE = 7; static constexpr uint16_t ESTIMATED_SIZE = 11;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "siren_state_response"; } const char *message_name() const override { return "siren_state_response"; }
#endif #endif
@@ -1577,6 +1633,8 @@ class SirenCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_LOCK
class ListEntitiesLockResponse : public InfoResponseProtoMessage { class ListEntitiesLockResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 58; static constexpr uint16_t MESSAGE_TYPE = 58;
@@ -1602,7 +1660,7 @@ class ListEntitiesLockResponse : public InfoResponseProtoMessage {
class LockStateResponse : public StateResponseProtoMessage { class LockStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 59; static constexpr uint16_t MESSAGE_TYPE = 59;
static constexpr uint16_t ESTIMATED_SIZE = 7; static constexpr uint16_t ESTIMATED_SIZE = 11;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "lock_state_response"; } const char *message_name() const override { return "lock_state_response"; }
#endif #endif
@@ -1639,6 +1697,8 @@ class LockCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_BUTTON
class ListEntitiesButtonResponse : public InfoResponseProtoMessage { class ListEntitiesButtonResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 61; static constexpr uint16_t MESSAGE_TYPE = 61;
@@ -1675,6 +1735,8 @@ class ButtonCommandRequest : public ProtoMessage {
protected: protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
}; };
#endif
#ifdef USE_MEDIA_PLAYER
class MediaPlayerSupportedFormat : public ProtoMessage { class MediaPlayerSupportedFormat : public ProtoMessage {
public: public:
std::string format{}; std::string format{};
@@ -1715,7 +1777,7 @@ class ListEntitiesMediaPlayerResponse : public InfoResponseProtoMessage {
class MediaPlayerStateResponse : public StateResponseProtoMessage { class MediaPlayerStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 64; static constexpr uint16_t MESSAGE_TYPE = 64;
static constexpr uint16_t ESTIMATED_SIZE = 14; static constexpr uint16_t ESTIMATED_SIZE = 18;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "media_player_state_response"; } const char *message_name() const override { return "media_player_state_response"; }
#endif #endif
@@ -1759,6 +1821,8 @@ class MediaPlayerCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_BLUETOOTH_PROXY
class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage { class SubscribeBluetoothLEAdvertisementsRequest : public ProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 66; static constexpr uint16_t MESSAGE_TYPE = 66;
@@ -2313,6 +2377,8 @@ class BluetoothScannerSetModeRequest : public ProtoMessage {
protected: protected:
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_VOICE_ASSISTANT
class SubscribeVoiceAssistantRequest : public ProtoMessage { class SubscribeVoiceAssistantRequest : public ProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 89; static constexpr uint16_t MESSAGE_TYPE = 89;
@@ -2562,6 +2628,8 @@ class VoiceAssistantSetConfiguration : public ProtoMessage {
protected: protected:
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
}; };
#endif
#ifdef USE_ALARM_CONTROL_PANEL
class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage { class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 94; static constexpr uint16_t MESSAGE_TYPE = 94;
@@ -2586,7 +2654,7 @@ class ListEntitiesAlarmControlPanelResponse : public InfoResponseProtoMessage {
class AlarmControlPanelStateResponse : public StateResponseProtoMessage { class AlarmControlPanelStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 95; static constexpr uint16_t MESSAGE_TYPE = 95;
static constexpr uint16_t ESTIMATED_SIZE = 7; static constexpr uint16_t ESTIMATED_SIZE = 11;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "alarm_control_panel_state_response"; } const char *message_name() const override { return "alarm_control_panel_state_response"; }
#endif #endif
@@ -2622,6 +2690,8 @@ class AlarmControlPanelCommandRequest : public ProtoMessage {
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_TEXT
class ListEntitiesTextResponse : public InfoResponseProtoMessage { class ListEntitiesTextResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 97; static constexpr uint16_t MESSAGE_TYPE = 97;
@@ -2647,7 +2717,7 @@ class ListEntitiesTextResponse : public InfoResponseProtoMessage {
class TextStateResponse : public StateResponseProtoMessage { class TextStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 98; static constexpr uint16_t MESSAGE_TYPE = 98;
static constexpr uint16_t ESTIMATED_SIZE = 16; static constexpr uint16_t ESTIMATED_SIZE = 20;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "text_state_response"; } const char *message_name() const override { return "text_state_response"; }
#endif #endif
@@ -2683,6 +2753,8 @@ class TextCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
}; };
#endif
#ifdef USE_DATETIME_DATE
class ListEntitiesDateResponse : public InfoResponseProtoMessage { class ListEntitiesDateResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 100; static constexpr uint16_t MESSAGE_TYPE = 100;
@@ -2704,7 +2776,7 @@ class ListEntitiesDateResponse : public InfoResponseProtoMessage {
class DateStateResponse : public StateResponseProtoMessage { class DateStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 101; static constexpr uint16_t MESSAGE_TYPE = 101;
static constexpr uint16_t ESTIMATED_SIZE = 19; static constexpr uint16_t ESTIMATED_SIZE = 23;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "date_state_response"; } const char *message_name() const override { return "date_state_response"; }
#endif #endif
@@ -2743,6 +2815,8 @@ class DateCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_DATETIME_TIME
class ListEntitiesTimeResponse : public InfoResponseProtoMessage { class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 103; static constexpr uint16_t MESSAGE_TYPE = 103;
@@ -2764,7 +2838,7 @@ class ListEntitiesTimeResponse : public InfoResponseProtoMessage {
class TimeStateResponse : public StateResponseProtoMessage { class TimeStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 104; static constexpr uint16_t MESSAGE_TYPE = 104;
static constexpr uint16_t ESTIMATED_SIZE = 19; static constexpr uint16_t ESTIMATED_SIZE = 23;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "time_state_response"; } const char *message_name() const override { return "time_state_response"; }
#endif #endif
@@ -2803,6 +2877,8 @@ class TimeCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_EVENT
class ListEntitiesEventResponse : public InfoResponseProtoMessage { class ListEntitiesEventResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 107; static constexpr uint16_t MESSAGE_TYPE = 107;
@@ -2826,7 +2902,7 @@ class ListEntitiesEventResponse : public InfoResponseProtoMessage {
class EventResponse : public StateResponseProtoMessage { class EventResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 108; static constexpr uint16_t MESSAGE_TYPE = 108;
static constexpr uint16_t ESTIMATED_SIZE = 14; static constexpr uint16_t ESTIMATED_SIZE = 18;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "event_response"; } const char *message_name() const override { return "event_response"; }
#endif #endif
@@ -2840,7 +2916,10 @@ class EventResponse : public StateResponseProtoMessage {
protected: protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_VALVE
class ListEntitiesValveResponse : public InfoResponseProtoMessage { class ListEntitiesValveResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 109; static constexpr uint16_t MESSAGE_TYPE = 109;
@@ -2866,7 +2945,7 @@ class ListEntitiesValveResponse : public InfoResponseProtoMessage {
class ValveStateResponse : public StateResponseProtoMessage { class ValveStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 110; static constexpr uint16_t MESSAGE_TYPE = 110;
static constexpr uint16_t ESTIMATED_SIZE = 12; static constexpr uint16_t ESTIMATED_SIZE = 16;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "valve_state_response"; } const char *message_name() const override { return "valve_state_response"; }
#endif #endif
@@ -2903,6 +2982,8 @@ class ValveCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
#ifdef USE_DATETIME_DATETIME
class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage { class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 112; static constexpr uint16_t MESSAGE_TYPE = 112;
@@ -2924,7 +3005,7 @@ class ListEntitiesDateTimeResponse : public InfoResponseProtoMessage {
class DateTimeStateResponse : public StateResponseProtoMessage { class DateTimeStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 113; static constexpr uint16_t MESSAGE_TYPE = 113;
static constexpr uint16_t ESTIMATED_SIZE = 12; static constexpr uint16_t ESTIMATED_SIZE = 16;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "date_time_state_response"; } const char *message_name() const override { return "date_time_state_response"; }
#endif #endif
@@ -2958,6 +3039,8 @@ class DateTimeCommandRequest : public ProtoMessage {
protected: protected:
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
}; };
#endif
#ifdef USE_UPDATE
class ListEntitiesUpdateResponse : public InfoResponseProtoMessage { class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 116; static constexpr uint16_t MESSAGE_TYPE = 116;
@@ -2980,7 +3063,7 @@ class ListEntitiesUpdateResponse : public InfoResponseProtoMessage {
class UpdateStateResponse : public StateResponseProtoMessage { class UpdateStateResponse : public StateResponseProtoMessage {
public: public:
static constexpr uint16_t MESSAGE_TYPE = 117; static constexpr uint16_t MESSAGE_TYPE = 117;
static constexpr uint16_t ESTIMATED_SIZE = 61; static constexpr uint16_t ESTIMATED_SIZE = 65;
#ifdef HAS_PROTO_MESSAGE_DUMP #ifdef HAS_PROTO_MESSAGE_DUMP
const char *message_name() const override { return "update_state_response"; } const char *message_name() const override { return "update_state_response"; }
#endif #endif
@@ -3023,6 +3106,7 @@ class UpdateCommandRequest : public ProtoMessage {
bool decode_32bit(uint32_t field_id, Proto32Bit value) override; bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
bool decode_varint(uint32_t field_id, ProtoVarInt value) override; bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
}; };
#endif
} // namespace api } // namespace api
} // namespace esphome } // namespace esphome

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

View File

@@ -2,9 +2,10 @@
// See script/api_protobuf/api_protobuf.py // See script/api_protobuf/api_protobuf.py
#pragma once #pragma once
#include "api_pb2.h"
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "api_pb2.h"
namespace esphome { namespace esphome {
namespace api { namespace api {
@@ -70,7 +71,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_execute_service_request(const ExecuteServiceRequest &value){}; virtual void on_execute_service_request(const ExecuteServiceRequest &value){};
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
virtual void on_camera_image_request(const CameraImageRequest &value){}; virtual void on_camera_image_request(const CameraImageRequest &value){};
#endif #endif
@@ -199,7 +200,7 @@ class APIServerConnectionBase : public ProtoService {
virtual void on_update_command_request(const UpdateCommandRequest &value){}; virtual void on_update_command_request(const UpdateCommandRequest &value){};
#endif #endif
protected: 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 { class APIServerConnection : public APIServerConnectionBase {
@@ -222,7 +223,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BUTTON #ifdef USE_BUTTON
virtual void button_command(const ButtonCommandRequest &msg) = 0; virtual void button_command(const ButtonCommandRequest &msg) = 0;
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
virtual void camera_image(const CameraImageRequest &msg) = 0; virtual void camera_image(const CameraImageRequest &msg) = 0;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
@@ -339,7 +340,7 @@ class APIServerConnection : public APIServerConnectionBase {
#ifdef USE_BUTTON #ifdef USE_BUTTON
void on_button_command_request(const ButtonCommandRequest &msg) override; void on_button_command_request(const ButtonCommandRequest &msg) override;
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
void on_camera_image_request(const CameraImageRequest &msg) override; void on_camera_image_request(const CameraImageRequest &msg) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE

View File

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

View File

@@ -24,6 +24,14 @@ static const char *const TAG = "api";
// APIServer // APIServer
APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables) APIServer *global_api_server = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
#ifndef USE_API_YAML_SERVICES
// Global empty vector to avoid guard variables (saves 8 bytes)
// This is initialized at program startup before any threads
static const std::vector<UserServiceDescriptor *> empty_user_services{};
const std::vector<UserServiceDescriptor *> &get_empty_user_services_instance() { return empty_user_services; }
#endif
APIServer::APIServer() { APIServer::APIServer() {
global_api_server = this; global_api_server = this;
// Pre-allocate shared write buffer // Pre-allocate shared write buffer
@@ -96,7 +104,8 @@ void APIServer::setup() {
#ifdef USE_LOGGER #ifdef USE_LOGGER
if (logger::global_logger != nullptr) { if (logger::global_logger != nullptr) {
logger::global_logger->add_on_log_callback([this](int level, const char *tag, const char *message) { logger::global_logger->add_on_log_callback(
[this](int level, const char *tag, const char *message, size_t message_len) {
if (this->shutting_down_) { if (this->shutting_down_) {
// Don't try to send logs during shutdown // Don't try to send logs during shutdown
// as it could result in a recursion and // as it could result in a recursion and
@@ -104,19 +113,18 @@ void APIServer::setup() {
return; return;
} }
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->remove_) if (!c->flags_.remove)
c->try_send_log_message(level, tag, message); c->try_send_log_message(level, tag, message, message_len);
} }
}); });
} }
#endif #endif
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
if (esp32_camera::global_esp32_camera != nullptr && !esp32_camera::global_esp32_camera->is_internal()) { if (camera::Camera::instance() != nullptr && !camera::Camera::instance()->is_internal()) {
esp32_camera::global_esp32_camera->add_image_callback( camera::Camera::instance()->add_image_callback([this](const std::shared_ptr<camera::CameraImage> &image) {
[this](const std::shared_ptr<esp32_camera::CameraImage> &image) {
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->remove_) if (!c->flags_.remove)
c->set_camera_state(image); c->set_camera_state(image);
} }
}); });
@@ -176,7 +184,7 @@ void APIServer::loop() {
while (client_index < this->clients_.size()) { while (client_index < this->clients_.size()) {
auto &client = this->clients_[client_index]; auto &client = this->clients_[client_index];
if (!client->remove_) { if (!client->flags_.remove) {
// Common case: process active client // Common case: process active client
client->loop(); client->loop();
client_index++; client_index++;
@@ -184,7 +192,9 @@ void APIServer::loop() {
} }
// Rare case: handle disconnection // Rare case: handle disconnection
#ifdef USE_API_CLIENT_DISCONNECTED_TRIGGER
this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_); this->client_disconnected_trigger_->trigger(client->client_info_, client->client_peername_);
#endif
ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str()); ESP_LOGV(TAG, "Remove connection %s", client->client_info_.c_str());
// Swap with the last element and pop (avoids expensive vector shifts) // Swap with the last element and pop (avoids expensive vector shifts)
@@ -216,6 +226,7 @@ void APIServer::dump_config() {
#endif #endif
} }
#ifdef USE_API_PASSWORD
bool APIServer::uses_password() const { return !this->password_.empty(); } bool APIServer::uses_password() const { return !this->password_.empty(); }
bool APIServer::check_password(const std::string &password) const { bool APIServer::check_password(const std::string &password) const {
@@ -246,192 +257,129 @@ bool APIServer::check_password(const std::string &password) const {
return result == 0; return result == 0;
} }
#endif
void APIServer::handle_disconnect(APIConnection *conn) {} void APIServer::handle_disconnect(APIConnection *conn) {}
// Macro for entities without extra parameters
#define API_DISPATCH_UPDATE(entity_type, entity_name) \
void APIServer::on_##entity_name##_update(entity_type *obj) { /* NOLINT(bugprone-macro-parentheses) */ \
if (obj->is_internal()) \
return; \
for (auto &c : this->clients_) \
c->send_##entity_name##_state(obj); \
}
// Macro for entities with extra parameters (but parameters not used in send)
#define API_DISPATCH_UPDATE_IGNORE_PARAMS(entity_type, entity_name, ...) \
void APIServer::on_##entity_name##_update(entity_type *obj, __VA_ARGS__) { /* NOLINT(bugprone-macro-parentheses) */ \
if (obj->is_internal()) \
return; \
for (auto &c : this->clients_) \
c->send_##entity_name##_state(obj); \
}
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) { API_DISPATCH_UPDATE(binary_sensor::BinarySensor, binary_sensor)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_binary_sensor_state(obj);
}
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
void APIServer::on_cover_update(cover::Cover *obj) { API_DISPATCH_UPDATE(cover::Cover, cover)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_cover_state(obj);
}
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
void APIServer::on_fan_update(fan::Fan *obj) { API_DISPATCH_UPDATE(fan::Fan, fan)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_fan_state(obj);
}
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
void APIServer::on_light_update(light::LightState *obj) { API_DISPATCH_UPDATE(light::LightState, light)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_light_state(obj);
}
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
void APIServer::on_sensor_update(sensor::Sensor *obj, float state) { API_DISPATCH_UPDATE_IGNORE_PARAMS(sensor::Sensor, sensor, float state)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_sensor_state(obj);
}
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
void APIServer::on_switch_update(switch_::Switch *obj, bool state) { API_DISPATCH_UPDATE_IGNORE_PARAMS(switch_::Switch, switch, bool state)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_switch_state(obj);
}
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
void APIServer::on_text_sensor_update(text_sensor::TextSensor *obj, const std::string &state) { API_DISPATCH_UPDATE_IGNORE_PARAMS(text_sensor::TextSensor, text_sensor, const std::string &state)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_text_sensor_state(obj);
}
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
void APIServer::on_climate_update(climate::Climate *obj) { API_DISPATCH_UPDATE(climate::Climate, climate)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_climate_state(obj);
}
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
void APIServer::on_number_update(number::Number *obj, float state) { API_DISPATCH_UPDATE_IGNORE_PARAMS(number::Number, number, float state)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_number_state(obj);
}
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
void APIServer::on_date_update(datetime::DateEntity *obj) { API_DISPATCH_UPDATE(datetime::DateEntity, date)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_date_state(obj);
}
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
void APIServer::on_time_update(datetime::TimeEntity *obj) { API_DISPATCH_UPDATE(datetime::TimeEntity, time)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_time_state(obj);
}
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
void APIServer::on_datetime_update(datetime::DateTimeEntity *obj) { API_DISPATCH_UPDATE(datetime::DateTimeEntity, datetime)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_datetime_state(obj);
}
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
void APIServer::on_text_update(text::Text *obj, const std::string &state) { API_DISPATCH_UPDATE_IGNORE_PARAMS(text::Text, text, const std::string &state)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_text_state(obj);
}
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
void APIServer::on_select_update(select::Select *obj, const std::string &state, size_t index) { API_DISPATCH_UPDATE_IGNORE_PARAMS(select::Select, select, const std::string &state, size_t index)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_select_state(obj);
}
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
void APIServer::on_lock_update(lock::Lock *obj) { API_DISPATCH_UPDATE(lock::Lock, lock)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_lock_state(obj);
}
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
void APIServer::on_valve_update(valve::Valve *obj) { API_DISPATCH_UPDATE(valve::Valve, valve)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_valve_state(obj);
}
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
void APIServer::on_media_player_update(media_player::MediaPlayer *obj) { API_DISPATCH_UPDATE(media_player::MediaPlayer, media_player)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_media_player_state(obj);
}
#endif #endif
#ifdef USE_EVENT #ifdef USE_EVENT
// Event is a special case - it's the only entity that passes extra parameters to the send method
void APIServer::on_event(event::Event *obj, const std::string &event_type) { void APIServer::on_event(event::Event *obj, const std::string &event_type) {
if (obj->is_internal())
return;
for (auto &c : this->clients_) for (auto &c : this->clients_)
c->send_event(obj, event_type); c->send_event(obj, event_type);
} }
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
// Update is a special case - the method is called on_update, not on_update_update
void APIServer::on_update(update::UpdateEntity *obj) { void APIServer::on_update(update::UpdateEntity *obj) {
if (obj->is_internal())
return;
for (auto &c : this->clients_) for (auto &c : this->clients_)
c->send_update_state(obj); c->send_update_state(obj);
} }
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #ifdef USE_ALARM_CONTROL_PANEL
void APIServer::on_alarm_control_panel_update(alarm_control_panel::AlarmControlPanel *obj) { API_DISPATCH_UPDATE(alarm_control_panel::AlarmControlPanel, alarm_control_panel)
if (obj->is_internal())
return;
for (auto &c : this->clients_)
c->send_alarm_control_panel_state(obj);
}
#endif #endif
float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; } float APIServer::get_setup_priority() const { return setup_priority::AFTER_WIFI; }
void APIServer::set_port(uint16_t port) { this->port_ = port; } void APIServer::set_port(uint16_t port) { this->port_ = port; }
#ifdef USE_API_PASSWORD
void APIServer::set_password(const std::string &password) { this->password_ = password; } void APIServer::set_password(const std::string &password) { this->password_ = password; }
#endif
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) { void APIServer::send_homeassistant_service_call(const HomeassistantServiceResponse &call) {
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
@@ -502,7 +450,7 @@ bool APIServer::save_noise_psk(psk_t psk, bool make_active) {
#ifdef USE_HOMEASSISTANT_TIME #ifdef USE_HOMEASSISTANT_TIME
void APIServer::request_time() { void APIServer::request_time() {
for (auto &client : this->clients_) { for (auto &client : this->clients_) {
if (!client->remove_ && client->is_authenticated()) if (!client->flags_.remove && client->is_authenticated())
client->send_time_request(); client->send_time_request();
} }
} }
@@ -526,8 +474,8 @@ void APIServer::on_shutdown() {
for (auto &c : this->clients_) { for (auto &c : this->clients_) {
if (!c->send_message(DisconnectRequest())) { if (!c->send_message(DisconnectRequest())) {
// If we can't send the disconnect request directly (tx_buffer full), // If we can't send the disconnect request directly (tx_buffer full),
// schedule it in the batch so it will be sent with the 5ms timer // schedule it at the front of the batch so it will be sent with priority
c->schedule_message_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE); c->schedule_message_front_(nullptr, &APIConnection::try_send_disconnect_request, DisconnectRequest::MESSAGE_TYPE);
} }
} }
} }

View File

@@ -25,6 +25,11 @@ struct SavedNoisePsk {
} PACKED; // NOLINT } PACKED; // NOLINT
#endif #endif
#ifndef USE_API_YAML_SERVICES
// Forward declaration of helper function
const std::vector<UserServiceDescriptor *> &get_empty_user_services_instance();
#endif
class APIServer : public Component, public Controller { class APIServer : public Component, public Controller {
public: public:
APIServer(); APIServer();
@@ -35,13 +40,15 @@ class APIServer : public Component, public Controller {
void dump_config() override; void dump_config() override;
void on_shutdown() override; void on_shutdown() override;
bool teardown() override; bool teardown() override;
#ifdef USE_API_PASSWORD
bool check_password(const std::string &password) const; bool check_password(const std::string &password) const;
bool uses_password() const; bool uses_password() const;
void set_port(uint16_t port);
void set_password(const std::string &password); void set_password(const std::string &password);
#endif
void set_port(uint16_t port);
void set_reboot_timeout(uint32_t reboot_timeout); void set_reboot_timeout(uint32_t reboot_timeout);
void set_batch_delay(uint32_t batch_delay); void set_batch_delay(uint16_t batch_delay);
uint32_t get_batch_delay() const { return batch_delay_; } uint16_t get_batch_delay() const { return batch_delay_; }
// Get reference to shared buffer for API connections // Get reference to shared buffer for API connections
std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; } std::vector<uint8_t> &get_shared_buffer_ref() { return shared_write_buffer_; }
@@ -105,7 +112,18 @@ class APIServer : public Component, public Controller {
void on_media_player_update(media_player::MediaPlayer *obj) override; void on_media_player_update(media_player::MediaPlayer *obj) override;
#endif #endif
void send_homeassistant_service_call(const HomeassistantServiceResponse &call); 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 #ifdef USE_HOMEASSISTANT_TIME
void request_time(); void request_time();
#endif #endif
@@ -134,35 +152,63 @@ class APIServer : public Component, public Controller {
void get_home_assistant_state(std::string entity_id, optional<std::string> attribute, void get_home_assistant_state(std::string entity_id, optional<std::string> attribute,
std::function<void(std::string)> f); std::function<void(std::string)> f);
const std::vector<HomeAssistantStateSubscription> &get_state_subs() const; 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
if (this->user_services_) {
return *this->user_services_;
}
// Return reference to global empty instance (no guard needed)
return get_empty_user_services_instance();
#endif
}
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *get_client_connected_trigger() const { return this->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 { Trigger<std::string, std::string> *get_client_disconnected_trigger() const {
return this->client_disconnected_trigger_; return this->client_disconnected_trigger_;
} }
#endif
protected: protected:
void schedule_reboot_timeout_(); void schedule_reboot_timeout_();
// Pointers and pointer-like types first (4 bytes each) // Pointers and pointer-like types first (4 bytes each)
std::unique_ptr<socket::Socket> socket_ = nullptr; std::unique_ptr<socket::Socket> socket_ = nullptr;
#ifdef USE_API_CLIENT_CONNECTED_TRIGGER
Trigger<std::string, std::string> *client_connected_trigger_ = new Trigger<std::string, std::string>(); 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>(); Trigger<std::string, std::string> *client_disconnected_trigger_ = new Trigger<std::string, std::string>();
#endif
// 4-byte aligned types // 4-byte aligned types
uint32_t reboot_timeout_{300000}; uint32_t reboot_timeout_{300000};
uint32_t batch_delay_{100};
// Vectors and strings (12 bytes each on 32-bit) // Vectors and strings (12 bytes each on 32-bit)
std::vector<std::unique_ptr<APIConnection>> clients_; std::vector<std::unique_ptr<APIConnection>> clients_;
#ifdef USE_API_PASSWORD
std::string password_; std::string password_;
#endif
std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections std::vector<uint8_t> shared_write_buffer_; // Shared proto write buffer for all connections
std::vector<HomeAssistantStateSubscription> state_subs_; 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_; 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 // Group smaller types together
uint16_t port_{6053}; uint16_t port_{6053};
uint16_t batch_delay_{100};
bool shutting_down_ = false; bool shutting_down_ = false;
// 3 bytes used, 1 byte padding // 5 bytes used, 3 bytes padding
#ifdef USE_API_NOISE #ifdef USE_API_NOISE
std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>(); std::shared_ptr<APINoiseContext> noise_ctx_ = std::make_shared<APINoiseContext>();

View File

@@ -4,9 +4,15 @@ import asyncio
from datetime import datetime from datetime import datetime
import logging import logging
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
import warnings
from aioesphomeapi import APIClient, parse_log_message # Suppress protobuf version warnings
from aioesphomeapi.log_runner import async_run 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.const import CONF_KEY, CONF_PASSWORD, CONF_PORT, __version__
from esphome.core import CORE 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]) port: int = int(conf[CONF_PORT])
password: str = conf[CONF_PASSWORD] password: str = conf[CONF_PASSWORD]
noise_psk: str | None = None noise_psk: str | None = None
if CONF_ENCRYPTION in conf: if (encryption := conf.get(CONF_ENCRYPTION)) and (key := encryption.get(CONF_KEY)):
noise_psk = conf[CONF_ENCRYPTION][CONF_KEY] noise_psk = key
_LOGGER.info("Starting log output from %s using esphome API", address) _LOGGER.info("Starting log output from %s using esphome API", address)
cli = APIClient( cli = APIClient(
address, address,

View File

@@ -1,6 +1,7 @@
#include "list_entities.h" #include "list_entities.h"
#ifdef USE_API #ifdef USE_API
#include "api_connection.h" #include "api_connection.h"
#include "api_pb2.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/util.h" #include "esphome/core/util.h"
@@ -8,155 +9,85 @@
namespace esphome { namespace esphome {
namespace api { namespace api {
// Generate entity handler implementations using macros
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool ListEntitiesIterator::on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) { LIST_ENTITIES_HANDLER(binary_sensor, binary_sensor::BinarySensor, ListEntitiesBinarySensorResponse)
this->client_->send_binary_sensor_info(binary_sensor);
return true;
}
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool ListEntitiesIterator::on_cover(cover::Cover *cover) { LIST_ENTITIES_HANDLER(cover, cover::Cover, ListEntitiesCoverResponse)
this->client_->send_cover_info(cover);
return true;
}
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool ListEntitiesIterator::on_fan(fan::Fan *fan) { LIST_ENTITIES_HANDLER(fan, fan::Fan, ListEntitiesFanResponse)
this->client_->send_fan_info(fan);
return true;
}
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool ListEntitiesIterator::on_light(light::LightState *light) { LIST_ENTITIES_HANDLER(light, light::LightState, ListEntitiesLightResponse)
this->client_->send_light_info(light);
return true;
}
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool ListEntitiesIterator::on_sensor(sensor::Sensor *sensor) { LIST_ENTITIES_HANDLER(sensor, sensor::Sensor, ListEntitiesSensorResponse)
this->client_->send_sensor_info(sensor);
return true;
}
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool ListEntitiesIterator::on_switch(switch_::Switch *a_switch) { LIST_ENTITIES_HANDLER(switch, switch_::Switch, ListEntitiesSwitchResponse)
this->client_->send_switch_info(a_switch);
return true;
}
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
bool ListEntitiesIterator::on_button(button::Button *button) { LIST_ENTITIES_HANDLER(button, button::Button, ListEntitiesButtonResponse)
this->client_->send_button_info(button);
return true;
}
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool ListEntitiesIterator::on_text_sensor(text_sensor::TextSensor *text_sensor) { LIST_ENTITIES_HANDLER(text_sensor, text_sensor::TextSensor, ListEntitiesTextSensorResponse)
this->client_->send_text_sensor_info(text_sensor);
return true;
}
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool ListEntitiesIterator::on_lock(lock::Lock *a_lock) { LIST_ENTITIES_HANDLER(lock, lock::Lock, ListEntitiesLockResponse)
this->client_->send_lock_info(a_lock);
return true;
}
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool ListEntitiesIterator::on_valve(valve::Valve *valve) { LIST_ENTITIES_HANDLER(valve, valve::Valve, ListEntitiesValveResponse)
this->client_->send_valve_info(valve); #endif
return true; #ifdef USE_CAMERA
} LIST_ENTITIES_HANDLER(camera, camera::Camera, 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 #endif
// Special cases that don't follow the pattern
bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); } bool ListEntitiesIterator::on_end() { return this->client_->send_list_info_done(); }
ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {} ListEntitiesIterator::ListEntitiesIterator(APIConnection *client) : client_(client) {}
bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) { bool ListEntitiesIterator::on_service(UserServiceDescriptor *service) {
auto resp = service->encode_list_service_response(); auto resp = service->encode_list_service_response();
return this->client_->send_message(resp); 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 api
} // namespace esphome } // namespace esphome
#endif #endif

View File

@@ -9,75 +9,83 @@ namespace api {
class APIConnection; 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 { class ListEntitiesIterator : public ComponentIterator {
public: public:
ListEntitiesIterator(APIConnection *client); ListEntitiesIterator(APIConnection *client);
#ifdef USE_BINARY_SENSOR #ifdef USE_BINARY_SENSOR
bool on_binary_sensor(binary_sensor::BinarySensor *binary_sensor) override; bool on_binary_sensor(binary_sensor::BinarySensor *entity) override;
#endif #endif
#ifdef USE_COVER #ifdef USE_COVER
bool on_cover(cover::Cover *cover) override; bool on_cover(cover::Cover *entity) override;
#endif #endif
#ifdef USE_FAN #ifdef USE_FAN
bool on_fan(fan::Fan *fan) override; bool on_fan(fan::Fan *entity) override;
#endif #endif
#ifdef USE_LIGHT #ifdef USE_LIGHT
bool on_light(light::LightState *light) override; bool on_light(light::LightState *entity) override;
#endif #endif
#ifdef USE_SENSOR #ifdef USE_SENSOR
bool on_sensor(sensor::Sensor *sensor) override; bool on_sensor(sensor::Sensor *entity) override;
#endif #endif
#ifdef USE_SWITCH #ifdef USE_SWITCH
bool on_switch(switch_::Switch *a_switch) override; bool on_switch(switch_::Switch *entity) override;
#endif #endif
#ifdef USE_BUTTON #ifdef USE_BUTTON
bool on_button(button::Button *button) override; bool on_button(button::Button *entity) override;
#endif #endif
#ifdef USE_TEXT_SENSOR #ifdef USE_TEXT_SENSOR
bool on_text_sensor(text_sensor::TextSensor *text_sensor) override; bool on_text_sensor(text_sensor::TextSensor *entity) override;
#endif #endif
bool on_service(UserServiceDescriptor *service) override; bool on_service(UserServiceDescriptor *service) override;
#ifdef USE_ESP32_CAMERA #ifdef USE_CAMERA
bool on_camera(esp32_camera::ESP32Camera *camera) override; bool on_camera(camera::Camera *entity) override;
#endif #endif
#ifdef USE_CLIMATE #ifdef USE_CLIMATE
bool on_climate(climate::Climate *climate) override; bool on_climate(climate::Climate *entity) override;
#endif #endif
#ifdef USE_NUMBER #ifdef USE_NUMBER
bool on_number(number::Number *number) override; bool on_number(number::Number *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATE #ifdef USE_DATETIME_DATE
bool on_date(datetime::DateEntity *date) override; bool on_date(datetime::DateEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_TIME #ifdef USE_DATETIME_TIME
bool on_time(datetime::TimeEntity *time) override; bool on_time(datetime::TimeEntity *entity) override;
#endif #endif
#ifdef USE_DATETIME_DATETIME #ifdef USE_DATETIME_DATETIME
bool on_datetime(datetime::DateTimeEntity *datetime) override; bool on_datetime(datetime::DateTimeEntity *entity) override;
#endif #endif
#ifdef USE_TEXT #ifdef USE_TEXT
bool on_text(text::Text *text) override; bool on_text(text::Text *entity) override;
#endif #endif
#ifdef USE_SELECT #ifdef USE_SELECT
bool on_select(select::Select *select) override; bool on_select(select::Select *entity) override;
#endif #endif
#ifdef USE_LOCK #ifdef USE_LOCK
bool on_lock(lock::Lock *a_lock) override; bool on_lock(lock::Lock *entity) override;
#endif #endif
#ifdef USE_VALVE #ifdef USE_VALVE
bool on_valve(valve::Valve *valve) override; bool on_valve(valve::Valve *entity) override;
#endif #endif
#ifdef USE_MEDIA_PLAYER #ifdef USE_MEDIA_PLAYER
bool on_media_player(media_player::MediaPlayer *media_player) override; bool on_media_player(media_player::MediaPlayer *entity) override;
#endif #endif
#ifdef USE_ALARM_CONTROL_PANEL #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 #endif
#ifdef USE_EVENT #ifdef USE_EVENT
bool on_event(event::Event *event) override; bool on_event(event::Event *entity) override;
#endif #endif
#ifdef USE_UPDATE #ifdef USE_UPDATE
bool on_update(update::UpdateEntity *update) override; bool on_update(update::UpdateEntity *entity) override;
#endif #endif
bool on_end() override; bool on_end() override;
bool completed() { return this->state_ == IteratorState::NONE; } bool completed() { return this->state_ == IteratorState::NONE; }

View File

@@ -364,7 +364,7 @@ class ProtoService {
*/ */
virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0; virtual ProtoWriteBuffer create_buffer(uint32_t reserve_size) = 0;
virtual bool send_buffer(ProtoWriteBuffer buffer, uint16_t message_type) = 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 // Optimized method that pre-allocates buffer based on message size
bool send_message_(const ProtoMessage &msg, uint16_t message_type) { bool send_message_(const ProtoMessage &msg, uint16_t message_type) {

View File

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

View File

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

View File

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

View File

@@ -5,6 +5,7 @@ from esphome.const import (
PLATFORM_BK72XX, PLATFORM_BK72XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_LN882X,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@@ -14,7 +15,15 @@ CODEOWNERS = ["@OttoWinter"]
CONFIG_SCHEMA = cv.All( CONFIG_SCHEMA = cv.All(
cv.Schema({}), cv.Schema({}),
cv.only_with_arduino, 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; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() 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_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }
void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; }
void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; } void set_battery_level(sensor::Sensor *battery_level) { battery_level_ = battery_level; }

View File

@@ -1,6 +1,7 @@
#include "atm90e32.h" #include "atm90e32.h"
#include <cinttypes> #include <cinttypes>
#include <cmath> #include <cmath>
#include <numbers>
#include "esphome/core/log.h" #include "esphome/core/log.h"
namespace esphome { 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 nominal_voltage = (line_freq == 60) ? 120.0f : 220.0f;
float target_voltage = nominal_voltage * multiplier; 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 divider = (2.0f * ugain) / 32768.0f;
float threshold = peak_01v / divider; float threshold = peak_01v / divider;

View File

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

View File

@@ -5,6 +5,7 @@
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE #if CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
#include "esp_crt_bundle.h" #include "esp_crt_bundle.h"
@@ -16,13 +17,13 @@ namespace audio {
static const uint32_t READ_WRITE_TIMEOUT_MS = 20; static const uint32_t READ_WRITE_TIMEOUT_MS = 20;
static const uint32_t CONNECTION_TIMEOUT_MS = 5000; static const uint32_t CONNECTION_TIMEOUT_MS = 5000;
static const uint8_t MAX_FETCHING_HEADER_ATTEMPTS = 6;
// 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 size_t HTTP_STREAM_BUFFER_SIZE = 2048; 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 // Some common HTTP status codes - borrowed from http_request component accessed 20241224
enum HttpStatus { 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.url = uri.c_str();
client_config.cert_pem = nullptr; client_config.cert_pem = nullptr;
client_config.disable_auto_redirect = false; 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.event_handler = http_event_handler;
client_config.user_data = this; client_config.user_data = this;
client_config.buffer_size = HTTP_STREAM_BUFFER_SIZE; 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); esp_err_t err = esp_http_client_open(this->client_, 0);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open URL");
this->cleanup_connection_(); this->cleanup_connection_();
return err; return err;
} }
int64_t header_length = esp_http_client_fetch_headers(this->client_); 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) { if (header_length < 0) {
ESP_LOGE(TAG, "Failed to fetch headers");
this->cleanup_connection_(); this->cleanup_connection_();
return ESP_FAIL; return ESP_FAIL;
} }
@@ -135,7 +153,7 @@ esp_err_t AudioReader::start(const std::string &uri, AudioFileType &file_type) {
ssize_t redirect_count = 0; 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); err = esp_http_client_open(this->client_, 0);
if (err != ESP_OK) { if (err != ESP_OK) {
this->cleanup_connection_(); this->cleanup_connection_();
@@ -267,21 +285,24 @@ AudioReaderState AudioReader::http_read_() {
return AudioReaderState::FINISHED; return AudioReaderState::FINISHED;
} }
} else if (this->output_transfer_buffer_->free() > 0) { } 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(),
int received_len = this->output_transfer_buffer_->free());
esp_http_client_read(this->client_, (char *) this->output_transfer_buffer_->get_buffer_end(), bytes_to_read);
if (received_len > 0) { if (received_len > 0) {
this->output_transfer_buffer_->increase_buffer_length(received_len); this->output_transfer_buffer_->increase_buffer_length(received_len);
this->last_data_read_ms_ = millis(); this->last_data_read_ms_ = millis();
} else if (received_len < 0) { return AudioReaderState::READING;
} else if (received_len <= 0) {
// HTTP read error // HTTP read error
if (received_len == -1) {
// A true connection error occured, no chance at recovery
this->cleanup_connection_(); this->cleanup_connection_();
return AudioReaderState::FAILED; return AudioReaderState::FAILED;
} else { }
if (bytes_to_read > 0) {
// Read timed out // Read timed out, manually verify if it has been too long since the last successful read
if ((millis() - this->last_data_read_ms_) > CONNECTION_TIMEOUT_MS) { if ((millis() - this->last_data_read_ms_) > MAX_FETCHING_HEADER_ATTEMPTS * CONNECTION_TIMEOUT_MS) {
ESP_LOGE(TAG, "Timed out");
this->cleanup_connection_(); this->cleanup_connection_();
return AudioReaderState::FAILED; return AudioReaderState::FAILED;
} }
@@ -289,7 +310,6 @@ AudioReaderState AudioReader::http_read_() {
delay(READ_WRITE_TIMEOUT_MS); delay(READ_WRITE_TIMEOUT_MS);
} }
} }
}
return AudioReaderState::READING; return AudioReaderState::READING;
} }

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; bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override;
void dump_config() 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_battery_voltage(sensor::Sensor *battery_voltage) { battery_voltage_ = battery_voltage; }
void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; }

View File

@@ -16,7 +16,6 @@ class BLEBinaryOutput : public output::BinaryOutput, public BLEClientNode, publi
public: public:
void dump_config() override; void dump_config() override;
void loop() 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_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_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); } 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 loop() override;
void update() override; void update() override;
void dump_config() 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; 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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() 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_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_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); } 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 loop() override {}
void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void write_state(bool state) override; 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, void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
esp_ble_gattc_cb_param_t *param) override; esp_ble_gattc_cb_param_t *param) override;
void dump_config() 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_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_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); } 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); this->set_found_(false);
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void set_found_(bool state) { void set_found_(bool state) {

View File

@@ -99,7 +99,6 @@ class BLERSSISensor : public sensor::Sensor, public esp32_ble_tracker::ESPBTDevi
return false; return false;
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
enum MatchType { MATCH_BY_MAC_ADDRESS, MATCH_BY_IRK, MATCH_BY_SERVICE_UUID, MATCH_BY_IBEACON_UUID }; 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; return true;
} }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
}; };
} // namespace ble_scanner } // namespace ble_scanner

View File

@@ -52,11 +52,21 @@ bool BluetoothProxy::parse_device(const esp32_ble_tracker::ESPBTDevice &device)
return true; return true;
} }
static constexpr size_t FLUSH_BATCH_SIZE = 8; // Batch size for BLE advertisements to maximize WiFi efficiency
static std::vector<api::BluetoothLERawAdvertisement> &get_batch_buffer() { // Each advertisement is up to 80 bytes when packaged (including protocol overhead)
static std::vector<api::BluetoothLERawAdvertisement> batch_buffer; // Most advertisements are 20-30 bytes, allowing even more to fit per packet
return batch_buffer; // 16 advertisements × 80 bytes (worst case) = 1280 bytes out of ~1320 bytes usable payload
} // This achieves ~97% WiFi MTU utilization while staying under the limit
static constexpr size_t FLUSH_BATCH_SIZE = 16;
namespace {
// Batch buffer in anonymous namespace to avoid guard variable (saves 8 bytes)
// This is initialized at program startup before any threads
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
std::vector<api::BluetoothLERawAdvertisement> batch_buffer;
} // namespace
static std::vector<api::BluetoothLERawAdvertisement> &get_batch_buffer() { return batch_buffer; }
bool BluetoothProxy::parse_devices(const esp32_ble::BLEScanResult *scan_results, size_t count) { bool BluetoothProxy::parse_devices(const esp32_ble::BLEScanResult *scan_results, size_t count) {
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_) if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr || !this->raw_advertisements_)
@@ -170,7 +180,7 @@ int BluetoothProxy::get_bluetooth_connections_free() {
void BluetoothProxy::loop() { void BluetoothProxy::loop() {
if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr) { if (!api::global_api_server->is_connected() || this->api_connection_ == nullptr) {
for (auto *connection : this->connections_) { for (auto *connection : this->connections_) {
if (connection->get_address() != 0) { if (connection->get_address() != 0 && !connection->disconnect_pending()) {
connection->disconnect(); connection->disconnect();
} }
} }

View File

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

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@DT-art1", "@bdraco"]

View File

@@ -0,0 +1,22 @@
#include "camera.h"
namespace esphome {
namespace camera {
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
Camera *Camera::global_camera = nullptr;
Camera::Camera() {
if (global_camera != nullptr) {
this->status_set_error("Multiple cameras are configured, but only one is supported.");
this->mark_failed();
return;
}
global_camera = this;
}
Camera *Camera::instance() { return global_camera; }
} // namespace camera
} // namespace esphome

View File

@@ -0,0 +1,80 @@
#pragma once
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
namespace esphome {
namespace camera {
/** Different sources for filtering.
* IDLE: Camera requests to send an image to the API.
* API_REQUESTER: API requests a new image.
* WEB_REQUESTER: ESP32 web server request an image. Ignored by API.
*/
enum CameraRequester : uint8_t { IDLE, API_REQUESTER, WEB_REQUESTER };
/** Abstract camera image base class.
* Encapsulates the JPEG encoded data and it is shared among
* all connected clients.
*/
class CameraImage {
public:
virtual uint8_t *get_data_buffer() = 0;
virtual size_t get_data_length() = 0;
virtual bool was_requested_by(CameraRequester requester) const = 0;
virtual ~CameraImage() {}
};
/** Abstract image reader base class.
* Keeps track of the data offset of the camera image and
* how many bytes are remaining to read. When the image
* is returned, the shared_ptr is reset and the camera can
* reuse the memory of the camera image.
*/
class CameraImageReader {
public:
virtual void set_image(std::shared_ptr<CameraImage> image) = 0;
virtual size_t available() const = 0;
virtual uint8_t *peek_data_buffer() = 0;
virtual void consume_data(size_t consumed) = 0;
virtual void return_image() = 0;
virtual ~CameraImageReader() {}
};
/** Abstract camera base class. Collaborates with API.
* 1) API server starts and installs callback (add_image_callback)
* which is called by the camera when a new image is available.
* 2) New API client connects and creates a new image reader (create_image_reader).
* 3) API connection receives protobuf CameraImageRequest and calls request_image.
* 3.a) API connection receives protobuf CameraImageRequest and calls start_stream.
* 4) Camera implementation provides JPEG data in the CameraImage and calls callback.
* 5) API connection sets the image in the image reader.
* 6) API connection consumes data from the image reader and returns the image when finished.
* 7.a) Camera captures a new image and continues with 4) until start_stream is called.
*/
class Camera : public EntityBase, public Component {
public:
Camera();
// Camera implementation invokes callback to publish a new image.
virtual void add_image_callback(std::function<void(std::shared_ptr<CameraImage>)> &&callback) = 0;
/// Returns a new camera image reader that keeps track of the JPEG data in the camera image.
virtual CameraImageReader *create_image_reader() = 0;
// Connection, camera or web server requests one new JPEG image.
virtual void request_image(CameraRequester requester) = 0;
// Connection, camera or web server requests a stream of images.
virtual void start_stream(CameraRequester requester) = 0;
// Connection or web server stops the previously started stream.
virtual void stop_stream(CameraRequester requester) = 0;
virtual ~Camera() {}
/// The singleton instance of the camera implementation.
static Camera *instance();
protected:
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static Camera *global_camera;
};
} // namespace camera
} // namespace esphome

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 set_reset_pin(GPIOPin *reset_pin) { this->reset_pin_ = reset_pin; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
void loop() override; void loop() override;
protected: protected:

View File

@@ -7,11 +7,12 @@ from esphome.const import (
PLATFORM_BK72XX, PLATFORM_BK72XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_LN882X,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
AUTO_LOAD = ["web_server_base"] AUTO_LOAD = ["web_server_base", "ota.web_server"]
DEPENDENCIES = ["wifi"] DEPENDENCIES = ["wifi"]
CODEOWNERS = ["@OttoWinter"] CODEOWNERS = ["@OttoWinter"]
@@ -27,7 +28,15 @@ CONFIG_SCHEMA = cv.All(
), ),
} }
).extend(cv.COMPONENT_SCHEMA), ).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,6 @@ void CaptivePortal::start() {
this->base_->init(); this->base_->init();
if (!this->initialized_) { if (!this->initialized_) {
this->base_->add_handler(this); this->base_->add_handler(this);
this->base_->add_ota_handler();
} }
#ifdef USE_ARDUINO #ifdef USE_ARDUINO

View File

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

View File

@@ -2,6 +2,7 @@
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
CONF_BYTE_ORDER = "byte_order"
CONF_DRAW_ROUNDING = "draw_rounding" CONF_DRAW_ROUNDING = "draw_rounding"
CONF_ON_STATE_CHANGE = "on_state_change" CONF_ON_STATE_CHANGE = "on_state_change"
CONF_REQUEST_HEADERS = "request_headers" CONF_REQUEST_HEADERS = "request_headers"

View File

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

View File

@@ -10,7 +10,6 @@ class CopyButton : public button::Button, public Component {
public: public:
void set_source(button::Button *source) { source_ = source; } void set_source(button::Button *source) { source_ = source; }
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void press_action() override; 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 set_source(cover::Cover *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
cover::CoverTraits get_traits() override; 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 set_source(fan::Fan *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
fan::FanTraits get_traits() override; 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 set_source(lock::Lock *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const lock::LockCall &call) override; 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 set_source(number::Number *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(float value) override; 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 set_source(select::Select *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const std::string &value) override; 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 set_source(sensor::Sensor *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
sensor::Sensor *source_; 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 set_source(switch_::Switch *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void write_state(bool state) override; 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 set_source(text::Text *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
void control(const std::string &value) override; 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 set_source(text_sensor::TextSensor *source) { source_ = source; }
void setup() override; void setup() override;
void dump_config() override; void dump_config() override;
float get_setup_priority() const override { return setup_priority::DATA; }
protected: protected:
text_sensor::TextSensor *source_; text_sensor::TextSensor *source_;

View File

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

View File

@@ -1,4 +1,5 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_BLOCK, CONF_BLOCK,
@@ -7,6 +8,7 @@ from esphome.const import (
CONF_FREE, CONF_FREE,
CONF_ID, CONF_ID,
CONF_LOOP_TIME, CONF_LOOP_TIME,
PlatformFramework,
) )
CODEOWNERS = ["@OttoWinter"] CODEOWNERS = ["@OttoWinter"]
@@ -44,3 +46,21 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"debug_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"debug_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"debug_host.cpp": {PlatformFramework.HOST_NATIVE},
"debug_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"debug_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@@ -1,6 +1,6 @@
from esphome import automation, pins from esphome import automation, pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import time from esphome.components import esp32, time
from esphome.components.esp32 import get_esp32_variant from esphome.components.esp32 import get_esp32_variant
from esphome.components.esp32.const import ( from esphome.components.esp32.const import (
VARIANT_ESP32, VARIANT_ESP32,
@@ -11,6 +11,7 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_DEFAULT, CONF_DEFAULT,
@@ -27,6 +28,7 @@ from esphome.const import (
CONF_WAKEUP_PIN, CONF_WAKEUP_PIN,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PlatformFramework,
) )
WAKEUP_PINS = { WAKEUP_PINS = {
@@ -114,12 +116,20 @@ def validate_pin_number(value):
return value return value
def validate_config(config): def _validate_ex1_wakeup_mode(value):
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_ESP32_EXT1_WAKEUP in config: if value == "ALL_LOW":
raise cv.Invalid("ESP32-C3 does not support wakeup from touch.") esp32.only_on_variant(supported=[VARIANT_ESP32], msg_prefix="ALL_LOW")(value)
if get_esp32_variant() == VARIANT_ESP32C3 and CONF_TOUCH_WAKEUP in config: if value == "ANY_LOW":
raise cv.Invalid("ESP32-C3 does not support wakeup from ext1") esp32.only_on_variant(
return config supported=[
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANT_ESP32C6,
VARIANT_ESP32H2,
],
msg_prefix="ANY_LOW",
)(value)
return value
deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep") deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep")
@@ -146,6 +156,7 @@ WAKEUP_PIN_MODES = {
esp_sleep_ext1_wakeup_mode_t = cg.global_ns.enum("esp_sleep_ext1_wakeup_mode_t") esp_sleep_ext1_wakeup_mode_t = cg.global_ns.enum("esp_sleep_ext1_wakeup_mode_t")
Ext1Wakeup = deep_sleep_ns.struct("Ext1Wakeup") Ext1Wakeup = deep_sleep_ns.struct("Ext1Wakeup")
EXT1_WAKEUP_MODES = { EXT1_WAKEUP_MODES = {
"ANY_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_LOW,
"ALL_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ALL_LOW, "ALL_LOW": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ALL_LOW,
"ANY_HIGH": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_HIGH, "ANY_HIGH": esp_sleep_ext1_wakeup_mode_t.ESP_EXT1_WAKEUP_ANY_HIGH,
} }
@@ -185,16 +196,28 @@ CONFIG_SCHEMA = cv.All(
), ),
cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All( cv.Optional(CONF_ESP32_EXT1_WAKEUP): cv.All(
cv.only_on_esp32, cv.only_on_esp32,
esp32.only_on_variant(
unsupported=[VARIANT_ESP32C3], msg_prefix="Wakeup from ext1"
),
cv.Schema( cv.Schema(
{ {
cv.Required(CONF_PINS): cv.ensure_list( cv.Required(CONF_PINS): cv.ensure_list(
pins.internal_gpio_input_pin_schema, validate_pin_number pins.internal_gpio_input_pin_schema, validate_pin_number
), ),
cv.Required(CONF_MODE): cv.enum(EXT1_WAKEUP_MODES, upper=True), cv.Required(CONF_MODE): cv.All(
cv.enum(EXT1_WAKEUP_MODES, upper=True),
_validate_ex1_wakeup_mode,
),
} }
), ),
), ),
cv.Optional(CONF_TOUCH_WAKEUP): cv.All(cv.only_on_esp32, cv.boolean), cv.Optional(CONF_TOUCH_WAKEUP): cv.All(
cv.only_on_esp32,
esp32.only_on_variant(
unsupported=[VARIANT_ESP32C3], msg_prefix="Wakeup from touch"
),
cv.boolean,
),
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]), cv.only_on([PLATFORM_ESP32, PLATFORM_ESP8266]),
@@ -313,3 +336,14 @@ async def deep_sleep_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
return var return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"deep_sleep_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"deep_sleep_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
}
)

View File

@@ -1,5 +1,6 @@
#include "display.h" #include "display.h"
#include <utility> #include <utility>
#include <numbers>
#include "display_color_utils.h" #include "display_color_utils.h"
#include "esphome/core/hal.h" #include "esphome/core/hal.h"
#include "esphome/core/log.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. // hence we rotate the shape by 270° to orient the polygon up.
rotation_degrees += ROTATION_270_DEGREES; rotation_degrees += ROTATION_270_DEGREES;
// Convert the rotation to radians, easier to use in trigonometrical calculations // 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 // 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. // 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, // 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 // 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. // 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_x = (int) round(cos(vertex_angle) * radius) + center_x;
*vertex_y = (int) round(sin(vertex_angle) * radius) + center_y; *vertex_y = (int) round(sin(vertex_angle) * radius) + center_y;
} }

View File

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

View File

@@ -0,0 +1 @@
CODEOWNERS = ["@mrk-its"]

View File

@@ -0,0 +1,209 @@
#include "ds2484.h"
namespace esphome {
namespace ds2484 {
static const char *const TAG = "ds2484.onewire";
void DS2484OneWireBus::setup() {
ESP_LOGCONFIG(TAG, "Running setup");
this->reset_device();
this->search();
}
void DS2484OneWireBus::dump_config() {
ESP_LOGCONFIG(TAG, "1-wire bus:");
this->dump_devices_(TAG);
}
bool DS2484OneWireBus::read_status_(uint8_t *status) {
for (uint8_t retry_nr = 0; retry_nr < 10; retry_nr++) {
if (this->read(status, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "read status error");
return false;
}
ESP_LOGVV(TAG, "status: %02x", *status);
if (!(*status & 1)) {
return true;
}
}
ESP_LOGE(TAG, "read status error: too many retries");
return false;
}
bool DS2484OneWireBus::wait_for_completion_() {
uint8_t status;
return this->read_status_(&status);
}
bool DS2484OneWireBus::reset_device() {
ESP_LOGVV(TAG, "reset_device");
uint8_t device_reset_cmd = 0xf0;
uint8_t response;
if (this->write(&device_reset_cmd, 1) != i2c::ERROR_OK) {
return false;
}
if (!this->wait_for_completion_()) {
ESP_LOGE(TAG, "reset_device: can't complete");
return false;
}
uint8_t config = (this->active_pullup_ ? 1 : 0) | (this->strong_pullup_ ? 4 : 0);
uint8_t write_config[2] = {0xd2, (uint8_t) (config | (~config << 4))};
if (this->write(write_config, 2) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "reset_device: can't write config");
return false;
}
if (this->read(&response, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "can't read read8 response");
return false;
}
if (response != (write_config[1] & 0xf)) {
ESP_LOGE(TAG, "configuration didn't update");
return false;
}
return true;
};
int DS2484OneWireBus::reset_int() {
ESP_LOGVV(TAG, "reset");
uint8_t reset_cmd = 0xb4;
if (this->write(&reset_cmd, 1) != i2c::ERROR_OK) {
return -1;
}
return this->wait_for_completion_() ? 1 : 0;
};
void DS2484OneWireBus::write8_(uint8_t value) {
uint8_t buffer[2] = {0xa5, value};
this->write(buffer, 2);
this->wait_for_completion_();
};
void DS2484OneWireBus::write8(uint8_t value) {
ESP_LOGVV(TAG, "write8: %02x", value);
this->write8_(value);
};
void DS2484OneWireBus::write64(uint64_t value) {
ESP_LOGVV(TAG, "write64: %llx", value);
for (uint8_t i = 0; i < 8; i++) {
this->write8_((value >> (i * 8)) & 0xff);
}
}
uint8_t DS2484OneWireBus::read8() {
uint8_t read8_cmd = 0x96;
uint8_t set_read_reg_cmd[2] = {0xe1, 0xe1};
uint8_t response = 0;
if (this->write(&read8_cmd, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "can't write read8 cmd");
return 0;
}
this->wait_for_completion_();
if (this->write(set_read_reg_cmd, 2) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "can't set read data reg");
return 0;
}
if (this->read(&response, 1) != i2c::ERROR_OK) {
ESP_LOGE(TAG, "can't read read8 response");
return 0;
}
return response;
}
uint64_t DS2484OneWireBus::read64() {
uint8_t response = 0;
for (uint8_t i = 0; i < 8; i++) {
response |= (this->read8() << (i * 8));
}
return response;
}
void DS2484OneWireBus::reset_search() {
this->last_discrepancy_ = 0;
this->last_device_flag_ = false;
this->address_ = 0;
}
bool DS2484OneWireBus::one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit) {
uint8_t buffer[2] = {(uint8_t) 0x78, (uint8_t) (*branch ? 0x80u : 0)};
uint8_t status;
if (!this->read_status_(&status)) {
ESP_LOGE(TAG, "one_wire_triple start: read status error");
return false;
}
if (this->write(buffer, 2) != i2c::ERROR_OK) {
ESP_LOGV(TAG, "one_wire_triple: can't write cmd");
return false;
}
if (!this->read_status_(&status)) {
ESP_LOGE(TAG, "one_wire_triple: read status error");
return false;
}
*id_bit = bool(status & 0x20);
*cmp_id_bit = bool(status & 0x40);
*branch = bool(status & 0x80);
return true;
}
uint64_t IRAM_ATTR DS2484OneWireBus::search_int() {
ESP_LOGVV(TAG, "search_int");
if (this->last_device_flag_) {
ESP_LOGVV(TAG, "last device flag set, quitting");
return 0u;
}
uint8_t last_zero = 0;
uint64_t bit_mask = 1;
uint64_t address = this->address_;
// Initiate search
for (uint8_t bit_number = 1; bit_number <= 64; bit_number++, bit_mask <<= 1) {
bool branch;
// compute branch value for the case when there is a discrepancy
// (there are devices with both 0s and 1s at this bit)
if (bit_number < this->last_discrepancy_) {
branch = (address & bit_mask) > 0;
} else {
branch = bit_number == this->last_discrepancy_;
}
bool id_bit, cmp_id_bit;
bool branch_before = branch;
if (!this->one_wire_triple_(&branch, &id_bit, &cmp_id_bit)) {
ESP_LOGW(TAG, "one wire triple error, quitting");
return 0;
}
if (id_bit && cmp_id_bit) {
ESP_LOGW(TAG, "no devices on the bus, quitting");
// No devices participating in search
return 0;
}
if (!id_bit && !cmp_id_bit && !branch) {
last_zero = bit_number;
}
ESP_LOGVV(TAG, "%d %d branch: %d %d", id_bit, cmp_id_bit, branch_before, branch);
if (branch) {
address |= bit_mask;
} else {
address &= ~bit_mask;
}
}
ESP_LOGVV(TAG, "last_discepancy: %d", last_zero);
ESP_LOGVV(TAG, "address: %llx", address);
this->last_discrepancy_ = last_zero;
if (this->last_discrepancy_ == 0) {
// we're at root and have no choices left, so this was the last one.
this->last_device_flag_ = true;
}
this->address_ = address;
return address;
}
} // namespace ds2484
} // namespace esphome

View File

@@ -0,0 +1,43 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/preferences.h"
#include "esphome/components/i2c/i2c.h"
#include "esphome/components/one_wire/one_wire.h"
namespace esphome {
namespace ds2484 {
class DS2484OneWireBus : public one_wire::OneWireBus, public i2c::I2CDevice, public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::BUS - 1.0; }
bool reset_device();
int reset_int() override;
void write8(uint8_t) override;
void write64(uint64_t) override;
uint8_t read8() override;
uint64_t read64() override;
void set_active_pullup(bool value) { this->active_pullup_ = value; }
void set_strong_pullup(bool value) { this->strong_pullup_ = value; }
protected:
void reset_search() override;
uint64_t search_int() override;
bool read_status_(uint8_t *);
bool wait_for_completion_();
void write8_(uint8_t);
bool one_wire_triple_(bool *branch, bool *id_bit, bool *cmp_id_bit);
uint64_t address_;
uint8_t last_discrepancy_{0};
bool last_device_flag_{false};
bool active_pullup_{false};
bool strong_pullup_{false};
};
} // namespace ds2484
} // namespace esphome

View File

@@ -0,0 +1,37 @@
import esphome.codegen as cg
from esphome.components import i2c
from esphome.components.one_wire import OneWireBus
import esphome.config_validation as cv
from esphome.const import CONF_ID
ds2484_ns = cg.esphome_ns.namespace("ds2484")
CONF_ACTIVE_PULLUP = "active_pullup"
CONF_STRONG_PULLUP = "strong_pullup"
CODEOWNERS = ["@mrk-its"]
DEPENDENCIES = ["i2c"]
DS2484OneWireBus = ds2484_ns.class_(
"DS2484OneWireBus", OneWireBus, i2c.I2CDevice, cg.Component
)
CONFIG_SCHEMA = (
cv.Schema(
{
cv.GenerateID(): cv.declare_id(DS2484OneWireBus),
cv.Optional(CONF_ACTIVE_PULLUP, default=False): cv.boolean,
cv.Optional(CONF_STRONG_PULLUP, default=False): cv.boolean,
}
)
.extend(cv.COMPONENT_SCHEMA)
.extend(i2c.i2c_device_schema(0x18))
)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await i2c.register_i2c_device(var, config)
await cg.register_component(var, config)
cg.add(var.set_active_pullup(config[CONF_ACTIVE_PULLUP]))
cg.add(var.set_strong_pullup(config[CONF_STRONG_PULLUP]))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -4,7 +4,7 @@ import logging
import os import os
from pathlib import Path from pathlib import Path
from esphome import git from esphome import yaml_util
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
@@ -23,7 +23,6 @@ from esphome.const import (
CONF_REFRESH, CONF_REFRESH,
CONF_SOURCE, CONF_SOURCE,
CONF_TYPE, CONF_TYPE,
CONF_URL,
CONF_VARIANT, CONF_VARIANT,
CONF_VERSION, CONF_VERSION,
KEY_CORE, KEY_CORE,
@@ -32,14 +31,13 @@ from esphome.const import (
KEY_TARGET_FRAMEWORK, KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM, KEY_TARGET_PLATFORM,
PLATFORM_ESP32, PLATFORM_ESP32,
TYPE_GIT,
TYPE_LOCAL,
__version__, __version__,
) )
from esphome.core import CORE, HexInt, TimePeriod from esphome.core import CORE, HexInt, TimePeriod
from esphome.cpp_generator import RawExpression from esphome.cpp_generator import RawExpression
import esphome.final_validate as fv import esphome.final_validate as fv
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
from esphome.types import ConfigType
from .boards import BOARDS from .boards import BOARDS
from .const import ( # noqa from .const import ( # noqa
@@ -49,10 +47,8 @@ from .const import ( # noqa
KEY_EXTRA_BUILD_FILES, KEY_EXTRA_BUILD_FILES,
KEY_PATH, KEY_PATH,
KEY_REF, KEY_REF,
KEY_REFRESH,
KEY_REPO, KEY_REPO,
KEY_SDKCONFIG_OPTIONS, KEY_SDKCONFIG_OPTIONS,
KEY_SUBMODULES,
KEY_VARIANT, KEY_VARIANT,
VARIANT_ESP32, VARIANT_ESP32,
VARIANT_ESP32C2, VARIANT_ESP32C2,
@@ -193,7 +189,7 @@ def get_download_types(storage_json):
] ]
def only_on_variant(*, supported=None, unsupported=None): def only_on_variant(*, supported=None, unsupported=None, msg_prefix="This feature"):
"""Config validator for features only available on some ESP32 variants.""" """Config validator for features only available on some ESP32 variants."""
if supported is not None and not isinstance(supported, list): if supported is not None and not isinstance(supported, list):
supported = [supported] supported = [supported]
@@ -204,11 +200,11 @@ def only_on_variant(*, supported=None, unsupported=None):
variant = get_esp32_variant() variant = get_esp32_variant()
if supported is not None and variant not in supported: if supported is not None and variant not in supported:
raise cv.Invalid( raise cv.Invalid(
f"This feature is only available on {', '.join(supported)}" f"{msg_prefix} is only available on {', '.join(supported)}"
) )
if unsupported is not None and variant in unsupported: if unsupported is not None and variant in unsupported:
raise cv.Invalid( raise cv.Invalid(
f"This feature is not available on {', '.join(unsupported)}" f"{msg_prefix} is not available on {', '.join(unsupported)}"
) )
return obj return obj
@@ -235,7 +231,7 @@ def add_idf_sdkconfig_option(name: str, value: SdkconfigValueType):
def add_idf_component( def add_idf_component(
*, *,
name: str, name: str,
repo: str, repo: str = None,
ref: str = None, ref: str = None,
path: str = None, path: str = None,
refresh: TimePeriod = None, refresh: TimePeriod = None,
@@ -245,30 +241,27 @@ def add_idf_component(
"""Add an esp-idf component to the project.""" """Add an esp-idf component to the project."""
if not CORE.using_esp_idf: if not CORE.using_esp_idf:
raise ValueError("Not an esp-idf project") raise ValueError("Not an esp-idf project")
if components is None: if not repo and not ref and not path:
components = [] raise ValueError("Requires at least one of repo, ref or path")
if name not in CORE.data[KEY_ESP32][KEY_COMPONENTS]: 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] = { CORE.data[KEY_ESP32][KEY_COMPONENTS][name] = {
KEY_REPO: repo, KEY_REPO: repo,
KEY_REF: ref, KEY_REF: ref,
KEY_PATH: path, 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): 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 # List based on https://github.com/pioarduino/esp-idf/releases
SUPPORTED_PIOARDUINO_ESP_IDF_5X = [ SUPPORTED_PIOARDUINO_ESP_IDF_5X = [
cv.Version(5, 5, 0), cv.Version(5, 5, 0),
cv.Version(5, 4, 2),
cv.Version(5, 4, 1), cv.Version(5, 4, 1),
cv.Version(5, 4, 0), cv.Version(5, 4, 0),
cv.Version(5, 3, 3), 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])) version = cv.Version.parse(cv.version_number(value[CONF_VERSION]))
source = value.get(CONF_SOURCE, None) source = value.get(CONF_SOURCE, None)
if version < cv.Version(4, 0, 0): if version < cv.Version(5, 0, 0):
raise cv.Invalid("Only ESP-IDF 4.0+ is supported.") raise cv.Invalid("Only ESP-IDF 5.0+ is supported.")
# flag this for later *before* we set value[CONF_PLATFORM_VERSION] below # flag this for later *before* we set value[CONF_PLATFORM_VERSION] below
has_platform_ver = CONF_PLATFORM_VERSION in value has_platform_ver = CONF_PLATFORM_VERSION in value
@@ -428,20 +422,15 @@ def _esp_idf_check_versions(value):
) )
if ( if (
(is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])) is_platformio := _platform_is_platformio(value[CONF_PLATFORM_VERSION])
and version.major >= 5 ) and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X:
and version not in SUPPORTED_PLATFORMIO_ESP_IDF_5X
):
raise cv.Invalid( raise cv.Invalid(
f"ESP-IDF {str(version)} not supported by platformio/espressif32" f"ESP-IDF {str(version)} not supported by platformio/espressif32"
) )
if ( if (
version.major < 5
or (
version in SUPPORTED_PLATFORMIO_ESP_IDF_5X version in SUPPORTED_PLATFORMIO_ESP_IDF_5X
and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X and version not in SUPPORTED_PIOARDUINO_ESP_IDF_5X
)
) and not has_platform_ver: ) and not has_platform_ver:
raise cv.Invalid( raise cv.Invalid(
f"ESP-IDF {value[CONF_VERSION]} may be supported by platformio/espressif32; please specify '{CONF_PLATFORM_VERSION}'" 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_MDNS_QUERIES = "enable_lwip_mdns_queries"
CONF_ENABLE_LWIP_BRIDGE_INTERFACE = "enable_lwip_bridge_interface" 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( ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
cv.Schema( cv.Schema(
{ {
@@ -606,7 +606,7 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
CONF_ENABLE_LWIP_DHCP_SERVER, "wifi", default=False CONF_ENABLE_LWIP_DHCP_SERVER, "wifi", default=False
): cv.boolean, ): cv.boolean,
cv.Optional( cv.Optional(
CONF_ENABLE_LWIP_MDNS_QUERIES, default=False CONF_ENABLE_LWIP_MDNS_QUERIES, default=True
): cv.boolean, ): cv.boolean,
cv.Optional( cv.Optional(
CONF_ENABLE_LWIP_BRIDGE_INTERFACE, default=False 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.Optional(CONF_COMPONENTS, default=[]): cv.ensure_list(
cv.All(
cv.Schema( cv.Schema(
{ {
cv.Required(CONF_NAME): cv.string_strict, cv.Required(CONF_NAME): cv.string_strict,
cv.Required(CONF_SOURCE): cv.SOURCE_SCHEMA, cv.Optional(CONF_SOURCE): cv.git_ref,
cv.Optional(CONF_REF): cv.string,
cv.Optional(CONF_PATH): cv.string, cv.Optional(CONF_PATH): cv.string,
cv.Optional(CONF_REFRESH, default="1d"): cv.All( cv.Optional(CONF_REFRESH): cv.All(
cv.string, cv.source_refresh cv.string, cv.source_refresh
), ),
} }
),
_validate_idf_component,
) )
), ),
} }
@@ -696,7 +700,7 @@ FINAL_VALIDATE_SCHEMA = cv.Schema(final_validate)
async def to_code(config): async def to_code(config):
cg.add_platformio_option("board", config[CONF_BOARD]) cg.add_platformio_option("board", config[CONF_BOARD])
cg.add_platformio_option("board_upload.flash_size", config[CONF_FLASH_SIZE]) 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_build_flag("-DUSE_ESP32")
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD]) cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}") 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_CPU0", False)
add_idf_sdkconfig_option("CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1", 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 # Set default CPU frequency
add_idf_sdkconfig_option(f"CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_{freq}", True) 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] and not advanced[CONF_ENABLE_LWIP_DHCP_SERVER]
): ):
add_idf_sdkconfig_option("CONFIG_LWIP_DHCPS", False) 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) add_idf_sdkconfig_option("CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES", False)
if not advanced.get(CONF_ENABLE_LWIP_BRIDGE_INTERFACE, False): if not advanced.get(CONF_ENABLE_LWIP_BRIDGE_INTERFACE, False):
add_idf_sdkconfig_option("CONFIG_LWIP_BRIDGEIF_MAX_PORTS", 0) 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): if advanced.get(CONF_IGNORE_EFUSE_MAC_CRC):
add_idf_sdkconfig_option("CONFIG_ESP_MAC_IGNORE_MAC_CRC_ERROR", True) 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( add_idf_sdkconfig_option(
"CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False "CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE", False
) )
else:
add_idf_sdkconfig_option(
"CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE", False
)
if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES): if advanced.get(CONF_ENABLE_IDF_EXPERIMENTAL_FEATURES):
_LOGGER.warning( _LOGGER.warning(
"Using experimental features in ESP-IDF may result in unexpected failures." "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)) add_idf_sdkconfig_option(name, RawSdkconfigValue(value))
for component in conf[CONF_COMPONENTS]: for component in conf[CONF_COMPONENTS]:
source = component[CONF_SOURCE]
if source[CONF_TYPE] == TYPE_GIT:
add_idf_component( add_idf_component(
name=component[CONF_NAME], name=component[CONF_NAME],
repo=source[CONF_URL], repo=component.get(CONF_SOURCE),
ref=source.get(CONF_REF), ref=component.get(CONF_REF),
path=component.get(CONF_PATH), path=component.get(CONF_PATH),
refresh=component[CONF_REFRESH],
) )
elif source[CONF_TYPE] == TYPE_LOCAL:
_LOGGER.warning("Local components are not implemented yet.")
elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO: elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO:
cg.add_platformio_option("framework", "arduino") cg.add_platformio_option("framework", "arduino")
cg.add_build_flag("-DUSE_ARDUINO") cg.add_build_flag("-DUSE_ARDUINO")
@@ -924,6 +920,26 @@ def _write_sdkconfig():
write_file_if_changed(sdk_path, contents) 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 # Called by writer.py
def copy_files(): def copy_files():
if CORE.using_arduino: if CORE.using_arduino:
@@ -936,6 +952,7 @@ def copy_files():
) )
if CORE.using_esp_idf: if CORE.using_esp_idf:
_write_sdkconfig() _write_sdkconfig()
_write_idf_component_yml()
if "partitions.csv" not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]: if "partitions.csv" not in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES]:
write_file_if_changed( write_file_if_changed(
CORE.relative_build_path("partitions.csv"), CORE.relative_build_path("partitions.csv"),
@@ -952,55 +969,6 @@ def copy_files():
__version__, __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(): for _, file in CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES].items():
if file[KEY_PATH].startswith("http"): if file[KEY_PATH].startswith("http"):
import requests import requests

View File

@@ -56,11 +56,7 @@ void arch_init() {
void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); } void IRAM_ATTR HOT arch_feed_wdt() { esp_task_wdt_reset(); }
uint8_t progmem_read_byte(const uint8_t *addr) { return *addr; } 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(); } 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 arch_get_cpu_freq_hz() {
uint32_t freq = 0; uint32_t freq = 0;
#ifdef USE_ESP_IDF #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; void attach_interrupt(void (*func)(void *), void *arg, gpio::InterruptType type) const override;
gpio_num_t pin_; gpio_num_t pin_;
bool inverted_;
gpio_drive_cap_t drive_strength_; gpio_drive_cap_t drive_strength_;
gpio::Flags flags_; gpio::Flags flags_;
bool inverted_;
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)
static bool isr_service_installed; static bool isr_service_installed;
}; };

View File

@@ -0,0 +1,69 @@
#include "esphome/core/helpers.h"
#ifdef USE_ESP32
#include "esp_efuse.h"
#include "esp_efuse_table.h"
#include "esp_mac.h"
#include <freertos/FreeRTOS.h>
#include <freertos/portmacro.h>
#include "esp_random.h"
#include "esp_system.h"
namespace esphome {
uint32_t random_uint32() { return esp_random(); }
bool random_bytes(uint8_t *data, size_t len) {
esp_fill_random(data, len);
return true;
}
Mutex::Mutex() { handle_ = xSemaphoreCreateMutex(); }
Mutex::~Mutex() {}
void Mutex::lock() { xSemaphoreTake(this->handle_, portMAX_DELAY); }
bool Mutex::try_lock() { return xSemaphoreTake(this->handle_, 0) == pdTRUE; }
void Mutex::unlock() { xSemaphoreGive(this->handle_); }
// only affects the executing core
// so should not be used as a mutex lock, only to get accurate timing
IRAM_ATTR InterruptLock::InterruptLock() { portDISABLE_INTERRUPTS(); }
IRAM_ATTR InterruptLock::~InterruptLock() { portENABLE_INTERRUPTS(); }
void get_mac_address_raw(uint8_t *mac) { // NOLINT(readability-non-const-parameter)
#if defined(CONFIG_SOC_IEEE802154_SUPPORTED)
// When CONFIG_SOC_IEEE802154_SUPPORTED is defined, esp_efuse_mac_get_default
// returns the 802.15.4 EUI-64 address, so we read directly from eFuse instead.
if (has_custom_mac_address()) {
esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48);
} else {
esp_efuse_read_field_blob(ESP_EFUSE_MAC_FACTORY, mac, 48);
}
#else
if (has_custom_mac_address()) {
esp_efuse_mac_get_custom(mac);
} else {
esp_efuse_mac_get_default(mac);
}
#endif
}
void set_mac_address(uint8_t *mac) { esp_base_mac_addr_set(mac); }
bool has_custom_mac_address() {
#if !defined(USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC)
uint8_t mac[6];
// do not use 'esp_efuse_mac_get_custom(mac)' because it drops an error in the logs whenever it fails
#ifndef USE_ESP32_VARIANT_ESP32
return (esp_efuse_read_field_blob(ESP_EFUSE_USER_DATA_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
#else
return (esp_efuse_read_field_blob(ESP_EFUSE_MAC_CUSTOM, mac, 48) == ESP_OK) && mac_address_is_valid(mac);
#endif
#else
return false;
#endif
}
} // namespace esphome
#endif // USE_ESP32

View File

@@ -1,7 +1,6 @@
#ifdef USE_ESP32 #ifdef USE_ESP32
#include "ble.h" #include "ble.h"
#include "ble_event_pool.h"
#include "esphome/core/application.h" #include "esphome/core/application.h"
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"

View File

@@ -12,8 +12,8 @@
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "ble_event.h" #include "ble_event.h"
#include "ble_event_pool.h" #include "esphome/core/lock_free_queue.h"
#include "queue.h" #include "esphome/core/event_pool.h"
#ifdef USE_ESP32 #ifdef USE_ESP32
@@ -25,10 +25,15 @@ namespace esphome {
namespace esp32_ble { namespace esp32_ble {
// Maximum number of BLE scan results to buffer // Maximum number of BLE scan results to buffer
// Sized to handle bursts of advertisements while allowing for processing delays
// With 16 advertisements per batch and some safety margin:
// - Without PSRAM: 24 entries (1.5× batch size)
// - With PSRAM: 36 entries (2.25× batch size)
// The reduced structure size (~80 bytes vs ~400 bytes) allows for larger buffers
#ifdef USE_PSRAM #ifdef USE_PSRAM
static constexpr uint8_t SCAN_RESULT_BUFFER_SIZE = 32; static constexpr uint8_t SCAN_RESULT_BUFFER_SIZE = 36;
#else #else
static constexpr uint8_t SCAN_RESULT_BUFFER_SIZE = 20; static constexpr uint8_t SCAN_RESULT_BUFFER_SIZE = 24;
#endif #endif
// Maximum size of the BLE event queue - must be power of 2 for lock-free queue // Maximum size of the BLE event queue - must be power of 2 for lock-free queue
@@ -51,7 +56,7 @@ enum IoCapability {
IO_CAP_KBDISP = ESP_IO_CAP_KBDISP, IO_CAP_KBDISP = ESP_IO_CAP_KBDISP,
}; };
enum BLEComponentState { enum BLEComponentState : uint8_t {
/** Nothing has been initialized yet. */ /** Nothing has been initialized yet. */
BLE_COMPONENT_STATE_OFF = 0, BLE_COMPONENT_STATE_OFF = 0,
/** BLE should be disabled on next loop. */ /** BLE should be disabled on next loop. */
@@ -141,21 +146,31 @@ class ESP32BLE : public Component {
private: private:
template<typename... Args> friend void enqueue_ble_event(Args... args); template<typename... Args> friend void enqueue_ble_event(Args... args);
// Vectors (12 bytes each on 32-bit, naturally aligned to 4 bytes)
std::vector<GAPEventHandler *> gap_event_handlers_; std::vector<GAPEventHandler *> gap_event_handlers_;
std::vector<GAPScanEventHandler *> gap_scan_event_handlers_; std::vector<GAPScanEventHandler *> gap_scan_event_handlers_;
std::vector<GATTcEventHandler *> gattc_event_handlers_; std::vector<GATTcEventHandler *> gattc_event_handlers_;
std::vector<GATTsEventHandler *> gatts_event_handlers_; std::vector<GATTsEventHandler *> gatts_event_handlers_;
std::vector<BLEStatusEventHandler *> ble_status_event_handlers_; std::vector<BLEStatusEventHandler *> ble_status_event_handlers_;
BLEComponentState state_{BLE_COMPONENT_STATE_OFF};
LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_; // Large objects (size depends on template parameters, but typically aligned to 4 bytes)
BLEEventPool<MAX_BLE_QUEUE_SIZE> ble_event_pool_; esphome::LockFreeQueue<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_events_;
BLEAdvertising *advertising_{}; esphome::EventPool<BLEEvent, MAX_BLE_QUEUE_SIZE> ble_event_pool_;
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE};
uint32_t advertising_cycle_time_{}; // optional<string> (typically 16+ bytes on 32-bit, aligned to 4 bytes)
bool enable_on_boot_{};
optional<std::string> name_; optional<std::string> name_;
uint16_t appearance_{0};
// 4-byte aligned members
BLEAdvertising *advertising_{}; // 4 bytes (pointer)
esp_ble_io_cap_t io_cap_{ESP_IO_CAP_NONE}; // 4 bytes (enum)
uint32_t advertising_cycle_time_{}; // 4 bytes
// 2-byte aligned members
uint16_t appearance_{0}; // 2 bytes
// 1-byte aligned members (grouped together to minimize padding)
BLEComponentState state_{BLE_COMPONENT_STATE_OFF}; // 1 byte (uint8_t enum)
bool enable_on_boot_{}; // 1 byte
}; };
// NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables)

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