esphome 2025.9.3__py3-none-any.whl → 2025.10.0b2__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 (351) hide show
  1. esphome/__main__.py +94 -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 +166 -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 +68 -10
  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 +7 -7
  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/dashboard_import/dashboard_import.cpp +1 -1
  55. esphome/components/dashboard_import/dashboard_import.h +1 -1
  56. esphome/components/deep_sleep/__init__.py +9 -2
  57. esphome/components/deep_sleep/deep_sleep_component.h +11 -9
  58. esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
  59. esphome/components/ektf2232/touchscreen/__init__.py +8 -5
  60. esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
  61. esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
  62. esphome/components/epaper_spi/__init__.py +1 -0
  63. esphome/components/epaper_spi/display.py +80 -0
  64. esphome/components/epaper_spi/epaper_spi.cpp +227 -0
  65. esphome/components/epaper_spi/epaper_spi.h +93 -0
  66. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
  67. esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
  68. esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
  69. esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
  70. esphome/components/es7210/es7210.cpp +3 -3
  71. esphome/components/esp32/__init__.py +256 -340
  72. esphome/components/esp32/boards.py +81 -0
  73. esphome/components/esp32/preferences.cpp +23 -17
  74. esphome/components/esp32_ble/__init__.py +167 -44
  75. esphome/components/esp32_ble/ble.cpp +47 -3
  76. esphome/components/esp32_ble/ble.h +18 -0
  77. esphome/components/esp32_ble/ble_advertising.cpp +7 -3
  78. esphome/components/esp32_ble/ble_advertising.h +4 -0
  79. esphome/components/esp32_ble/ble_uuid.cpp +16 -42
  80. esphome/components/esp32_ble_beacon/__init__.py +3 -4
  81. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +0 -4
  82. esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
  83. esphome/components/esp32_ble_server/__init__.py +28 -14
  84. esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
  85. esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
  86. esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
  87. esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
  88. esphome/components/esp32_ble_server/ble_server.cpp +59 -24
  89. esphome/components/esp32_ble_server/ble_server.h +38 -20
  90. esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
  91. esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
  92. esphome/components/esp32_ble_tracker/__init__.py +25 -80
  93. esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -8
  94. esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
  95. esphome/components/esp32_camera/__init__.py +1 -3
  96. esphome/components/esp32_can/esp32_can.cpp +22 -4
  97. esphome/components/esp32_can/esp32_can.h +3 -0
  98. esphome/components/esp32_hosted/__init__.py +2 -1
  99. esphome/components/esp32_improv/esp32_improv_component.cpp +135 -65
  100. esphome/components/esp32_improv/esp32_improv_component.h +7 -1
  101. esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
  102. esphome/components/esp8266/__init__.py +3 -3
  103. esphome/components/esphome/ota/__init__.py +21 -2
  104. esphome/components/esphome/ota/ota_esphome.cpp +456 -146
  105. esphome/components/esphome/ota/ota_esphome.h +49 -2
  106. esphome/components/ethernet/__init__.py +39 -22
  107. esphome/components/ethernet/ethernet_component.cpp +28 -5
  108. esphome/components/ethernet/ethernet_component.h +5 -1
  109. esphome/components/external_components/__init__.py +8 -6
  110. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  111. esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
  112. esphome/components/font/__init__.py +5 -5
  113. esphome/components/graph/graph.cpp +1 -1
  114. esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
  115. esphome/components/haier/hon_climate.cpp +2 -2
  116. esphome/components/haier/hon_climate.h +1 -1
  117. esphome/components/hdc1080/hdc1080.cpp +42 -34
  118. esphome/components/hdc1080/hdc1080.h +1 -3
  119. esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
  120. esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
  121. esphome/components/http_request/__init__.py +3 -3
  122. esphome/components/htu21d/htu21d.cpp +13 -18
  123. esphome/components/htu21d/htu21d.h +1 -1
  124. esphome/components/i2s_audio/__init__.py +1 -2
  125. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
  126. esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
  127. esphome/components/improv_serial/improv_serial_component.cpp +12 -15
  128. esphome/components/improv_serial/improv_serial_component.h +6 -8
  129. esphome/components/json/json_util.cpp +42 -44
  130. esphome/components/json/json_util.h +57 -0
  131. esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
  132. esphome/components/key_collector/key_collector.h +4 -4
  133. esphome/components/libretiny/__init__.py +6 -6
  134. esphome/components/libretiny/preferences.cpp +23 -16
  135. esphome/components/light/light_call.cpp +98 -120
  136. esphome/components/light/light_call.h +17 -7
  137. esphome/components/lm75b/__init__.py +0 -0
  138. esphome/components/lm75b/lm75b.cpp +39 -0
  139. esphome/components/lm75b/lm75b.h +19 -0
  140. esphome/components/lm75b/sensor.py +34 -0
  141. esphome/components/lock/lock.h +12 -6
  142. esphome/components/logger/__init__.py +15 -27
  143. esphome/components/logger/logger.cpp +10 -20
  144. esphome/components/logger/logger.h +105 -62
  145. esphome/components/logger/logger_esp32.cpp +0 -48
  146. esphome/components/logger/logger_zephyr.cpp +2 -3
  147. esphome/components/logger/select/logger_level_select.cpp +6 -7
  148. esphome/components/logger/select/logger_level_select.h +7 -0
  149. esphome/components/ltr501/ltr501.cpp +7 -6
  150. esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
  151. esphome/components/matrix_keypad/matrix_keypad.h +4 -4
  152. esphome/components/max7219digit/max7219digit.cpp +1 -1
  153. esphome/components/mcp23xxx_base/mcp23xxx_base.h +3 -3
  154. esphome/components/mcp2515/mcp2515.cpp +31 -3
  155. esphome/components/mcp2515/mcp2515_defs.h +3 -1
  156. esphome/components/md5/md5.cpp +0 -26
  157. esphome/components/md5/md5.h +10 -20
  158. esphome/components/mdns/__init__.py +93 -19
  159. esphome/components/mdns/mdns_component.cpp +57 -94
  160. esphome/components/mdns/mdns_component.h +35 -11
  161. esphome/components/mdns/mdns_esp32.cpp +7 -13
  162. esphome/components/mdns/mdns_esp8266.cpp +7 -7
  163. esphome/components/mdns/mdns_libretiny.cpp +3 -4
  164. esphome/components/mdns/mdns_rp2040.cpp +3 -4
  165. esphome/components/mipi/__init__.py +1 -5
  166. esphome/components/mipi_spi/display.py +24 -8
  167. esphome/components/mipi_spi/mipi_spi.h +3 -3
  168. esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
  169. esphome/components/mmc5603/mmc5603.cpp +3 -3
  170. esphome/components/modbus/modbus.cpp +27 -13
  171. esphome/components/modbus/modbus.h +5 -3
  172. esphome/components/modbus/modbus_definitions.h +86 -0
  173. esphome/components/modbus_controller/__init__.py +29 -1
  174. esphome/components/modbus_controller/const.py +4 -0
  175. esphome/components/modbus_controller/modbus_controller.cpp +38 -13
  176. esphome/components/modbus_controller/modbus_controller.h +18 -29
  177. esphome/components/mpr121/mpr121.cpp +41 -42
  178. esphome/components/mpr121/mpr121.h +0 -1
  179. esphome/components/nau7802/nau7802.cpp +2 -2
  180. esphome/components/network/__init__.py +7 -3
  181. esphome/components/nextion/display.py +4 -4
  182. esphome/components/nextion/nextion.cpp +8 -8
  183. esphome/components/number/__init__.py +2 -0
  184. esphome/components/number/number_call.cpp +23 -12
  185. esphome/components/number/number_call.h +5 -0
  186. esphome/components/online_image/bmp_image.cpp +2 -1
  187. esphome/components/online_image/jpeg_image.cpp +4 -2
  188. esphome/components/opentherm/opentherm.cpp +5 -5
  189. esphome/components/opentherm/opentherm.h +3 -3
  190. esphome/components/openthread/openthread.cpp +11 -10
  191. esphome/components/openthread/openthread.h +0 -1
  192. esphome/components/ota/ota_backend.h +1 -0
  193. esphome/components/packages/__init__.py +10 -8
  194. esphome/components/packet_transport/packet_transport.cpp +2 -0
  195. esphome/components/pid/pid_controller.cpp +1 -1
  196. esphome/components/prometheus/prometheus_handler.cpp +239 -239
  197. esphome/components/psram/__init__.py +30 -28
  198. esphome/components/qmc5883l/qmc5883l.cpp +15 -0
  199. esphome/components/qmc5883l/qmc5883l.h +3 -0
  200. esphome/components/qmc5883l/sensor.py +31 -12
  201. esphome/components/remote_base/gobox_protocol.cpp +3 -3
  202. esphome/components/remote_receiver/__init__.py +14 -2
  203. esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
  204. esphome/components/remote_receiver/remote_receiver.h +4 -0
  205. esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
  206. esphome/components/remote_transmitter/__init__.py +2 -2
  207. esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
  208. esphome/components/rp2040/__init__.py +11 -11
  209. esphome/components/rtttl/rtttl.cpp +2 -2
  210. esphome/components/scd30/sensor.py +1 -1
  211. esphome/components/script/__init__.py +1 -1
  212. esphome/components/script/script.h +7 -7
  213. esphome/components/select/select.cpp +5 -4
  214. esphome/components/select/select_call.cpp +1 -1
  215. esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
  216. esphome/components/sensor/__init__.py +2 -0
  217. esphome/components/sha256/__init__.py +22 -0
  218. esphome/components/sha256/sha256.cpp +116 -0
  219. esphome/components/sha256/sha256.h +60 -0
  220. esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
  221. esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
  222. esphome/components/spi/__init__.py +0 -3
  223. esphome/components/split_buffer/__init__.py +5 -0
  224. esphome/components/split_buffer/split_buffer.cpp +133 -0
  225. esphome/components/split_buffer/split_buffer.h +40 -0
  226. esphome/components/sps30/sps30.cpp +14 -10
  227. esphome/components/sps30/sps30.h +2 -0
  228. esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
  229. esphome/components/st7789v/st7789v.cpp +3 -2
  230. esphome/components/statsd/statsd.cpp +1 -1
  231. esphome/components/substitutions/__init__.py +3 -1
  232. esphome/components/substitutions/jinja.py +13 -3
  233. esphome/components/sx126x/__init__.py +16 -0
  234. esphome/components/sx126x/sx126x.cpp +15 -1
  235. esphome/components/sx126x/sx126x.h +9 -1
  236. esphome/components/sx126x/sx126x_reg.h +2 -0
  237. esphome/components/text_sensor/text_sensor.cpp +16 -0
  238. esphome/components/text_sensor/text_sensor.h +3 -10
  239. esphome/components/tormatic/tormatic_cover.cpp +1 -1
  240. esphome/components/tuya/select/tuya_select.cpp +1 -1
  241. esphome/components/tuya/tuya.cpp +29 -4
  242. esphome/components/uart/__init__.py +37 -27
  243. esphome/components/uart/uart.h +6 -0
  244. esphome/components/uart/uart_component.cpp +8 -0
  245. esphome/components/uart/uart_component.h +28 -0
  246. esphome/components/uart/uart_component_esp_idf.cpp +64 -10
  247. esphome/components/uart/uart_component_esp_idf.h +5 -2
  248. esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
  249. esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
  250. esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
  251. esphome/components/usb_host/__init__.py +12 -2
  252. esphome/components/usb_host/usb_host.h +89 -14
  253. esphome/components/usb_host/usb_host_client.cpp +157 -22
  254. esphome/components/usb_host/usb_host_component.cpp +1 -1
  255. esphome/components/usb_uart/__init__.py +0 -1
  256. esphome/components/usb_uart/ch34x.cpp +4 -4
  257. esphome/components/usb_uart/cp210x.cpp +3 -3
  258. esphome/components/usb_uart/usb_uart.cpp +88 -32
  259. esphome/components/usb_uart/usb_uart.h +30 -6
  260. esphome/components/valve/valve.cpp +1 -0
  261. esphome/components/veml7700/veml7700.cpp +7 -6
  262. esphome/components/version/version_text_sensor.cpp +2 -1
  263. esphome/components/voice_assistant/voice_assistant.cpp +3 -2
  264. esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
  265. esphome/components/web_server/list_entities.cpp +3 -4
  266. esphome/components/web_server/list_entities.h +8 -10
  267. esphome/components/web_server/ota/__init__.py +1 -1
  268. esphome/components/web_server/ota/ota_web_server.cpp +9 -3
  269. esphome/components/web_server/web_server.cpp +509 -404
  270. esphome/components/web_server/web_server.h +5 -6
  271. esphome/components/web_server/web_server_v1.cpp +21 -19
  272. esphome/components/web_server_base/__init__.py +5 -2
  273. esphome/components/web_server_base/web_server_base.h +27 -7
  274. esphome/components/web_server_idf/__init__.py +1 -1
  275. esphome/components/web_server_idf/multipart.cpp +2 -2
  276. esphome/components/web_server_idf/multipart.h +2 -2
  277. esphome/components/web_server_idf/utils.cpp +2 -2
  278. esphome/components/web_server_idf/utils.h +2 -2
  279. esphome/components/web_server_idf/web_server_idf.cpp +118 -26
  280. esphome/components/web_server_idf/web_server_idf.h +12 -10
  281. esphome/components/wifi/__init__.py +13 -11
  282. esphome/components/wifi/wifi_component.cpp +74 -56
  283. esphome/components/wifi/wifi_component.h +4 -4
  284. esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
  285. esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
  286. esphome/components/wireguard/__init__.py +1 -1
  287. esphome/components/wts01/__init__.py +0 -0
  288. esphome/components/wts01/sensor.py +41 -0
  289. esphome/components/wts01/wts01.cpp +91 -0
  290. esphome/components/wts01/wts01.h +27 -0
  291. esphome/components/zephyr/__init__.py +5 -5
  292. esphome/components/zwave_proxy/__init__.py +43 -0
  293. esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
  294. esphome/components/zwave_proxy/zwave_proxy.h +93 -0
  295. esphome/config.py +79 -24
  296. esphome/config_validation.py +13 -15
  297. esphome/const.py +9 -2
  298. esphome/core/__init__.py +33 -22
  299. esphome/core/component.cpp +28 -18
  300. esphome/core/component_iterator.h +2 -1
  301. esphome/core/config.py +15 -15
  302. esphome/core/defines.h +21 -0
  303. esphome/core/entity_helpers.py +9 -6
  304. esphome/core/hash_base.h +56 -0
  305. esphome/core/helpers.cpp +19 -3
  306. esphome/core/helpers.h +26 -0
  307. esphome/core/scheduler.cpp +5 -21
  308. esphome/core/scheduler.h +19 -8
  309. esphome/core/string_ref.h +1 -1
  310. esphome/core/time.cpp +5 -5
  311. esphome/cpp_generator.py +4 -29
  312. esphome/dashboard/const.py +21 -4
  313. esphome/dashboard/core.py +10 -8
  314. esphome/dashboard/dns.py +15 -0
  315. esphome/dashboard/entries.py +15 -21
  316. esphome/dashboard/models.py +76 -0
  317. esphome/dashboard/settings.py +7 -7
  318. esphome/dashboard/status/mdns.py +46 -2
  319. esphome/dashboard/web_server.py +367 -93
  320. esphome/espota2.py +112 -32
  321. esphome/external_files.py +6 -7
  322. esphome/git.py +8 -0
  323. esphome/helpers.py +124 -77
  324. esphome/loader.py +8 -9
  325. esphome/pins.py +2 -2
  326. esphome/platformio_api.py +56 -18
  327. esphome/storage_json.py +26 -21
  328. esphome/types.py +30 -2
  329. esphome/util.py +32 -16
  330. esphome/vscode.py +8 -8
  331. esphome/wizard.py +10 -10
  332. esphome/writer.py +50 -15
  333. esphome/yaml_util.py +37 -31
  334. esphome/zeroconf.py +12 -3
  335. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/METADATA +12 -12
  336. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/RECORD +340 -320
  337. esphome/components/event_emitter/__init__.py +0 -5
  338. esphome/components/event_emitter/event_emitter.cpp +0 -14
  339. esphome/components/event_emitter/event_emitter.h +0 -63
  340. esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
  341. esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
  342. esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
  343. esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
  344. esphome/components/uart/uart_component_esp32_arduino.h +0 -60
  345. esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
  346. esphome/core/string_ref.cpp +0 -12
  347. esphome/dashboard/util/file.py +0 -63
  348. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/WHEEL +0 -0
  349. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/entry_points.txt +0 -0
  350. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/licenses/LICENSE +0 -0
  351. {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/top_level.txt +0 -0
@@ -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
 
@@ -2,11 +2,12 @@
2
2
 
3
3
  #include "ble_descriptor.h"
4
4
  #include "esphome/components/esp32_ble/ble_uuid.h"
5
- #include "esphome/components/event_emitter/event_emitter.h"
6
5
  #include "esphome/components/bytebuffer/bytebuffer.h"
7
6
 
8
7
  #include <vector>
9
- #include <unordered_map>
8
+ #include <span>
9
+ #include <functional>
10
+ #include <memory>
10
11
 
11
12
  #ifdef USE_ESP32
12
13
 
@@ -23,22 +24,10 @@ namespace esp32_ble_server {
23
24
 
24
25
  using namespace esp32_ble;
25
26
  using namespace bytebuffer;
26
- using namespace event_emitter;
27
27
 
28
28
  class BLEService;
29
29
 
30
- namespace BLECharacteristicEvt {
31
- enum VectorEvt {
32
- ON_WRITE,
33
- };
34
-
35
- enum EmptyEvt {
36
- ON_READ,
37
- };
38
- } // namespace BLECharacteristicEvt
39
-
40
- class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, std::vector<uint8_t>, uint16_t>,
41
- public EventEmitter<BLECharacteristicEvt::EmptyEvt, uint16_t> {
30
+ class BLECharacteristic {
42
31
  public:
43
32
  BLECharacteristic(ESPBTUUID uuid, uint32_t properties);
44
33
  ~BLECharacteristic();
@@ -77,6 +66,15 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s
77
66
  bool is_created();
78
67
  bool is_failed();
79
68
 
69
+ // Direct callback registration - only allocates when callback is set
70
+ void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) {
71
+ this->on_write_callback_ =
72
+ std::make_unique<std::function<void(std::span<const uint8_t>, uint16_t)>>(std::move(callback));
73
+ }
74
+ void on_read(std::function<void(uint16_t)> &&callback) {
75
+ this->on_read_callback_ = std::make_unique<std::function<void(uint16_t)>>(std::move(callback));
76
+ }
77
+
80
78
  protected:
81
79
  bool write_event_{false};
82
80
  BLEService *service_{};
@@ -89,7 +87,20 @@ class BLECharacteristic : public EventEmitter<BLECharacteristicEvt::VectorEvt, s
89
87
  SemaphoreHandle_t set_value_lock_;
90
88
 
91
89
  std::vector<BLEDescriptor *> descriptors_;
92
- std::unordered_map<uint16_t, bool> clients_to_notify_;
90
+
91
+ struct ClientNotificationEntry {
92
+ uint16_t conn_id;
93
+ bool indicate; // true = indicate, false = notify
94
+ };
95
+ std::vector<ClientNotificationEntry> clients_to_notify_;
96
+
97
+ void remove_client_from_notify_list_(uint16_t conn_id);
98
+ ClientNotificationEntry *find_client_in_notify_list_(uint16_t conn_id);
99
+
100
+ void set_property_bit_(esp_gatt_char_prop_t bit, bool value);
101
+
102
+ std::unique_ptr<std::function<void(std::span<const uint8_t>, uint16_t)>> on_write_callback_;
103
+ std::unique_ptr<std::function<void(uint16_t)>> on_read_callback_;
93
104
 
94
105
  esp_gatt_perm_t permissions_ = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
95
106
 
@@ -74,9 +74,10 @@ void BLEDescriptor::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_
74
74
  break;
75
75
  this->value_.attr_len = param->write.len;
76
76
  memcpy(this->value_.attr_value, param->write.value, param->write.len);
77
- this->emit_(BLEDescriptorEvt::VectorEvt::ON_WRITE,
78
- std::vector<uint8_t>(param->write.value, param->write.value + param->write.len),
79
- param->write.conn_id);
77
+ if (this->on_write_callback_) {
78
+ (*this->on_write_callback_)(std::span<const uint8_t>(param->write.value, param->write.len),
79
+ param->write.conn_id);
80
+ }
80
81
  break;
81
82
  }
82
83
  default:
@@ -1,30 +1,26 @@
1
1
  #pragma once
2
2
 
3
3
  #include "esphome/components/esp32_ble/ble_uuid.h"
4
- #include "esphome/components/event_emitter/event_emitter.h"
5
4
  #include "esphome/components/bytebuffer/bytebuffer.h"
6
5
 
7
6
  #ifdef USE_ESP32
8
7
 
9
8
  #include <esp_gatt_defs.h>
10
9
  #include <esp_gatts_api.h>
10
+ #include <span>
11
+ #include <functional>
12
+ #include <memory>
11
13
 
12
14
  namespace esphome {
13
15
  namespace esp32_ble_server {
14
16
 
15
17
  using namespace esp32_ble;
16
18
  using namespace bytebuffer;
17
- using namespace event_emitter;
18
19
 
19
20
  class BLECharacteristic;
20
21
 
21
- namespace BLEDescriptorEvt {
22
- enum VectorEvt {
23
- ON_WRITE,
24
- };
25
- } // namespace BLEDescriptorEvt
26
-
27
- class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vector<uint8_t>, uint16_t> {
22
+ // Base class for BLE descriptors
23
+ class BLEDescriptor {
28
24
  public:
29
25
  BLEDescriptor(ESPBTUUID uuid, uint16_t max_len = 100, bool read = true, bool write = true);
30
26
  virtual ~BLEDescriptor();
@@ -39,6 +35,12 @@ class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vect
39
35
  bool is_created() { return this->state_ == CREATED; }
40
36
  bool is_failed() { return this->state_ == FAILED; }
41
37
 
38
+ // Direct callback registration - only allocates when callback is set
39
+ void on_write(std::function<void(std::span<const uint8_t>, uint16_t)> &&callback) {
40
+ this->on_write_callback_ =
41
+ std::make_unique<std::function<void(std::span<const uint8_t>, uint16_t)>>(std::move(callback));
42
+ }
43
+
42
44
  protected:
43
45
  BLECharacteristic *characteristic_{nullptr};
44
46
  ESPBTUUID uuid_;
@@ -46,6 +48,8 @@ class BLEDescriptor : public EventEmitter<BLEDescriptorEvt::VectorEvt, std::vect
46
48
 
47
49
  esp_attr_value_t value_{};
48
50
 
51
+ std::unique_ptr<std::function<void(std::span<const uint8_t>, uint16_t)>> on_write_callback_;
52
+
49
53
  esp_gatt_perm_t permissions_{};
50
54
 
51
55
  enum State : uint8_t {
@@ -70,11 +70,11 @@ void BLEServer::loop() {
70
70
  // it is at the top of the GATT table
71
71
  this->device_information_service_->do_create(this);
72
72
  // Create all services previously created
73
- for (auto &pair : this->services_) {
74
- if (pair.second == this->device_information_service_) {
73
+ for (auto &entry : this->services_) {
74
+ if (entry.service == this->device_information_service_) {
75
75
  continue;
76
76
  }
77
- pair.second->do_create(this);
77
+ entry.service->do_create(this);
78
78
  }
79
79
  this->state_ = STARTING_SERVICE;
80
80
  }
@@ -118,7 +118,7 @@ BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t n
118
118
  }
119
119
  BLEService *service = // NOLINT(cppcoreguidelines-owning-memory)
120
120
  new BLEService(uuid, num_handles, inst_id, advertise);
121
- this->services_.emplace(BLEServer::get_service_key(uuid, inst_id), service);
121
+ this->services_.push_back({uuid, inst_id, service});
122
122
  if (this->parent_->is_active() && this->registered_) {
123
123
  service->do_create(this);
124
124
  }
@@ -127,26 +127,32 @@ BLEService *BLEServer::create_service(ESPBTUUID uuid, bool advertise, uint16_t n
127
127
 
128
128
  void BLEServer::remove_service(ESPBTUUID uuid, uint8_t inst_id) {
129
129
  ESP_LOGV(TAG, "Removing BLE service - %s %d", uuid.to_string().c_str(), inst_id);
130
- BLEService *service = this->get_service(uuid, inst_id);
131
- if (service == nullptr) {
132
- ESP_LOGW(TAG, "BLE service %s %d does not exist", uuid.to_string().c_str(), inst_id);
133
- return;
130
+ for (auto it = this->services_.begin(); it != this->services_.end(); ++it) {
131
+ if (it->uuid == uuid && it->inst_id == inst_id) {
132
+ it->service->do_delete();
133
+ delete it->service; // NOLINT(cppcoreguidelines-owning-memory)
134
+ this->services_.erase(it);
135
+ return;
136
+ }
134
137
  }
135
- service->do_delete();
136
- delete service; // NOLINT(cppcoreguidelines-owning-memory)
137
- this->services_.erase(BLEServer::get_service_key(uuid, inst_id));
138
+ ESP_LOGW(TAG, "BLE service %s %d does not exist", uuid.to_string().c_str(), inst_id);
138
139
  }
139
140
 
140
141
  BLEService *BLEServer::get_service(ESPBTUUID uuid, uint8_t inst_id) {
141
- BLEService *service = nullptr;
142
- if (this->services_.count(BLEServer::get_service_key(uuid, inst_id)) > 0) {
143
- service = this->services_.at(BLEServer::get_service_key(uuid, inst_id));
142
+ for (auto &entry : this->services_) {
143
+ if (entry.uuid == uuid && entry.inst_id == inst_id) {
144
+ return entry.service;
145
+ }
144
146
  }
145
- return service;
147
+ return nullptr;
146
148
  }
147
149
 
148
- std::string BLEServer::get_service_key(ESPBTUUID uuid, uint8_t inst_id) {
149
- return uuid.to_string() + std::to_string(inst_id);
150
+ void BLEServer::dispatch_callbacks_(CallbackType type, uint16_t conn_id) {
151
+ for (auto &entry : this->callbacks_) {
152
+ if (entry.type == type) {
153
+ entry.callback(conn_id);
154
+ }
155
+ }
150
156
  }
151
157
 
152
158
  void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
@@ -155,14 +161,14 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga
155
161
  case ESP_GATTS_CONNECT_EVT: {
156
162
  ESP_LOGD(TAG, "BLE Client connected");
157
163
  this->add_client_(param->connect.conn_id);
158
- this->emit_(BLEServerEvt::EmptyEvt::ON_CONNECT, param->connect.conn_id);
164
+ this->dispatch_callbacks_(CallbackType::ON_CONNECT, param->connect.conn_id);
159
165
  break;
160
166
  }
161
167
  case ESP_GATTS_DISCONNECT_EVT: {
162
168
  ESP_LOGD(TAG, "BLE Client disconnected");
163
169
  this->remove_client_(param->disconnect.conn_id);
164
170
  this->parent_->advertising_start();
165
- this->emit_(BLEServerEvt::EmptyEvt::ON_DISCONNECT, param->disconnect.conn_id);
171
+ this->dispatch_callbacks_(CallbackType::ON_DISCONNECT, param->disconnect.conn_id);
166
172
  break;
167
173
  }
168
174
  case ESP_GATTS_REG_EVT: {
@@ -174,17 +180,46 @@ void BLEServer::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t ga
174
180
  break;
175
181
  }
176
182
 
177
- for (const auto &pair : this->services_) {
178
- pair.second->gatts_event_handler(event, gatts_if, param);
183
+ for (auto &entry : this->services_) {
184
+ entry.service->gatts_event_handler(event, gatts_if, param);
185
+ }
186
+ }
187
+
188
+ int8_t BLEServer::find_client_index_(uint16_t conn_id) const {
189
+ for (uint8_t i = 0; i < this->client_count_; i++) {
190
+ if (this->clients_[i] == conn_id)
191
+ return i;
192
+ }
193
+ return -1;
194
+ }
195
+
196
+ void BLEServer::add_client_(uint16_t conn_id) {
197
+ // Check if already in list
198
+ if (this->find_client_index_(conn_id) >= 0)
199
+ return;
200
+ // Add if there's space
201
+ if (this->client_count_ < USE_ESP32_BLE_MAX_CONNECTIONS) {
202
+ this->clients_[this->client_count_++] = conn_id;
203
+ } else {
204
+ // This should never happen since max clients is known at compile time
205
+ ESP_LOGE(TAG, "Client array full");
206
+ }
207
+ }
208
+
209
+ void BLEServer::remove_client_(uint16_t conn_id) {
210
+ int8_t index = this->find_client_index_(conn_id);
211
+ if (index >= 0) {
212
+ // Replace with last element and decrement count (client order not preserved)
213
+ this->clients_[index] = this->clients_[--this->client_count_];
179
214
  }
180
215
  }
181
216
 
182
217
  void BLEServer::ble_before_disabled_event_handler() {
183
218
  // Delete all clients
184
- this->clients_.clear();
219
+ this->client_count_ = 0;
185
220
  // Delete all services
186
- for (auto &pair : this->services_) {
187
- pair.second->do_delete();
221
+ for (auto &entry : this->services_) {
222
+ entry.service->do_delete();
188
223
  }
189
224
  this->registered_ = false;
190
225
  this->state_ = INIT;
@@ -12,7 +12,7 @@
12
12
  #include <memory>
13
13
  #include <vector>
14
14
  #include <unordered_map>
15
- #include <unordered_set>
15
+ #include <functional>
16
16
 
17
17
  #ifdef USE_ESP32
18
18
 
@@ -24,18 +24,7 @@ namespace esp32_ble_server {
24
24
  using namespace esp32_ble;
25
25
  using namespace bytebuffer;
26
26
 
27
- namespace BLEServerEvt {
28
- enum EmptyEvt {
29
- ON_CONNECT,
30
- ON_DISCONNECT,
31
- };
32
- } // namespace BLEServerEvt
33
-
34
- class BLEServer : public Component,
35
- public GATTsEventHandler,
36
- public BLEStatusEventHandler,
37
- public Parented<ESP32BLE>,
38
- public EventEmitter<BLEServerEvt::EmptyEvt, uint16_t> {
27
+ class BLEServer : public Component, public GATTsEventHandler, public BLEStatusEventHandler, public Parented<ESP32BLE> {
39
28
  public:
40
29
  void setup() override;
41
30
  void loop() override;
@@ -57,27 +46,56 @@ class BLEServer : public Component,
57
46
  void set_device_information_service(BLEService *service) { this->device_information_service_ = service; }
58
47
 
59
48
  esp_gatt_if_t get_gatts_if() { return this->gatts_if_; }
60
- uint32_t get_connected_client_count() { return this->clients_.size(); }
61
- const std::unordered_set<uint16_t> &get_clients() { return this->clients_; }
49
+ uint32_t get_connected_client_count() { return this->client_count_; }
50
+ const uint16_t *get_clients() const { return this->clients_; }
51
+ uint8_t get_client_count() const { return this->client_count_; }
62
52
 
63
53
  void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
64
54
  esp_ble_gatts_cb_param_t *param) override;
65
55
 
66
56
  void ble_before_disabled_event_handler() override;
67
57
 
58
+ // Direct callback registration - supports multiple callbacks
59
+ void on_connect(std::function<void(uint16_t)> &&callback) {
60
+ this->callbacks_.push_back({CallbackType::ON_CONNECT, std::move(callback)});
61
+ }
62
+ void on_disconnect(std::function<void(uint16_t)> &&callback) {
63
+ this->callbacks_.push_back({CallbackType::ON_DISCONNECT, std::move(callback)});
64
+ }
65
+
68
66
  protected:
69
- static std::string get_service_key(ESPBTUUID uuid, uint8_t inst_id);
67
+ enum class CallbackType : uint8_t {
68
+ ON_CONNECT,
69
+ ON_DISCONNECT,
70
+ };
71
+
72
+ struct CallbackEntry {
73
+ CallbackType type;
74
+ std::function<void(uint16_t)> callback;
75
+ };
76
+
77
+ struct ServiceEntry {
78
+ ESPBTUUID uuid;
79
+ uint8_t inst_id;
80
+ BLEService *service;
81
+ };
82
+
70
83
  void restart_advertising_();
71
84
 
72
- void add_client_(uint16_t conn_id) { this->clients_.insert(conn_id); }
73
- void remove_client_(uint16_t conn_id) { this->clients_.erase(conn_id); }
85
+ int8_t find_client_index_(uint16_t conn_id) const;
86
+ void add_client_(uint16_t conn_id);
87
+ void remove_client_(uint16_t conn_id);
88
+ void dispatch_callbacks_(CallbackType type, uint16_t conn_id);
89
+
90
+ std::vector<CallbackEntry> callbacks_;
74
91
 
75
92
  std::vector<uint8_t> manufacturer_data_{};
76
93
  esp_gatt_if_t gatts_if_{0};
77
94
  bool registered_{false};
78
95
 
79
- std::unordered_set<uint16_t> clients_;
80
- std::unordered_map<std::string, BLEService *> services_{};
96
+ uint16_t clients_[USE_ESP32_BLE_MAX_CONNECTIONS]{};
97
+ uint8_t client_count_{0};
98
+ std::vector<ServiceEntry> services_{};
81
99
  std::vector<BLEService *> services_to_start_{};
82
100
  BLEService *device_information_service_{};
83
101