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
@@ -1504,6 +1504,10 @@ BOARDS = {
1504
1504
  "name": "BPI-Bit",
1505
1505
  "variant": VARIANT_ESP32,
1506
1506
  },
1507
+ "bpi-centi-s3": {
1508
+ "name": "BPI-Centi-S3",
1509
+ "variant": VARIANT_ESP32S3,
1510
+ },
1507
1511
  "bpi_leaf_s3": {
1508
1512
  "name": "BPI-Leaf-S3",
1509
1513
  "variant": VARIANT_ESP32S3,
@@ -1664,10 +1668,46 @@ BOARDS = {
1664
1668
  "name": "Espressif ESP32-S3-DevKitC-1-N8 (8 MB QD, No PSRAM)",
1665
1669
  "variant": VARIANT_ESP32S3,
1666
1670
  },
1671
+ "esp32-s3-devkitc-1-n32r8v": {
1672
+ "name": "Espressif ESP32-S3-DevKitC-1-N32R8V (32 MB Flash Octal, 8 MB PSRAM Octal)",
1673
+ "variant": VARIANT_ESP32S3,
1674
+ },
1675
+ "esp32-s3-devkitc1-n16r16": {
1676
+ "name": "Espressif ESP32-S3-DevKitC-1-N16R16V (16 MB Flash Quad, 16 MB PSRAM Octal)",
1677
+ "variant": VARIANT_ESP32S3,
1678
+ },
1679
+ "esp32-s3-devkitc1-n16r2": {
1680
+ "name": "Espressif ESP32-S3-DevKitC-1-N16R2 (16 MB Flash Quad, 2 MB PSRAM Quad)",
1681
+ "variant": VARIANT_ESP32S3,
1682
+ },
1683
+ "esp32-s3-devkitc1-n16r8": {
1684
+ "name": "Espressif ESP32-S3-DevKitC-1-N16R8V (16 MB Flash Quad, 8 MB PSRAM Octal)",
1685
+ "variant": VARIANT_ESP32S3,
1686
+ },
1687
+ "esp32-s3-devkitc1-n4r2": {
1688
+ "name": "Espressif ESP32-S3-DevKitC-1-N4R2 (4 MB Flash Quad, 2 MB PSRAM Quad)",
1689
+ "variant": VARIANT_ESP32S3,
1690
+ },
1691
+ "esp32-s3-devkitc1-n4r8": {
1692
+ "name": "Espressif ESP32-S3-DevKitC-1-N4R8 (4 MB Flash Quad, 8 MB PSRAM Octal)",
1693
+ "variant": VARIANT_ESP32S3,
1694
+ },
1695
+ "esp32-s3-devkitc1-n8r2": {
1696
+ "name": "Espressif ESP32-S3-DevKitC-1-N8R2 (8 MB Flash Quad, 2 MB PSRAM quad)",
1697
+ "variant": VARIANT_ESP32S3,
1698
+ },
1699
+ "esp32-s3-devkitc1-n8r8": {
1700
+ "name": "Espressif ESP32-S3-DevKitC-1-N8R8 (8 MB Flash Quad, 8 MB PSRAM Octal)",
1701
+ "variant": VARIANT_ESP32S3,
1702
+ },
1667
1703
  "esp32-s3-devkitm-1": {
1668
1704
  "name": "Espressif ESP32-S3-DevKitM-1",
1669
1705
  "variant": VARIANT_ESP32S3,
1670
1706
  },
1707
+ "esp32-s3-fh4r2": {
1708
+ "name": "Espressif ESP32-S3-FH4R2 (4 MB QD, 2MB PSRAM)",
1709
+ "variant": VARIANT_ESP32S3,
1710
+ },
1671
1711
  "esp32-solo1": {
1672
1712
  "name": "Espressif Generic ESP32-solo1 4M Flash",
1673
1713
  "variant": VARIANT_ESP32,
@@ -1764,6 +1804,10 @@ BOARDS = {
1764
1804
  "name": "Franzininho WiFi MSC",
1765
1805
  "variant": VARIANT_ESP32S2,
1766
1806
  },
1807
+ "freenove-esp32-s3-n8r8": {
1808
+ "name": "Freenove ESP32-S3 WROOM N8R8 (8MB Flash / 8MB PSRAM)",
1809
+ "variant": VARIANT_ESP32S3,
1810
+ },
1767
1811
  "freenove_esp32_s3_wroom": {
1768
1812
  "name": "Freenove ESP32-S3 WROOM N8R8 (8MB Flash / 8MB PSRAM)",
1769
1813
  "variant": VARIANT_ESP32S3,
@@ -1964,6 +2008,10 @@ BOARDS = {
1964
2008
  "name": "M5Stack AtomS3",
1965
2009
  "variant": VARIANT_ESP32S3,
1966
2010
  },
2011
+ "m5stack-atoms3u": {
2012
+ "name": "M5Stack AtomS3U",
2013
+ "variant": VARIANT_ESP32S3,
2014
+ },
1967
2015
  "m5stack-core-esp32": {
1968
2016
  "name": "M5Stack Core ESP32",
1969
2017
  "variant": VARIANT_ESP32,
@@ -2084,6 +2132,10 @@ BOARDS = {
2084
2132
  "name": "Ai-Thinker NodeMCU-32S2 (ESP-12K)",
2085
2133
  "variant": VARIANT_ESP32S2,
2086
2134
  },
2135
+ "nologo_esp32c3_super_mini": {
2136
+ "name": "Nologo ESP32C3 SuperMini",
2137
+ "variant": VARIANT_ESP32C3,
2138
+ },
2087
2139
  "nscreen-32": {
2088
2140
  "name": "YeaCreate NSCREEN-32",
2089
2141
  "variant": VARIANT_ESP32,
@@ -2192,6 +2244,10 @@ BOARDS = {
2192
2244
  "name": "SparkFun LoRa Gateway 1-Channel",
2193
2245
  "variant": VARIANT_ESP32,
2194
2246
  },
2247
+ "sparkfun_pro_micro_esp32c3": {
2248
+ "name": "SparkFun Pro Micro ESP32-C3",
2249
+ "variant": VARIANT_ESP32C3,
2250
+ },
2195
2251
  "sparkfun_qwiic_pocket_esp32c6": {
2196
2252
  "name": "SparkFun ESP32-C6 Qwiic Pocket",
2197
2253
  "variant": VARIANT_ESP32C6,
@@ -2256,6 +2312,14 @@ BOARDS = {
2256
2312
  "name": "Turta IoT Node",
2257
2313
  "variant": VARIANT_ESP32,
2258
2314
  },
2315
+ "um_bling": {
2316
+ "name": "Unexpected Maker BLING!",
2317
+ "variant": VARIANT_ESP32S3,
2318
+ },
2319
+ "um_edges3_d": {
2320
+ "name": "Unexpected Maker EDGES3[D]",
2321
+ "variant": VARIANT_ESP32S3,
2322
+ },
2259
2323
  "um_feathers2": {
2260
2324
  "name": "Unexpected Maker FeatherS2",
2261
2325
  "variant": VARIANT_ESP32S2,
@@ -2268,10 +2332,18 @@ BOARDS = {
2268
2332
  "name": "Unexpected Maker FeatherS3",
2269
2333
  "variant": VARIANT_ESP32S3,
2270
2334
  },
2335
+ "um_feathers3_neo": {
2336
+ "name": "Unexpected Maker FeatherS3 Neo",
2337
+ "variant": VARIANT_ESP32S3,
2338
+ },
2271
2339
  "um_nanos3": {
2272
2340
  "name": "Unexpected Maker NanoS3",
2273
2341
  "variant": VARIANT_ESP32S3,
2274
2342
  },
2343
+ "um_omgs3": {
2344
+ "name": "Unexpected Maker OMGS3",
2345
+ "variant": VARIANT_ESP32S3,
2346
+ },
2275
2347
  "um_pros3": {
2276
2348
  "name": "Unexpected Maker PROS3",
2277
2349
  "variant": VARIANT_ESP32S3,
@@ -2280,6 +2352,14 @@ BOARDS = {
2280
2352
  "name": "Unexpected Maker RMP",
2281
2353
  "variant": VARIANT_ESP32S2,
2282
2354
  },
2355
+ "um_squixl": {
2356
+ "name": "Unexpected Maker SQUiXL",
2357
+ "variant": VARIANT_ESP32S3,
2358
+ },
2359
+ "um_tinyc6": {
2360
+ "name": "Unexpected Maker TinyC6",
2361
+ "variant": VARIANT_ESP32C6,
2362
+ },
2283
2363
  "um_tinys2": {
2284
2364
  "name": "Unexpected Maker TinyS2",
2285
2365
  "variant": VARIANT_ESP32S2,
@@ -2401,3 +2481,4 @@ BOARDS = {
2401
2481
  "variant": VARIANT_ESP32S3,
2402
2482
  },
2403
2483
  }
2484
+ # DO NOT ADD ANYTHING BELOW THIS LINE
@@ -17,7 +17,14 @@ static const char *const TAG = "esp32.preferences";
17
17
 
18
18
  struct NVSData {
19
19
  std::string key;
20
- std::vector<uint8_t> data;
20
+ std::unique_ptr<uint8_t[]> data;
21
+ size_t len;
22
+
23
+ void set_data(const uint8_t *src, size_t size) {
24
+ data = std::make_unique<uint8_t[]>(size);
25
+ memcpy(data.get(), src, size);
26
+ len = size;
27
+ }
21
28
  };
22
29
 
23
30
  static std::vector<NVSData> s_pending_save; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
@@ -30,26 +37,26 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
30
37
  // try find in pending saves and update that
31
38
  for (auto &obj : s_pending_save) {
32
39
  if (obj.key == key) {
33
- obj.data.assign(data, data + len);
40
+ obj.set_data(data, len);
34
41
  return true;
35
42
  }
36
43
  }
37
44
  NVSData save{};
38
45
  save.key = key;
39
- save.data.assign(data, data + len);
40
- s_pending_save.emplace_back(save);
41
- ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %d", key.c_str(), len);
46
+ save.set_data(data, len);
47
+ s_pending_save.emplace_back(std::move(save));
48
+ ESP_LOGVV(TAG, "s_pending_save: key: %s, len: %zu", key.c_str(), len);
42
49
  return true;
43
50
  }
44
51
  bool load(uint8_t *data, size_t len) override {
45
52
  // try find in pending saves and load from that
46
53
  for (auto &obj : s_pending_save) {
47
54
  if (obj.key == key) {
48
- if (obj.data.size() != len) {
55
+ if (obj.len != len) {
49
56
  // size mismatch
50
57
  return false;
51
58
  }
52
- memcpy(data, obj.data.data(), len);
59
+ memcpy(data, obj.data.get(), len);
53
60
  return true;
54
61
  }
55
62
  }
@@ -61,7 +68,7 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
61
68
  return false;
62
69
  }
63
70
  if (actual_len != len) {
64
- ESP_LOGVV(TAG, "NVS length does not match (%u!=%u)", actual_len, len);
71
+ ESP_LOGVV(TAG, "NVS length does not match (%zu!=%zu)", actual_len, len);
65
72
  return false;
66
73
  }
67
74
  err = nvs_get_blob(nvs_handle, key.c_str(), data, &len);
@@ -69,7 +76,7 @@ class ESP32PreferenceBackend : public ESPPreferenceBackend {
69
76
  ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", key.c_str(), esp_err_to_name(err));
70
77
  return false;
71
78
  } else {
72
- ESP_LOGVV(TAG, "nvs_get_blob: key: %s, len: %d", key.c_str(), len);
79
+ ESP_LOGVV(TAG, "nvs_get_blob: key: %s, len: %zu", key.c_str(), len);
73
80
  }
74
81
  return true;
75
82
  }
@@ -112,7 +119,7 @@ class ESP32Preferences : public ESPPreferences {
112
119
  if (s_pending_save.empty())
113
120
  return true;
114
121
 
115
- ESP_LOGV(TAG, "Saving %d items...", s_pending_save.size());
122
+ ESP_LOGV(TAG, "Saving %zu items...", s_pending_save.size());
116
123
  // goal try write all pending saves even if one fails
117
124
  int cached = 0, written = 0, failed = 0;
118
125
  esp_err_t last_err = ESP_OK;
@@ -123,11 +130,10 @@ class ESP32Preferences : public ESPPreferences {
123
130
  const auto &save = s_pending_save[i];
124
131
  ESP_LOGVV(TAG, "Checking if NVS data %s has changed", save.key.c_str());
125
132
  if (is_changed(nvs_handle, save)) {
126
- esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.data(), save.data.size());
127
- ESP_LOGV(TAG, "sync: key: %s, len: %d", save.key.c_str(), save.data.size());
133
+ esp_err_t err = nvs_set_blob(nvs_handle, save.key.c_str(), save.data.get(), save.len);
134
+ ESP_LOGV(TAG, "sync: key: %s, len: %zu", save.key.c_str(), save.len);
128
135
  if (err != 0) {
129
- ESP_LOGV(TAG, "nvs_set_blob('%s', len=%u) failed: %s", save.key.c_str(), save.data.size(),
130
- esp_err_to_name(err));
136
+ ESP_LOGV(TAG, "nvs_set_blob('%s', len=%zu) failed: %s", save.key.c_str(), save.len, esp_err_to_name(err));
131
137
  failed++;
132
138
  last_err = err;
133
139
  last_key = save.key;
@@ -135,7 +141,7 @@ class ESP32Preferences : public ESPPreferences {
135
141
  }
136
142
  written++;
137
143
  } else {
138
- ESP_LOGV(TAG, "NVS data not changed skipping %s len=%u", save.key.c_str(), save.data.size());
144
+ ESP_LOGV(TAG, "NVS data not changed skipping %s len=%zu", save.key.c_str(), save.len);
139
145
  cached++;
140
146
  }
141
147
  s_pending_save.erase(s_pending_save.begin() + i);
@@ -164,7 +170,7 @@ class ESP32Preferences : public ESPPreferences {
164
170
  return true;
165
171
  }
166
172
  // Check size first before allocating memory
167
- if (actual_len != to_save.data.size()) {
173
+ if (actual_len != to_save.len) {
168
174
  return true;
169
175
  }
170
176
  auto stored_data = std::make_unique<uint8_t[]>(actual_len);
@@ -173,7 +179,7 @@ class ESP32Preferences : public ESPPreferences {
173
179
  ESP_LOGV(TAG, "nvs_get_blob('%s') failed: %s", to_save.key.c_str(), esp_err_to_name(err));
174
180
  return true;
175
181
  }
176
- return memcmp(to_save.data.data(), stored_data.get(), to_save.data.size()) != 0;
182
+ return memcmp(to_save.data.get(), stored_data.get(), to_save.len) != 0;
177
183
  }
178
184
 
179
185
  bool reset() override {
@@ -1,5 +1,8 @@
1
+ from collections.abc import Callable, MutableMapping
1
2
  from enum import Enum
3
+ import logging
2
4
  import re
5
+ from typing import Any
3
6
 
4
7
  from esphome import automation
5
8
  import esphome.codegen as cg
@@ -9,6 +12,7 @@ from esphome.const import (
9
12
  CONF_ENABLE_ON_BOOT,
10
13
  CONF_ESPHOME,
11
14
  CONF_ID,
15
+ CONF_MAX_CONNECTIONS,
12
16
  CONF_NAME,
13
17
  CONF_NAME_ADD_MAC_SUFFIX,
14
18
  )
@@ -19,6 +23,8 @@ DEPENDENCIES = ["esp32"]
19
23
  CODEOWNERS = ["@jesserockz", "@Rapsssito", "@bdraco"]
20
24
  DOMAIN = "esp32_ble"
21
25
 
26
+ _LOGGER = logging.getLogger(__name__)
27
+
22
28
 
23
29
  class BTLoggers(Enum):
24
30
  """Bluetooth logger categories available in ESP-IDF.
@@ -127,6 +133,28 @@ CONF_DISABLE_BT_LOGS = "disable_bt_logs"
127
133
  CONF_CONNECTION_TIMEOUT = "connection_timeout"
128
134
  CONF_MAX_NOTIFICATIONS = "max_notifications"
129
135
 
136
+ # BLE connection limits
137
+ # ESP-IDF CONFIG_BT_ACL_CONNECTIONS has range 1-9, default 4
138
+ # Total instances: 10 (ADV + SCAN + connections)
139
+ # - ADV only: up to 9 connections
140
+ # - SCAN only: up to 9 connections
141
+ # - ADV + SCAN: up to 8 connections
142
+ DEFAULT_MAX_CONNECTIONS = 3
143
+ IDF_MAX_CONNECTIONS = 9
144
+
145
+ # Connection slot tracking keys
146
+ KEY_ESP32_BLE = "esp32_ble"
147
+ KEY_USED_CONNECTION_SLOTS = "used_connection_slots"
148
+
149
+ # Export for use by other components (bluetooth_proxy, etc.)
150
+ __all__ = [
151
+ "DEFAULT_MAX_CONNECTIONS",
152
+ "IDF_MAX_CONNECTIONS",
153
+ "KEY_ESP32_BLE",
154
+ "KEY_USED_CONNECTION_SLOTS",
155
+ "consume_connection_slots",
156
+ ]
157
+
130
158
  NO_BLUETOOTH_VARIANTS = [const.VARIANT_ESP32S2]
131
159
 
132
160
  esp32_ble_ns = cg.esphome_ns.namespace("esp32_ble")
@@ -174,19 +202,18 @@ CONFIG_SCHEMA = cv.Schema(
174
202
  cv.Optional(
175
203
  CONF_ADVERTISING_CYCLE_TIME, default="10s"
176
204
  ): cv.positive_time_period_milliseconds,
177
- cv.SplitDefault(CONF_DISABLE_BT_LOGS, esp32_idf=True): cv.All(
178
- cv.only_with_esp_idf, cv.boolean
179
- ),
180
- cv.SplitDefault(CONF_CONNECTION_TIMEOUT, esp32_idf="20s"): cv.All(
181
- cv.only_with_esp_idf,
205
+ cv.Optional(CONF_DISABLE_BT_LOGS, default=True): cv.boolean,
206
+ cv.Optional(CONF_CONNECTION_TIMEOUT, default="20s"): cv.All(
182
207
  cv.positive_time_period_seconds,
183
208
  cv.Range(min=TimePeriod(seconds=10), max=TimePeriod(seconds=180)),
184
209
  ),
185
- cv.SplitDefault(CONF_MAX_NOTIFICATIONS, esp32_idf=12): cv.All(
186
- cv.only_with_esp_idf,
210
+ cv.Optional(CONF_MAX_NOTIFICATIONS, default=12): cv.All(
187
211
  cv.positive_int,
188
212
  cv.Range(min=1, max=64),
189
213
  ),
214
+ cv.Optional(CONF_MAX_CONNECTIONS, default=DEFAULT_MAX_CONNECTIONS): cv.All(
215
+ cv.positive_int, cv.Range(min=1, max=IDF_MAX_CONNECTIONS)
216
+ ),
190
217
  }
191
218
  ).extend(cv.COMPONENT_SCHEMA)
192
219
 
@@ -234,6 +261,60 @@ def validate_variant(_):
234
261
  raise cv.Invalid(f"{variant} does not support Bluetooth")
235
262
 
236
263
 
264
+ def consume_connection_slots(
265
+ value: int, consumer: str
266
+ ) -> Callable[[MutableMapping], MutableMapping]:
267
+ """Reserve BLE connection slots for a component.
268
+
269
+ Args:
270
+ value: Number of connection slots to reserve
271
+ consumer: Name of the component consuming the slots
272
+
273
+ Returns:
274
+ A validator function that records the slot usage
275
+ """
276
+
277
+ def _consume_connection_slots(config: MutableMapping) -> MutableMapping:
278
+ data: dict[str, Any] = CORE.data.setdefault(KEY_ESP32_BLE, {})
279
+ slots: list[str] = data.setdefault(KEY_USED_CONNECTION_SLOTS, [])
280
+ slots.extend([consumer] * value)
281
+ return config
282
+
283
+ return _consume_connection_slots
284
+
285
+
286
+ def validate_connection_slots(max_connections: int) -> None:
287
+ """Validate that BLE connection slots don't exceed the configured maximum."""
288
+ # Skip validation in testing mode to allow component grouping
289
+ if CORE.testing_mode:
290
+ return
291
+
292
+ ble_data = CORE.data.get(KEY_ESP32_BLE, {})
293
+ used_slots = ble_data.get(KEY_USED_CONNECTION_SLOTS, [])
294
+ num_used = len(used_slots)
295
+
296
+ if num_used <= max_connections:
297
+ return
298
+
299
+ slot_users = ", ".join(used_slots)
300
+
301
+ if num_used > IDF_MAX_CONNECTIONS:
302
+ raise cv.Invalid(
303
+ f"BLE components require {num_used} connection slots but maximum is {IDF_MAX_CONNECTIONS}. "
304
+ f"Reduce the number of BLE clients. Components: {slot_users}"
305
+ )
306
+
307
+ _LOGGER.warning(
308
+ "BLE components require %d connection slot(s) but only %d configured. "
309
+ "Please set 'max_connections: %d' in the 'esp32_ble' component. "
310
+ "Components: %s",
311
+ num_used,
312
+ max_connections,
313
+ num_used,
314
+ slot_users,
315
+ )
316
+
317
+
237
318
  def final_validation(config):
238
319
  validate_variant(config)
239
320
  if (name := config.get(CONF_NAME)) is not None:
@@ -246,6 +327,47 @@ def final_validation(config):
246
327
  f"Name '{name}' is too long, maximum length is {max_length} characters"
247
328
  )
248
329
 
330
+ # Set GATT Client/Server sdkconfig options based on which components are loaded
331
+ full_config = fv.full_config.get()
332
+
333
+ # Validate connection slots usage
334
+ max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
335
+ validate_connection_slots(max_connections)
336
+
337
+ # Check if BLE Server is needed
338
+ has_ble_server = "esp32_ble_server" in full_config
339
+
340
+ # Check if BLE Client is needed (via esp32_ble_tracker or esp32_ble_client)
341
+ has_ble_client = (
342
+ "esp32_ble_tracker" in full_config or "esp32_ble_client" in full_config
343
+ )
344
+
345
+ # ESP-IDF BLE stack requires GATT Server to be enabled when GATT Client is enabled
346
+ # This is an internal dependency in the Bluedroid stack (tested ESP-IDF 5.4.2-5.5.1)
347
+ # See: https://github.com/espressif/esp-idf/issues/17724
348
+ add_idf_sdkconfig_option("CONFIG_BT_GATTS_ENABLE", has_ble_server or has_ble_client)
349
+ add_idf_sdkconfig_option("CONFIG_BT_GATTC_ENABLE", has_ble_client)
350
+
351
+ # Handle max_connections: check for deprecated location in esp32_ble_tracker
352
+ max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
353
+
354
+ # Use value from tracker if esp32_ble doesn't have it explicitly set (backward compat)
355
+ if "esp32_ble_tracker" in full_config:
356
+ tracker_config = full_config["esp32_ble_tracker"]
357
+ if "max_connections" in tracker_config and CONF_MAX_CONNECTIONS not in config:
358
+ max_connections = tracker_config["max_connections"]
359
+
360
+ # Set CONFIG_BT_ACL_CONNECTIONS to the maximum connections needed + 1 for ADV/SCAN
361
+ # This is the Bluedroid host stack total instance limit (range 1-9, default 4)
362
+ # Total instances = ADV/SCAN (1) + connection slots (max_connections)
363
+ # Shared between client (tracker/ble_client) and server
364
+ add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", max_connections + 1)
365
+
366
+ # Set controller-specific max connections for ESP32 (classic)
367
+ # CONFIG_BTDM_CTRL_BLE_MAX_CONN is ESP32-specific controller limit (just connections, not ADV/SCAN)
368
+ # For newer chips (C3/S3/etc), different configs are used automatically
369
+ add_idf_sdkconfig_option("CONFIG_BTDM_CTRL_BLE_MAX_CONN", max_connections)
370
+
249
371
  return config
250
372
 
251
373
 
@@ -261,43 +383,44 @@ async def to_code(config):
261
383
  cg.add(var.set_name(name))
262
384
  await cg.register_component(var, config)
263
385
 
264
- if CORE.using_esp_idf:
265
- add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
266
- add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
267
-
268
- # Register the core BLE loggers that are always needed
269
- register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI)
270
-
271
- # Apply logger settings if log disabling is enabled
272
- if config.get(CONF_DISABLE_BT_LOGS, False):
273
- # Disable all Bluetooth loggers that are not required
274
- for logger in BTLoggers:
275
- if logger not in _required_loggers:
276
- add_idf_sdkconfig_option(f"{logger.value}_NONE", True)
277
-
278
- # Set BLE connection establishment timeout to match aioesphomeapi/bleak-retry-connector
279
- # Default is 20 seconds instead of ESP-IDF's 30 seconds. Because there is no way to
280
- # cancel a BLE connection in progress, when aioesphomeapi times out at 20 seconds,
281
- # the connection slot remains occupied for the remaining time, preventing new connection
282
- # attempts and wasting valuable connection slots.
283
- if CONF_CONNECTION_TIMEOUT in config:
284
- timeout_seconds = int(config[CONF_CONNECTION_TIMEOUT].total_seconds)
285
- add_idf_sdkconfig_option(
286
- "CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT", timeout_seconds
287
- )
288
- # Increase GATT client connection retry count for problematic devices
289
- # Default in ESP-IDF is 3, we increase to 10 for better reliability with
290
- # low-power/timing-sensitive devices
291
- add_idf_sdkconfig_option("CONFIG_BT_GATTC_CONNECT_RETRY_COUNT", 10)
292
-
293
- # Set the maximum number of notification registrations
294
- # This controls how many BLE characteristics can have notifications enabled
295
- # across all connections for a single GATT client interface
296
- # https://github.com/esphome/issues/issues/6808
297
- if CONF_MAX_NOTIFICATIONS in config:
298
- add_idf_sdkconfig_option(
299
- "CONFIG_BT_GATTC_NOTIF_REG_MAX", config[CONF_MAX_NOTIFICATIONS]
300
- )
386
+ # Define max connections for use in C++ code (e.g., ble_server.h)
387
+ max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
388
+ cg.add_define("USE_ESP32_BLE_MAX_CONNECTIONS", max_connections)
389
+
390
+ add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
391
+ add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
392
+
393
+ # Register the core BLE loggers that are always needed
394
+ register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI)
395
+
396
+ # Apply logger settings if log disabling is enabled
397
+ if config.get(CONF_DISABLE_BT_LOGS, False):
398
+ # Disable all Bluetooth loggers that are not required
399
+ for logger in BTLoggers:
400
+ if logger not in _required_loggers:
401
+ add_idf_sdkconfig_option(f"{logger.value}_NONE", True)
402
+
403
+ # Set BLE connection establishment timeout to match aioesphomeapi/bleak-retry-connector
404
+ # Default is 20 seconds instead of ESP-IDF's 30 seconds. Because there is no way to
405
+ # cancel a BLE connection in progress, when aioesphomeapi times out at 20 seconds,
406
+ # the connection slot remains occupied for the remaining time, preventing new connection
407
+ # attempts and wasting valuable connection slots.
408
+ if CONF_CONNECTION_TIMEOUT in config:
409
+ timeout_seconds = int(config[CONF_CONNECTION_TIMEOUT].total_seconds)
410
+ add_idf_sdkconfig_option("CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT", timeout_seconds)
411
+ # Increase GATT client connection retry count for problematic devices
412
+ # Default in ESP-IDF is 3, we increase to 10 for better reliability with
413
+ # low-power/timing-sensitive devices
414
+ add_idf_sdkconfig_option("CONFIG_BT_GATTC_CONNECT_RETRY_COUNT", 10)
415
+
416
+ # Set the maximum number of notification registrations
417
+ # This controls how many BLE characteristics can have notifications enabled
418
+ # across all connections for a single GATT client interface
419
+ # https://github.com/esphome/issues/issues/6808
420
+ if CONF_MAX_NOTIFICATIONS in config:
421
+ add_idf_sdkconfig_option(
422
+ "CONFIG_BT_GATTC_NOTIF_REG_MAX", config[CONF_MAX_NOTIFICATIONS]
423
+ )
301
424
 
302
425
  cg.add_define("USE_ESP32_BLE")
303
426