esphome 2025.9.2__py3-none-any.whl → 2025.10.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (344) hide show
  1. esphome/__main__.py +87 -31
  2. esphome/address_cache.py +142 -0
  3. esphome/automation.py +130 -32
  4. esphome/build_gen/platformio.py +1 -3
  5. esphome/codegen.py +1 -0
  6. esphome/components/animation/animation.cpp +2 -2
  7. esphome/components/api/__init__.py +167 -3
  8. esphome/components/api/api_connection.cpp +84 -41
  9. esphome/components/api/api_connection.h +22 -16
  10. esphome/components/api/api_frame_helper.cpp +33 -19
  11. esphome/components/api/api_frame_helper.h +19 -4
  12. esphome/components/api/api_frame_helper_noise.cpp +41 -53
  13. esphome/components/api/api_frame_helper_noise.h +1 -1
  14. esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
  15. esphome/components/api/api_frame_helper_plaintext.h +1 -1
  16. esphome/components/api/api_pb2.cpp +189 -15
  17. esphome/components/api/api_pb2.h +132 -20
  18. esphome/components/api/api_pb2_dump.cpp +97 -9
  19. esphome/components/api/api_pb2_service.cpp +118 -160
  20. esphome/components/api/api_pb2_service.h +31 -3
  21. esphome/components/api/api_server.cpp +78 -11
  22. esphome/components/api/api_server.h +32 -4
  23. esphome/components/api/custom_api_device.h +8 -8
  24. esphome/components/api/homeassistant_service.h +123 -6
  25. esphome/components/api/proto.h +6 -2
  26. esphome/components/api/user_services.h +2 -2
  27. esphome/components/as7341/sensor.py +1 -1
  28. esphome/components/audio/__init__.py +1 -1
  29. esphome/components/audio/audio.cpp +1 -1
  30. esphome/components/audio/audio_decoder.cpp +9 -9
  31. esphome/components/bl0906/bl0906.cpp +2 -2
  32. esphome/components/bl0942/bl0942.cpp +2 -2
  33. esphome/components/ble_client/__init__.py +1 -1
  34. esphome/components/bluetooth_proxy/__init__.py +4 -30
  35. esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
  36. esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
  37. esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
  38. esphome/components/camera_encoder/__init__.py +2 -4
  39. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
  40. esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
  41. esphome/components/canbus/canbus.cpp +7 -5
  42. esphome/components/canbus/canbus.h +4 -4
  43. esphome/components/captive_portal/__init__.py +18 -1
  44. esphome/components/captive_portal/captive_portal.cpp +40 -46
  45. esphome/components/captive_portal/captive_portal.h +20 -22
  46. esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
  47. esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
  48. esphome/components/ccs811/ccs811.cpp +1 -1
  49. esphome/components/climate/climate.cpp +10 -7
  50. esphome/components/cm1106/cm1106.cpp +1 -1
  51. esphome/components/copy/lock/copy_lock.cpp +1 -1
  52. esphome/components/cover/cover.cpp +1 -0
  53. esphome/components/daikin_arc/daikin_arc.cpp +19 -12
  54. esphome/components/deep_sleep/__init__.py +9 -2
  55. esphome/components/deep_sleep/deep_sleep_component.h +11 -9
  56. esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
  57. esphome/components/ektf2232/touchscreen/__init__.py +8 -5
  58. esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
  59. esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
  60. esphome/components/epaper_spi/__init__.py +1 -0
  61. esphome/components/epaper_spi/display.py +80 -0
  62. esphome/components/epaper_spi/epaper_spi.cpp +227 -0
  63. esphome/components/epaper_spi/epaper_spi.h +93 -0
  64. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
  65. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
  66. esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
  67. esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
  68. esphome/components/es7210/es7210.cpp +3 -3
  69. esphome/components/esp32/__init__.py +254 -339
  70. esphome/components/esp32/boards.py +81 -0
  71. esphome/components/esp32/preferences.cpp +23 -17
  72. esphome/components/esp32_ble/__init__.py +159 -44
  73. esphome/components/esp32_ble/ble.cpp +47 -3
  74. esphome/components/esp32_ble/ble.h +18 -0
  75. esphome/components/esp32_ble/ble_advertising.cpp +7 -3
  76. esphome/components/esp32_ble/ble_advertising.h +4 -0
  77. esphome/components/esp32_ble/ble_uuid.cpp +16 -42
  78. esphome/components/esp32_ble_beacon/__init__.py +3 -4
  79. esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
  80. esphome/components/esp32_ble_server/__init__.py +28 -14
  81. esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
  82. esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
  83. esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
  84. esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
  85. esphome/components/esp32_ble_server/ble_server.cpp +59 -24
  86. esphome/components/esp32_ble_server/ble_server.h +38 -20
  87. esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
  88. esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
  89. esphome/components/esp32_ble_tracker/__init__.py +25 -80
  90. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
  91. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
  92. esphome/components/esp32_camera/__init__.py +1 -3
  93. esphome/components/esp32_can/esp32_can.cpp +22 -4
  94. esphome/components/esp32_can/esp32_can.h +3 -0
  95. esphome/components/esp32_hosted/__init__.py +2 -1
  96. esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
  97. esphome/components/esp32_improv/esp32_improv_component.h +6 -1
  98. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  99. esphome/components/esp8266/__init__.py +3 -3
  100. esphome/components/esphome/ota/__init__.py +21 -2
  101. esphome/components/esphome/ota/ota_esphome.cpp +455 -145
  102. esphome/components/esphome/ota/ota_esphome.h +49 -2
  103. esphome/components/ethernet/__init__.py +39 -22
  104. esphome/components/ethernet/ethernet_component.cpp +28 -5
  105. esphome/components/ethernet/ethernet_component.h +5 -1
  106. esphome/components/external_components/__init__.py +8 -6
  107. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  108. esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
  109. esphome/components/font/__init__.py +5 -5
  110. esphome/components/graph/graph.cpp +1 -1
  111. esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
  112. esphome/components/haier/hon_climate.cpp +2 -2
  113. esphome/components/haier/hon_climate.h +1 -1
  114. esphome/components/hdc1080/hdc1080.cpp +42 -34
  115. esphome/components/hdc1080/hdc1080.h +1 -3
  116. esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
  117. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  118. esphome/components/http_request/__init__.py +3 -3
  119. esphome/components/htu21d/htu21d.cpp +13 -18
  120. esphome/components/htu21d/htu21d.h +1 -1
  121. esphome/components/i2s_audio/__init__.py +1 -2
  122. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  123. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
  124. esphome/components/improv_serial/improv_serial_component.cpp +12 -15
  125. esphome/components/improv_serial/improv_serial_component.h +6 -8
  126. esphome/components/json/json_util.cpp +35 -43
  127. esphome/components/json/json_util.h +57 -0
  128. esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
  129. esphome/components/key_collector/key_collector.h +4 -4
  130. esphome/components/libretiny/__init__.py +6 -6
  131. esphome/components/libretiny/preferences.cpp +23 -16
  132. esphome/components/light/light_call.cpp +98 -120
  133. esphome/components/light/light_call.h +17 -7
  134. esphome/components/lm75b/__init__.py +0 -0
  135. esphome/components/lm75b/lm75b.cpp +39 -0
  136. esphome/components/lm75b/lm75b.h +19 -0
  137. esphome/components/lm75b/sensor.py +34 -0
  138. esphome/components/lock/lock.h +12 -6
  139. esphome/components/logger/__init__.py +15 -27
  140. esphome/components/logger/logger.cpp +10 -20
  141. esphome/components/logger/logger.h +105 -62
  142. esphome/components/logger/logger_esp32.cpp +0 -48
  143. esphome/components/logger/logger_zephyr.cpp +2 -3
  144. esphome/components/logger/select/logger_level_select.cpp +6 -7
  145. esphome/components/logger/select/logger_level_select.h +7 -0
  146. esphome/components/ltr501/ltr501.cpp +7 -6
  147. esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
  148. esphome/components/matrix_keypad/matrix_keypad.h +4 -4
  149. esphome/components/max7219digit/max7219digit.cpp +1 -1
  150. esphome/components/mcp2515/mcp2515.cpp +31 -3
  151. esphome/components/mcp2515/mcp2515_defs.h +3 -1
  152. esphome/components/md5/md5.cpp +0 -26
  153. esphome/components/md5/md5.h +10 -20
  154. esphome/components/mdns/__init__.py +19 -6
  155. esphome/components/mdns/mdns_component.cpp +27 -59
  156. esphome/components/mdns/mdns_component.h +23 -10
  157. esphome/components/mdns/mdns_esp32.cpp +7 -7
  158. esphome/components/mdns/mdns_esp8266.cpp +6 -6
  159. esphome/components/mdns/mdns_libretiny.cpp +3 -3
  160. esphome/components/mdns/mdns_rp2040.cpp +3 -3
  161. esphome/components/mipi/__init__.py +1 -5
  162. esphome/components/mipi_spi/display.py +24 -8
  163. esphome/components/mipi_spi/mipi_spi.h +3 -3
  164. esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
  165. esphome/components/mmc5603/mmc5603.cpp +3 -3
  166. esphome/components/modbus/modbus.cpp +27 -13
  167. esphome/components/modbus/modbus.h +5 -3
  168. esphome/components/modbus/modbus_definitions.h +86 -0
  169. esphome/components/modbus_controller/__init__.py +29 -1
  170. esphome/components/modbus_controller/const.py +4 -0
  171. esphome/components/modbus_controller/modbus_controller.cpp +38 -13
  172. esphome/components/modbus_controller/modbus_controller.h +18 -29
  173. esphome/components/mpr121/mpr121.cpp +41 -42
  174. esphome/components/mpr121/mpr121.h +0 -1
  175. esphome/components/nau7802/nau7802.cpp +2 -2
  176. esphome/components/network/__init__.py +7 -3
  177. esphome/components/nextion/display.py +4 -4
  178. esphome/components/nextion/nextion.cpp +8 -8
  179. esphome/components/number/__init__.py +2 -0
  180. esphome/components/number/number_call.cpp +23 -12
  181. esphome/components/number/number_call.h +5 -0
  182. esphome/components/online_image/bmp_image.cpp +2 -1
  183. esphome/components/online_image/jpeg_image.cpp +4 -2
  184. esphome/components/openthread/openthread.cpp +6 -7
  185. esphome/components/openthread/openthread.h +0 -1
  186. esphome/components/ota/ota_backend.h +1 -0
  187. esphome/components/packages/__init__.py +10 -8
  188. esphome/components/packet_transport/packet_transport.cpp +2 -0
  189. esphome/components/pid/pid_controller.cpp +1 -1
  190. esphome/components/prometheus/prometheus_handler.cpp +239 -239
  191. esphome/components/psram/__init__.py +30 -28
  192. esphome/components/qmc5883l/qmc5883l.cpp +15 -0
  193. esphome/components/qmc5883l/qmc5883l.h +3 -0
  194. esphome/components/qmc5883l/sensor.py +31 -12
  195. esphome/components/remote_base/gobox_protocol.cpp +3 -3
  196. esphome/components/remote_receiver/__init__.py +14 -2
  197. esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
  198. esphome/components/remote_receiver/remote_receiver.h +4 -0
  199. esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
  200. esphome/components/remote_transmitter/__init__.py +2 -2
  201. esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
  202. esphome/components/rp2040/__init__.py +11 -11
  203. esphome/components/rtttl/rtttl.cpp +2 -2
  204. esphome/components/scd30/sensor.py +1 -1
  205. esphome/components/script/__init__.py +1 -1
  206. esphome/components/script/script.h +7 -7
  207. esphome/components/select/select.cpp +5 -4
  208. esphome/components/select/select_call.cpp +1 -1
  209. esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
  210. esphome/components/sensor/__init__.py +2 -0
  211. esphome/components/sha256/__init__.py +22 -0
  212. esphome/components/sha256/sha256.cpp +116 -0
  213. esphome/components/sha256/sha256.h +60 -0
  214. esphome/components/sim800l/sim800l.cpp +8 -4
  215. esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
  216. esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
  217. esphome/components/spi/__init__.py +0 -3
  218. esphome/components/split_buffer/__init__.py +5 -0
  219. esphome/components/split_buffer/split_buffer.cpp +133 -0
  220. esphome/components/split_buffer/split_buffer.h +40 -0
  221. esphome/components/sps30/sps30.cpp +14 -10
  222. esphome/components/sps30/sps30.h +2 -0
  223. esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
  224. esphome/components/st7789v/st7789v.cpp +3 -2
  225. esphome/components/statsd/statsd.cpp +1 -1
  226. esphome/components/substitutions/__init__.py +3 -1
  227. esphome/components/substitutions/jinja.py +13 -3
  228. esphome/components/sx126x/__init__.py +16 -0
  229. esphome/components/sx126x/sx126x.cpp +15 -1
  230. esphome/components/sx126x/sx126x.h +9 -1
  231. esphome/components/sx126x/sx126x_reg.h +2 -0
  232. esphome/components/text_sensor/text_sensor.cpp +16 -0
  233. esphome/components/text_sensor/text_sensor.h +3 -10
  234. esphome/components/tormatic/tormatic_cover.cpp +1 -1
  235. esphome/components/tuya/select/tuya_select.cpp +1 -1
  236. esphome/components/tuya/tuya.cpp +29 -4
  237. esphome/components/uart/__init__.py +36 -26
  238. esphome/components/uart/uart.h +6 -0
  239. esphome/components/uart/uart_component.cpp +8 -0
  240. esphome/components/uart/uart_component.h +28 -0
  241. esphome/components/uart/uart_component_esp_idf.cpp +64 -10
  242. esphome/components/uart/uart_component_esp_idf.h +5 -2
  243. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
  244. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
  245. esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
  246. esphome/components/usb_host/__init__.py +2 -1
  247. esphome/components/usb_host/usb_host.h +82 -13
  248. esphome/components/usb_host/usb_host_client.cpp +180 -24
  249. esphome/components/usb_host/usb_host_component.cpp +1 -1
  250. esphome/components/usb_uart/__init__.py +0 -1
  251. esphome/components/usb_uart/ch34x.cpp +4 -4
  252. esphome/components/usb_uart/cp210x.cpp +3 -3
  253. esphome/components/usb_uart/usb_uart.cpp +88 -32
  254. esphome/components/usb_uart/usb_uart.h +30 -6
  255. esphome/components/valve/valve.cpp +1 -0
  256. esphome/components/veml7700/veml7700.cpp +7 -6
  257. esphome/components/version/version_text_sensor.cpp +2 -1
  258. esphome/components/voice_assistant/voice_assistant.cpp +3 -3
  259. esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
  260. esphome/components/web_server/list_entities.cpp +3 -4
  261. esphome/components/web_server/list_entities.h +8 -10
  262. esphome/components/web_server/ota/__init__.py +1 -1
  263. esphome/components/web_server/ota/ota_web_server.cpp +9 -3
  264. esphome/components/web_server/web_server.cpp +509 -404
  265. esphome/components/web_server/web_server.h +5 -6
  266. esphome/components/web_server/web_server_v1.cpp +21 -19
  267. esphome/components/web_server_base/__init__.py +5 -2
  268. esphome/components/web_server_base/web_server_base.h +27 -7
  269. esphome/components/web_server_idf/__init__.py +1 -1
  270. esphome/components/web_server_idf/multipart.cpp +2 -2
  271. esphome/components/web_server_idf/multipart.h +2 -2
  272. esphome/components/web_server_idf/utils.cpp +2 -2
  273. esphome/components/web_server_idf/utils.h +2 -2
  274. esphome/components/web_server_idf/web_server_idf.cpp +118 -26
  275. esphome/components/web_server_idf/web_server_idf.h +12 -10
  276. esphome/components/wifi/__init__.py +13 -11
  277. esphome/components/wifi/wifi_component.cpp +73 -56
  278. esphome/components/wifi/wifi_component.h +4 -4
  279. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  280. esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
  281. esphome/components/wireguard/__init__.py +1 -1
  282. esphome/components/wts01/__init__.py +0 -0
  283. esphome/components/wts01/sensor.py +41 -0
  284. esphome/components/wts01/wts01.cpp +91 -0
  285. esphome/components/wts01/wts01.h +27 -0
  286. esphome/components/zephyr/__init__.py +5 -5
  287. esphome/components/zwave_proxy/__init__.py +43 -0
  288. esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
  289. esphome/components/zwave_proxy/zwave_proxy.h +93 -0
  290. esphome/config.py +79 -24
  291. esphome/config_validation.py +13 -15
  292. esphome/const.py +9 -2
  293. esphome/core/__init__.py +31 -22
  294. esphome/core/component.cpp +28 -18
  295. esphome/core/component_iterator.h +2 -1
  296. esphome/core/config.py +15 -15
  297. esphome/core/defines.h +19 -0
  298. esphome/core/hash_base.h +56 -0
  299. esphome/core/helpers.cpp +19 -3
  300. esphome/core/helpers.h +26 -0
  301. esphome/core/scheduler.cpp +5 -21
  302. esphome/core/scheduler.h +19 -8
  303. esphome/core/string_ref.h +1 -1
  304. esphome/core/time.cpp +5 -5
  305. esphome/cpp_generator.py +4 -29
  306. esphome/dashboard/const.py +21 -4
  307. esphome/dashboard/core.py +10 -8
  308. esphome/dashboard/dns.py +15 -0
  309. esphome/dashboard/entries.py +15 -21
  310. esphome/dashboard/models.py +76 -0
  311. esphome/dashboard/settings.py +7 -7
  312. esphome/dashboard/status/mdns.py +46 -2
  313. esphome/dashboard/web_server.py +367 -93
  314. esphome/espota2.py +111 -31
  315. esphome/external_files.py +6 -7
  316. esphome/git.py +8 -0
  317. esphome/helpers.py +124 -77
  318. esphome/loader.py +8 -9
  319. esphome/platformio_api.py +25 -18
  320. esphome/storage_json.py +26 -21
  321. esphome/types.py +30 -2
  322. esphome/util.py +32 -16
  323. esphome/vscode.py +8 -8
  324. esphome/wizard.py +10 -10
  325. esphome/writer.py +50 -15
  326. esphome/yaml_util.py +37 -31
  327. esphome/zeroconf.py +12 -3
  328. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
  329. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +333 -313
  330. esphome/components/event_emitter/__init__.py +0 -5
  331. esphome/components/event_emitter/event_emitter.cpp +0 -14
  332. esphome/components/event_emitter/event_emitter.h +0 -63
  333. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
  334. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
  335. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
  336. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
  337. esphome/components/uart/uart_component_esp32_arduino.h +0 -60
  338. esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
  339. esphome/core/string_ref.cpp +0 -12
  340. esphome/dashboard/util/file.py +0 -63
  341. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
  342. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
  343. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
  344. {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -9,6 +9,7 @@
9
9
  #endif
10
10
 
11
11
  #include <functional>
12
+ #include <span>
12
13
 
13
14
  #include "esphome/core/automation.h"
14
15
  #include "esphome/core/component.h"
@@ -74,17 +75,21 @@ class GAPScanEventHandler {
74
75
  virtual void gap_scan_event_handler(const BLEScanResult &scan_result) = 0;
75
76
  };
76
77
 
78
+ #ifdef USE_ESP32_BLE_CLIENT
77
79
  class GATTcEventHandler {
78
80
  public:
79
81
  virtual void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
80
82
  esp_ble_gattc_cb_param_t *param) = 0;
81
83
  };
84
+ #endif
82
85
 
86
+ #ifdef USE_ESP32_BLE_SERVER
83
87
  class GATTsEventHandler {
84
88
  public:
85
89
  virtual void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
86
90
  esp_ble_gatts_cb_param_t *param) = 0;
87
91
  };
92
+ #endif
88
93
 
89
94
  class BLEStatusEventHandler {
90
95
  public:
@@ -114,6 +119,7 @@ class ESP32BLE : public Component {
114
119
  void advertising_set_service_data(const std::vector<uint8_t> &data);
115
120
  void advertising_set_manufacturer_data(const std::vector<uint8_t> &data);
116
121
  void advertising_set_appearance(uint16_t appearance) { this->appearance_ = appearance; }
122
+ void advertising_set_service_data_and_name(std::span<const uint8_t> data, bool include_name);
117
123
  void advertising_add_service_uuid(ESPBTUUID uuid);
118
124
  void advertising_remove_service_uuid(ESPBTUUID uuid);
119
125
  void advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback);
@@ -123,16 +129,24 @@ class ESP32BLE : public Component {
123
129
  void register_gap_scan_event_handler(GAPScanEventHandler *handler) {
124
130
  this->gap_scan_event_handlers_.push_back(handler);
125
131
  }
132
+ #ifdef USE_ESP32_BLE_CLIENT
126
133
  void register_gattc_event_handler(GATTcEventHandler *handler) { this->gattc_event_handlers_.push_back(handler); }
134
+ #endif
135
+ #ifdef USE_ESP32_BLE_SERVER
127
136
  void register_gatts_event_handler(GATTsEventHandler *handler) { this->gatts_event_handlers_.push_back(handler); }
137
+ #endif
128
138
  void register_ble_status_event_handler(BLEStatusEventHandler *handler) {
129
139
  this->ble_status_event_handlers_.push_back(handler);
130
140
  }
131
141
  void set_enable_on_boot(bool enable_on_boot) { this->enable_on_boot_ = enable_on_boot; }
132
142
 
133
143
  protected:
144
+ #ifdef USE_ESP32_BLE_SERVER
134
145
  static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
146
+ #endif
147
+ #ifdef USE_ESP32_BLE_CLIENT
135
148
  static void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
149
+ #endif
136
150
  static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
137
151
 
138
152
  bool ble_setup_();
@@ -148,8 +162,12 @@ class ESP32BLE : public Component {
148
162
  // Vectors (12 bytes each on 32-bit, naturally aligned to 4 bytes)
149
163
  std::vector<GAPEventHandler *> gap_event_handlers_;
150
164
  std::vector<GAPScanEventHandler *> gap_scan_event_handlers_;
165
+ #ifdef USE_ESP32_BLE_CLIENT
151
166
  std::vector<GATTcEventHandler *> gattc_event_handlers_;
167
+ #endif
168
+ #ifdef USE_ESP32_BLE_SERVER
152
169
  std::vector<GATTsEventHandler *> gatts_event_handlers_;
170
+ #endif
153
171
  std::vector<BLEStatusEventHandler *> ble_status_event_handlers_;
154
172
 
155
173
  // Large objects (size depends on template parameters, but typically aligned to 4 bytes)
@@ -43,7 +43,7 @@ void BLEAdvertising::remove_service_uuid(ESPBTUUID uuid) {
43
43
  this->advertising_uuids_.end());
44
44
  }
45
45
 
46
- void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
46
+ void BLEAdvertising::set_service_data(std::span<const uint8_t> data) {
47
47
  delete[] this->advertising_data_.p_service_data;
48
48
  this->advertising_data_.p_service_data = nullptr;
49
49
  this->advertising_data_.service_data_len = data.size();
@@ -54,6 +54,10 @@ void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
54
54
  }
55
55
  }
56
56
 
57
+ void BLEAdvertising::set_service_data(const std::vector<uint8_t> &data) {
58
+ this->set_service_data(std::span<const uint8_t>(data));
59
+ }
60
+
57
61
  void BLEAdvertising::set_manufacturer_data(const std::vector<uint8_t> &data) {
58
62
  delete[] this->advertising_data_.p_manufacturer_data;
59
63
  this->advertising_data_.p_manufacturer_data = nullptr;
@@ -84,7 +88,7 @@ esp_err_t BLEAdvertising::services_advertisement_() {
84
88
  esp_err_t err;
85
89
 
86
90
  this->advertising_data_.set_scan_rsp = false;
87
- this->advertising_data_.include_name = !this->scan_response_;
91
+ this->advertising_data_.include_name = this->include_name_in_adv_ || !this->scan_response_;
88
92
  this->advertising_data_.include_txpower = !this->scan_response_;
89
93
  err = esp_ble_gap_config_adv_data(&this->advertising_data_);
90
94
  if (err != ESP_OK) {
@@ -148,7 +152,7 @@ void BLEAdvertising::loop() {
148
152
  if (now - this->last_advertisement_time_ > this->advertising_cycle_time_) {
149
153
  this->stop();
150
154
  this->current_adv_index_ += 1;
151
- if (this->current_adv_index_ >= this->raw_advertisements_callbacks_.size()) {
155
+ if (static_cast<size_t>(this->current_adv_index_) >= this->raw_advertisements_callbacks_.size()) {
152
156
  this->current_adv_index_ = -1;
153
157
  }
154
158
  this->start();
@@ -4,6 +4,7 @@
4
4
 
5
5
  #include <array>
6
6
  #include <functional>
7
+ #include <span>
7
8
  #include <vector>
8
9
 
9
10
  #ifdef USE_ESP32
@@ -36,6 +37,8 @@ class BLEAdvertising {
36
37
  void set_manufacturer_data(const std::vector<uint8_t> &data);
37
38
  void set_appearance(uint16_t appearance) { this->advertising_data_.appearance = appearance; }
38
39
  void set_service_data(const std::vector<uint8_t> &data);
40
+ void set_service_data(std::span<const uint8_t> data);
41
+ void set_include_name(bool include_name) { this->include_name_in_adv_ = include_name; }
39
42
  void register_raw_advertisement_callback(std::function<void(bool)> &&callback);
40
43
 
41
44
  void start();
@@ -45,6 +48,7 @@ class BLEAdvertising {
45
48
  esp_err_t services_advertisement_();
46
49
 
47
50
  bool scan_response_;
51
+ bool include_name_in_adv_{false};
48
52
  esp_ble_adv_data_t advertising_data_;
49
53
  esp_ble_adv_data_t scan_response_data_;
50
54
  esp_ble_adv_params_t advertising_params_;
@@ -42,32 +42,18 @@ ESPBTUUID ESPBTUUID::from_raw_reversed(const uint8_t *data) {
42
42
  ESPBTUUID ESPBTUUID::from_raw(const std::string &data) {
43
43
  ESPBTUUID ret;
44
44
  if (data.length() == 4) {
45
- ret.uuid_.len = ESP_UUID_LEN_16;
46
- ret.uuid_.uuid.uuid16 = 0;
47
- for (uint i = 0; i < data.length(); i += 2) {
48
- uint8_t msb = data.c_str()[i];
49
- uint8_t lsb = data.c_str()[i + 1];
50
- uint8_t lsb_shift = i <= 2 ? (2 - i) * 4 : 0;
51
-
52
- if (msb > '9')
53
- msb -= 7;
54
- if (lsb > '9')
55
- lsb -= 7;
56
- ret.uuid_.uuid.uuid16 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift;
45
+ // 16-bit UUID as 4-character hex string
46
+ auto parsed = parse_hex<uint16_t>(data);
47
+ if (parsed.has_value()) {
48
+ ret.uuid_.len = ESP_UUID_LEN_16;
49
+ ret.uuid_.uuid.uuid16 = parsed.value();
57
50
  }
58
51
  } else if (data.length() == 8) {
59
- ret.uuid_.len = ESP_UUID_LEN_32;
60
- ret.uuid_.uuid.uuid32 = 0;
61
- for (uint i = 0; i < data.length(); i += 2) {
62
- uint8_t msb = data.c_str()[i];
63
- uint8_t lsb = data.c_str()[i + 1];
64
- uint8_t lsb_shift = i <= 6 ? (6 - i) * 4 : 0;
65
-
66
- if (msb > '9')
67
- msb -= 7;
68
- if (lsb > '9')
69
- lsb -= 7;
70
- ret.uuid_.uuid.uuid32 += (((msb & 0x0F) << 4) | (lsb & 0x0F)) << lsb_shift;
52
+ // 32-bit UUID as 8-character hex string
53
+ auto parsed = parse_hex<uint32_t>(data);
54
+ if (parsed.has_value()) {
55
+ ret.uuid_.len = ESP_UUID_LEN_32;
56
+ ret.uuid_.uuid.uuid32 = parsed.value();
71
57
  }
72
58
  } else if (data.length() == 16) { // how we can have 16 byte length string reprezenting 128 bit uuid??? needs to be
73
59
  // investigated (lack of time)
@@ -145,28 +131,16 @@ bool ESPBTUUID::operator==(const ESPBTUUID &uuid) const {
145
131
  if (this->uuid_.len == uuid.uuid_.len) {
146
132
  switch (this->uuid_.len) {
147
133
  case ESP_UUID_LEN_16:
148
- if (uuid.uuid_.uuid.uuid16 == this->uuid_.uuid.uuid16) {
149
- return true;
150
- }
151
- break;
134
+ return this->uuid_.uuid.uuid16 == uuid.uuid_.uuid.uuid16;
152
135
  case ESP_UUID_LEN_32:
153
- if (uuid.uuid_.uuid.uuid32 == this->uuid_.uuid.uuid32) {
154
- return true;
155
- }
156
- break;
136
+ return this->uuid_.uuid.uuid32 == uuid.uuid_.uuid.uuid32;
157
137
  case ESP_UUID_LEN_128:
158
- for (uint8_t i = 0; i < ESP_UUID_LEN_128; i++) {
159
- if (uuid.uuid_.uuid.uuid128[i] != this->uuid_.uuid.uuid128[i]) {
160
- return false;
161
- }
162
- }
163
- return true;
164
- break;
138
+ return memcmp(this->uuid_.uuid.uuid128, uuid.uuid_.uuid.uuid128, ESP_UUID_LEN_128) == 0;
139
+ default:
140
+ return false;
165
141
  }
166
- } else {
167
- return this->as_128bit() == uuid.as_128bit();
168
142
  }
169
- return false;
143
+ return this->as_128bit() == uuid.as_128bit();
170
144
  }
171
145
  esp_bt_uuid_t ESPBTUUID::get_uuid() const { return this->uuid_; }
172
146
  std::string ESPBTUUID::to_string() const {
@@ -4,7 +4,7 @@ from esphome.components.esp32 import add_idf_sdkconfig_option
4
4
  from esphome.components.esp32_ble import CONF_BLE_ID
5
5
  import esphome.config_validation as cv
6
6
  from esphome.const import CONF_ID, CONF_TX_POWER, CONF_TYPE, CONF_UUID
7
- from esphome.core import CORE, TimePeriod
7
+ from esphome.core import TimePeriod
8
8
 
9
9
  AUTO_LOAD = ["esp32_ble"]
10
10
  DEPENDENCIES = ["esp32"]
@@ -86,6 +86,5 @@ async def to_code(config):
86
86
 
87
87
  cg.add_define("USE_ESP32_BLE_ADVERTISING")
88
88
 
89
- if CORE.using_esp_idf:
90
- add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
91
- add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
89
+ add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
90
+ add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
@@ -43,13 +43,6 @@ void BLEClientBase::setup() {
43
43
  void BLEClientBase::set_state(espbt::ClientState st) {
44
44
  ESP_LOGV(TAG, "[%d] [%s] Set state %d", this->connection_index_, this->address_str_.c_str(), (int) st);
45
45
  ESPBTClient::set_state(st);
46
-
47
- if (st == espbt::ClientState::READY_TO_CONNECT) {
48
- // Enable loop for state processing
49
- this->enable_loop();
50
- // Connect immediately instead of waiting for next loop
51
- this->connect();
52
- }
53
46
  }
54
47
 
55
48
  void BLEClientBase::loop() {
@@ -65,8 +58,8 @@ void BLEClientBase::loop() {
65
58
  }
66
59
  this->set_state(espbt::ClientState::IDLE);
67
60
  }
68
- // If its idle, we can disable the loop as set_state
69
- // will enable it again when we need to connect.
61
+ // If idle, we can disable the loop as connect()
62
+ // will enable it again when a connection is needed.
70
63
  else if (this->state_ == espbt::ClientState::IDLE) {
71
64
  this->disable_loop();
72
65
  }
@@ -108,9 +101,20 @@ bool BLEClientBase::parse_device(const espbt::ESPBTDevice &device) {
108
101
  #endif
109
102
 
110
103
  void BLEClientBase::connect() {
104
+ // Prevent duplicate connection attempts
105
+ if (this->state_ == espbt::ClientState::CONNECTING || this->state_ == espbt::ClientState::CONNECTED ||
106
+ this->state_ == espbt::ClientState::ESTABLISHED) {
107
+ ESP_LOGW(TAG, "[%d] [%s] Connection already in progress, state=%s", this->connection_index_,
108
+ this->address_str_.c_str(), espbt::client_state_to_string(this->state_));
109
+ return;
110
+ }
111
111
  ESP_LOGI(TAG, "[%d] [%s] 0x%02x Connecting", this->connection_index_, this->address_str_.c_str(),
112
112
  this->remote_addr_type_);
113
113
  this->paired_ = false;
114
+ // Enable loop for state processing
115
+ this->enable_loop();
116
+ // Immediately transition to CONNECTING to prevent duplicate connection attempts
117
+ this->set_state(espbt::ClientState::CONNECTING);
114
118
 
115
119
  // Determine connection parameters based on connection type
116
120
  if (this->connection_type_ == espbt::ConnectionType::V3_WITHOUT_CACHE) {
@@ -168,7 +172,7 @@ void BLEClientBase::unconditional_disconnect() {
168
172
  this->log_gattc_warning_("esp_ble_gattc_close", err);
169
173
  }
170
174
 
171
- if (this->state_ == espbt::ClientState::READY_TO_CONNECT || this->state_ == espbt::ClientState::DISCOVERED) {
175
+ if (this->state_ == espbt::ClientState::DISCOVERED) {
172
176
  this->set_address(0);
173
177
  this->set_state(espbt::ClientState::IDLE);
174
178
  } else {
@@ -212,8 +216,6 @@ void BLEClientBase::handle_connection_result_(esp_err_t ret) {
212
216
  if (ret) {
213
217
  this->log_gattc_warning_("esp_ble_gattc_open", ret);
214
218
  this->set_state(espbt::ClientState::IDLE);
215
- } else {
216
- this->set_state(espbt::ClientState::CONNECTING);
217
219
  }
218
220
  }
219
221
 
@@ -26,7 +26,7 @@ from esphome.const import (
26
26
  from esphome.core import CORE
27
27
  from esphome.schema_extractors import SCHEMA_EXTRACT
28
28
 
29
- AUTO_LOAD = ["esp32_ble", "bytebuffer", "event_emitter"]
29
+ AUTO_LOAD = ["esp32_ble", "bytebuffer"]
30
30
  CODEOWNERS = ["@jesserockz", "@clydebarrow", "@Rapsssito"]
31
31
  DEPENDENCIES = ["esp32"]
32
32
  DOMAIN = "esp32_ble_server"
@@ -488,6 +488,7 @@ async def to_code_descriptor(descriptor_conf, char_var):
488
488
  cg.add(desc_var.set_value(value))
489
489
  if CONF_ON_WRITE in descriptor_conf:
490
490
  on_write_conf = descriptor_conf[CONF_ON_WRITE]
491
+ cg.add_define("USE_ESP32_BLE_SERVER_DESCRIPTOR_ON_WRITE")
491
492
  await automation.build_automation(
492
493
  BLETriggers_ns.create_descriptor_on_write_trigger(desc_var),
493
494
  [(cg.std_vector.template(cg.uint8), "x"), (cg.uint16, "id")],
@@ -505,23 +506,32 @@ async def to_code_characteristic(service_var, char_conf):
505
506
  )
506
507
  if CONF_ON_WRITE in char_conf:
507
508
  on_write_conf = char_conf[CONF_ON_WRITE]
509
+ cg.add_define("USE_ESP32_BLE_SERVER_CHARACTERISTIC_ON_WRITE")
508
510
  await automation.build_automation(
509
511
  BLETriggers_ns.create_characteristic_on_write_trigger(char_var),
510
512
  [(cg.std_vector.template(cg.uint8), "x"), (cg.uint16, "id")],
511
513
  on_write_conf,
512
514
  )
513
515
  if CONF_VALUE in char_conf:
514
- action_conf = {
515
- CONF_ID: char_conf[CONF_ID],
516
- CONF_VALUE: char_conf[CONF_VALUE],
517
- }
518
- value_action = await ble_server_characteristic_set_value(
519
- action_conf,
520
- char_conf[CONF_CHAR_VALUE_ACTION_ID_],
521
- cg.TemplateArguments(),
522
- {},
523
- )
524
- cg.add(value_action.play())
516
+ # Check if the value is templated (Lambda)
517
+ value_data = char_conf[CONF_VALUE][CONF_DATA]
518
+ if isinstance(value_data, cv.Lambda):
519
+ # Templated value - need the full action infrastructure
520
+ action_conf = {
521
+ CONF_ID: char_conf[CONF_ID],
522
+ CONF_VALUE: char_conf[CONF_VALUE],
523
+ }
524
+ value_action = await ble_server_characteristic_set_value(
525
+ action_conf,
526
+ char_conf[CONF_CHAR_VALUE_ACTION_ID_],
527
+ cg.TemplateArguments(),
528
+ {},
529
+ )
530
+ cg.add(value_action.play())
531
+ else:
532
+ # Static value - just set it directly without action infrastructure
533
+ value = await parse_value(char_conf[CONF_VALUE], {})
534
+ cg.add(char_var.set_value(value))
525
535
  for descriptor_conf in char_conf[CONF_DESCRIPTORS]:
526
536
  await to_code_descriptor(descriptor_conf, char_var)
527
537
 
@@ -560,12 +570,14 @@ async def to_code(config):
560
570
  else:
561
571
  cg.add(var.enqueue_start_service(service_var))
562
572
  if CONF_ON_CONNECT in config:
573
+ cg.add_define("USE_ESP32_BLE_SERVER_ON_CONNECT")
563
574
  await automation.build_automation(
564
575
  BLETriggers_ns.create_server_on_connect_trigger(var),
565
576
  [(cg.uint16, "id")],
566
577
  config[CONF_ON_CONNECT],
567
578
  )
568
579
  if CONF_ON_DISCONNECT in config:
580
+ cg.add_define("USE_ESP32_BLE_SERVER_ON_DISCONNECT")
569
581
  await automation.build_automation(
570
582
  BLETriggers_ns.create_server_on_disconnect_trigger(var),
571
583
  [(cg.uint16, "id")],
@@ -573,8 +585,7 @@ async def to_code(config):
573
585
  )
574
586
  cg.add_define("USE_ESP32_BLE_SERVER")
575
587
  cg.add_define("USE_ESP32_BLE_ADVERTISING")
576
- if CORE.using_esp_idf:
577
- add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
588
+ add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
578
589
 
579
590
 
580
591
  @automation.register_action(
@@ -595,6 +606,7 @@ async def ble_server_characteristic_set_value(config, action_id, template_arg, a
595
606
  var = cg.new_Pvariable(action_id, template_arg, paren)
596
607
  value = await parse_value(config[CONF_VALUE], args)
597
608
  cg.add(var.set_buffer(value))
609
+ cg.add_define("USE_ESP32_BLE_SERVER_SET_VALUE_ACTION")
598
610
  return var
599
611
 
600
612
 
@@ -613,6 +625,7 @@ async def ble_server_descriptor_set_value(config, action_id, template_arg, args)
613
625
  var = cg.new_Pvariable(action_id, template_arg, paren)
614
626
  value = await parse_value(config[CONF_VALUE], args)
615
627
  cg.add(var.set_buffer(value))
628
+ cg.add_define("USE_ESP32_BLE_SERVER_DESCRIPTOR_SET_VALUE_ACTION")
616
629
  return var
617
630
 
618
631
 
@@ -630,4 +643,5 @@ async def ble_server_descriptor_set_value(config, action_id, template_arg, args)
630
643
  )
631
644
  async def ble_server_characteristic_notify(config, action_id, template_arg, args):
632
645
  paren = await cg.get_variable(config[CONF_ID])
646
+ cg.add_define("USE_ESP32_BLE_SERVER_NOTIFY_ACTION")
633
647
  return cg.new_Pvariable(action_id, template_arg, paren)
@@ -49,13 +49,17 @@ void BLECharacteristic::notify() {
49
49
  this->service_->get_server()->get_connected_client_count() == 0)
50
50
  return;
51
51
 
52
- for (auto &client : this->service_->get_server()->get_clients()) {
52
+ const uint16_t *clients = this->service_->get_server()->get_clients();
53
+ uint8_t client_count = this->service_->get_server()->get_client_count();
54
+
55
+ for (uint8_t i = 0; i < client_count; i++) {
56
+ uint16_t client = clients[i];
53
57
  size_t length = this->value_.size();
54
- // If the client is not in the list of clients to notify, skip it
55
- if (this->clients_to_notify_.count(client) == 0)
58
+ // Find the client in the list of clients to notify
59
+ auto *entry = this->find_client_in_notify_list_(client);
60
+ if (entry == nullptr)
56
61
  continue;
57
- // If the client is in the list of clients to notify, check if it requires an ack (i.e. INDICATE)
58
- bool require_ack = this->clients_to_notify_[client];
62
+ bool require_ack = entry->indicate;
59
63
  // TODO: Remove this block when INDICATE acknowledgment is supported
60
64
  if (require_ack) {
61
65
  ESP_LOGW(TAG, "INDICATE acknowledgment is not yet supported (i.e. it works as a NOTIFY)");
@@ -73,16 +77,17 @@ void BLECharacteristic::notify() {
73
77
  void BLECharacteristic::add_descriptor(BLEDescriptor *descriptor) {
74
78
  // If the descriptor is the CCCD descriptor, listen to its write event to know if the client wants to be notified
75
79
  if (descriptor->get_uuid() == ESPBTUUID::from_uint16(ESP_GATT_UUID_CHAR_CLIENT_CONFIG)) {
76
- descriptor->on(BLEDescriptorEvt::VectorEvt::ON_WRITE, [this](const std::vector<uint8_t> &value, uint16_t conn_id) {
80
+ descriptor->on_write([this](std::span<const uint8_t> value, uint16_t conn_id) {
77
81
  if (value.size() != 2)
78
82
  return;
79
83
  uint16_t cccd = encode_uint16(value[1], value[0]);
80
84
  bool notify = (cccd & 1) != 0;
81
85
  bool indicate = (cccd & 2) != 0;
86
+ // Remove existing entry if present
87
+ this->remove_client_from_notify_list_(conn_id);
88
+ // Add new entry if needed
82
89
  if (notify || indicate) {
83
- this->clients_to_notify_[conn_id] = indicate;
84
- } else {
85
- this->clients_to_notify_.erase(conn_id);
90
+ this->clients_to_notify_.push_back({conn_id, indicate});
86
91
  }
87
92
  });
88
93
  }
@@ -120,69 +125,49 @@ bool BLECharacteristic::is_created() {
120
125
  if (this->state_ != CREATING_DEPENDENTS)
121
126
  return false;
122
127
 
123
- bool created = true;
124
128
  for (auto *descriptor : this->descriptors_) {
125
- created &= descriptor->is_created();
129
+ if (!descriptor->is_created())
130
+ return false;
126
131
  }
127
- if (created)
128
- this->state_ = CREATED;
129
- return this->state_ == CREATED;
132
+ // All descriptors are created if we reach here
133
+ this->state_ = CREATED;
134
+ return true;
130
135
  }
131
136
 
132
137
  bool BLECharacteristic::is_failed() {
133
138
  if (this->state_ == FAILED)
134
139
  return true;
135
140
 
136
- bool failed = false;
137
141
  for (auto *descriptor : this->descriptors_) {
138
- failed |= descriptor->is_failed();
142
+ if (descriptor->is_failed()) {
143
+ this->state_ = FAILED;
144
+ return true;
145
+ }
139
146
  }
140
- if (failed)
141
- this->state_ = FAILED;
142
- return this->state_ == FAILED;
147
+ return false;
143
148
  }
144
149
 
145
- void BLECharacteristic::set_broadcast_property(bool value) {
150
+ void BLECharacteristic::set_property_bit_(esp_gatt_char_prop_t bit, bool value) {
146
151
  if (value) {
147
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_BROADCAST);
152
+ this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | bit);
148
153
  } else {
149
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_BROADCAST);
154
+ this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~bit);
150
155
  }
151
156
  }
157
+
158
+ void BLECharacteristic::set_broadcast_property(bool value) {
159
+ this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_BROADCAST, value);
160
+ }
152
161
  void BLECharacteristic::set_indicate_property(bool value) {
153
- if (value) {
154
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_INDICATE);
155
- } else {
156
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_INDICATE);
157
- }
162
+ this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_INDICATE, value);
158
163
  }
159
164
  void BLECharacteristic::set_notify_property(bool value) {
160
- if (value) {
161
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_NOTIFY);
162
- } else {
163
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_NOTIFY);
164
- }
165
- }
166
- void BLECharacteristic::set_read_property(bool value) {
167
- if (value) {
168
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_READ);
169
- } else {
170
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_READ);
171
- }
172
- }
173
- void BLECharacteristic::set_write_property(bool value) {
174
- if (value) {
175
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE);
176
- } else {
177
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE);
178
- }
165
+ this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_NOTIFY, value);
179
166
  }
167
+ void BLECharacteristic::set_read_property(bool value) { this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_READ, value); }
168
+ void BLECharacteristic::set_write_property(bool value) { this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_WRITE, value); }
180
169
  void BLECharacteristic::set_write_no_response_property(bool value) {
181
- if (value) {
182
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ | ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
183
- } else {
184
- this->properties_ = (esp_gatt_char_prop_t) (this->properties_ & ~ESP_GATT_CHAR_PROP_BIT_WRITE_NR);
185
- }
170
+ this->set_property_bit_(ESP_GATT_CHAR_PROP_BIT_WRITE_NR, value);
186
171
  }
187
172
 
188
173
  void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
@@ -207,8 +192,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
207
192
  if (!param->read.need_rsp)
208
193
  break; // For some reason you can request a read but not want a response
209
194
 
210
- this->EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t>::emit_(BLECharacteristicEvt::EmptyEvt::ON_READ,
211
- param->read.conn_id);
195
+ if (this->on_read_callback_) {
196
+ (*this->on_read_callback_)(param->read.conn_id);
197
+ }
212
198
 
213
199
  uint16_t max_offset = 22;
214
200
 
@@ -276,8 +262,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
276
262
  }
277
263
 
278
264
  if (!param->write.is_prep) {
279
- this->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_(
280
- BLECharacteristicEvt::VectorEvt::ON_WRITE, this->value_, param->write.conn_id);
265
+ if (this->on_write_callback_) {
266
+ (*this->on_write_callback_)(this->value_, param->write.conn_id);
267
+ }
281
268
  }
282
269
 
283
270
  break;
@@ -288,8 +275,9 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
288
275
  break;
289
276
  this->write_event_ = false;
290
277
  if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC) {
291
- this->EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>::emit_(
292
- BLECharacteristicEvt::VectorEvt::ON_WRITE, this->value_, param->exec_write.conn_id);
278
+ if (this->on_write_callback_) {
279
+ (*this->on_write_callback_)(this->value_, param->exec_write.conn_id);
280
+ }
293
281
  }
294
282
  esp_err_t err =
295
283
  esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, nullptr);
@@ -307,6 +295,28 @@ void BLECharacteristic::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt
307
295
  }
308
296
  }
309
297
 
298
+ void BLECharacteristic::remove_client_from_notify_list_(uint16_t conn_id) {
299
+ // Since we typically have very few clients (often just 1), we can optimize
300
+ // for the common case by swapping with the last element and popping
301
+ for (size_t i = 0; i < this->clients_to_notify_.size(); i++) {
302
+ if (this->clients_to_notify_[i].conn_id == conn_id) {
303
+ // Swap with last element and pop (safe even when i is the last element)
304
+ this->clients_to_notify_[i] = this->clients_to_notify_.back();
305
+ this->clients_to_notify_.pop_back();
306
+ return;
307
+ }
308
+ }
309
+ }
310
+
311
+ BLECharacteristic::ClientNotificationEntry *BLECharacteristic::find_client_in_notify_list_(uint16_t conn_id) {
312
+ for (auto &entry : this->clients_to_notify_) {
313
+ if (entry.conn_id == conn_id) {
314
+ return &entry;
315
+ }
316
+ }
317
+ return nullptr;
318
+ }
319
+
310
320
  } // namespace esp32_ble_server
311
321
  } // namespace esphome
312
322