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.
- esphome/__main__.py +87 -31
- esphome/address_cache.py +142 -0
- esphome/automation.py +130 -32
- esphome/build_gen/platformio.py +1 -3
- esphome/codegen.py +1 -0
- esphome/components/animation/animation.cpp +2 -2
- esphome/components/api/__init__.py +167 -3
- esphome/components/api/api_connection.cpp +84 -41
- esphome/components/api/api_connection.h +22 -16
- esphome/components/api/api_frame_helper.cpp +33 -19
- esphome/components/api/api_frame_helper.h +19 -4
- esphome/components/api/api_frame_helper_noise.cpp +41 -53
- esphome/components/api/api_frame_helper_noise.h +1 -1
- esphome/components/api/api_frame_helper_plaintext.cpp +22 -31
- esphome/components/api/api_frame_helper_plaintext.h +1 -1
- esphome/components/api/api_pb2.cpp +189 -15
- esphome/components/api/api_pb2.h +132 -20
- esphome/components/api/api_pb2_dump.cpp +97 -9
- esphome/components/api/api_pb2_service.cpp +118 -160
- esphome/components/api/api_pb2_service.h +31 -3
- esphome/components/api/api_server.cpp +78 -11
- esphome/components/api/api_server.h +32 -4
- esphome/components/api/custom_api_device.h +8 -8
- esphome/components/api/homeassistant_service.h +123 -6
- esphome/components/api/proto.h +6 -2
- esphome/components/api/user_services.h +2 -2
- esphome/components/as7341/sensor.py +1 -1
- esphome/components/audio/__init__.py +1 -1
- esphome/components/audio/audio.cpp +1 -1
- esphome/components/audio/audio_decoder.cpp +9 -9
- esphome/components/bl0906/bl0906.cpp +2 -2
- esphome/components/bl0942/bl0942.cpp +2 -2
- esphome/components/ble_client/__init__.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +4 -30
- esphome/components/bluetooth_proxy/bluetooth_connection.cpp +11 -4
- esphome/components/bluetooth_proxy/bluetooth_connection.h +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +2 -2
- esphome/components/camera_encoder/__init__.py +2 -4
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.cpp +4 -2
- esphome/components/camera_encoder/esp32_camera_jpeg_encoder.h +3 -1
- esphome/components/canbus/canbus.cpp +7 -5
- esphome/components/canbus/canbus.h +4 -4
- esphome/components/captive_portal/__init__.py +18 -1
- esphome/components/captive_portal/captive_portal.cpp +40 -46
- esphome/components/captive_portal/captive_portal.h +20 -22
- esphome/components/captive_portal/dns_server_esp32_idf.cpp +205 -0
- esphome/components/captive_portal/dns_server_esp32_idf.h +27 -0
- esphome/components/ccs811/ccs811.cpp +1 -1
- esphome/components/climate/climate.cpp +10 -7
- esphome/components/cm1106/cm1106.cpp +1 -1
- esphome/components/copy/lock/copy_lock.cpp +1 -1
- esphome/components/cover/cover.cpp +1 -0
- esphome/components/daikin_arc/daikin_arc.cpp +19 -12
- esphome/components/deep_sleep/__init__.py +9 -2
- esphome/components/deep_sleep/deep_sleep_component.h +11 -9
- esphome/components/deep_sleep/deep_sleep_esp32.cpp +51 -27
- esphome/components/ektf2232/touchscreen/__init__.py +8 -5
- esphome/components/ektf2232/touchscreen/ektf2232.cpp +4 -4
- esphome/components/ektf2232/touchscreen/ektf2232.h +2 -2
- esphome/components/epaper_spi/__init__.py +1 -0
- esphome/components/epaper_spi/display.py +80 -0
- esphome/components/epaper_spi/epaper_spi.cpp +227 -0
- esphome/components/epaper_spi/epaper_spi.h +93 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.cpp +42 -0
- esphome/components/epaper_spi/epaper_spi_model_7p3in_spectra_e6.h +45 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.cpp +135 -0
- esphome/components/epaper_spi/epaper_spi_spectra_e6.h +23 -0
- esphome/components/es7210/es7210.cpp +3 -3
- esphome/components/esp32/__init__.py +254 -339
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +159 -44
- esphome/components/esp32_ble/ble.cpp +47 -3
- esphome/components/esp32_ble/ble.h +18 -0
- esphome/components/esp32_ble/ble_advertising.cpp +7 -3
- esphome/components/esp32_ble/ble_advertising.h +4 -0
- esphome/components/esp32_ble/ble_uuid.cpp +16 -42
- esphome/components/esp32_ble_beacon/__init__.py +3 -4
- esphome/components/esp32_ble_client/ble_client_base.cpp +14 -12
- esphome/components/esp32_ble_server/__init__.py +28 -14
- esphome/components/esp32_ble_server/ble_characteristic.cpp +67 -57
- esphome/components/esp32_ble_server/ble_characteristic.h +27 -16
- esphome/components/esp32_ble_server/ble_descriptor.cpp +4 -3
- esphome/components/esp32_ble_server/ble_descriptor.h +13 -9
- esphome/components/esp32_ble_server/ble_server.cpp +59 -24
- esphome/components/esp32_ble_server/ble_server.h +38 -20
- esphome/components/esp32_ble_server/ble_server_automations.cpp +49 -33
- esphome/components/esp32_ble_server/ble_server_automations.h +39 -24
- esphome/components/esp32_ble_tracker/__init__.py +25 -80
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +2 -4
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +0 -3
- esphome/components/esp32_camera/__init__.py +1 -3
- esphome/components/esp32_can/esp32_can.cpp +22 -4
- esphome/components/esp32_can/esp32_can.h +3 -0
- esphome/components/esp32_hosted/__init__.py +2 -1
- esphome/components/esp32_improv/esp32_improv_component.cpp +102 -44
- esphome/components/esp32_improv/esp32_improv_component.h +6 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +1 -1
- esphome/components/esp8266/__init__.py +3 -3
- esphome/components/esphome/ota/__init__.py +21 -2
- esphome/components/esphome/ota/ota_esphome.cpp +455 -145
- esphome/components/esphome/ota/ota_esphome.h +49 -2
- esphome/components/ethernet/__init__.py +39 -22
- esphome/components/ethernet/ethernet_component.cpp +28 -5
- esphome/components/ethernet/ethernet_component.h +5 -1
- esphome/components/external_components/__init__.py +8 -6
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +2 -1
- esphome/components/font/__init__.py +5 -5
- esphome/components/graph/graph.cpp +1 -1
- esphome/components/graphical_display_menu/graphical_display_menu.cpp +3 -2
- esphome/components/haier/hon_climate.cpp +2 -2
- esphome/components/haier/hon_climate.h +1 -1
- esphome/components/hdc1080/hdc1080.cpp +42 -34
- esphome/components/hdc1080/hdc1080.h +1 -3
- esphome/components/homeassistant/number/homeassistant_number.cpp +2 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/http_request/__init__.py +3 -3
- esphome/components/htu21d/htu21d.cpp +13 -18
- esphome/components/htu21d/htu21d.h +1 -1
- esphome/components/i2s_audio/__init__.py +1 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +2 -2
- esphome/components/improv_serial/improv_serial_component.cpp +12 -15
- esphome/components/improv_serial/improv_serial_component.h +6 -8
- esphome/components/json/json_util.cpp +35 -43
- esphome/components/json/json_util.h +57 -0
- esphome/components/kamstrup_kmp/kamstrup_kmp.cpp +2 -2
- esphome/components/key_collector/key_collector.h +4 -4
- esphome/components/libretiny/__init__.py +6 -6
- esphome/components/libretiny/preferences.cpp +23 -16
- esphome/components/light/light_call.cpp +98 -120
- esphome/components/light/light_call.h +17 -7
- esphome/components/lm75b/__init__.py +0 -0
- esphome/components/lm75b/lm75b.cpp +39 -0
- esphome/components/lm75b/lm75b.h +19 -0
- esphome/components/lm75b/sensor.py +34 -0
- esphome/components/lock/lock.h +12 -6
- esphome/components/logger/__init__.py +15 -27
- esphome/components/logger/logger.cpp +10 -20
- esphome/components/logger/logger.h +105 -62
- esphome/components/logger/logger_esp32.cpp +0 -48
- esphome/components/logger/logger_zephyr.cpp +2 -3
- esphome/components/logger/select/logger_level_select.cpp +6 -7
- esphome/components/logger/select/logger_level_select.h +7 -0
- esphome/components/ltr501/ltr501.cpp +7 -6
- esphome/components/ltr_als_ps/ltr_als_ps.cpp +7 -6
- esphome/components/matrix_keypad/matrix_keypad.h +4 -4
- esphome/components/max7219digit/max7219digit.cpp +1 -1
- esphome/components/mcp2515/mcp2515.cpp +31 -3
- esphome/components/mcp2515/mcp2515_defs.h +3 -1
- esphome/components/md5/md5.cpp +0 -26
- esphome/components/md5/md5.h +10 -20
- esphome/components/mdns/__init__.py +19 -6
- esphome/components/mdns/mdns_component.cpp +27 -59
- esphome/components/mdns/mdns_component.h +23 -10
- esphome/components/mdns/mdns_esp32.cpp +7 -7
- esphome/components/mdns/mdns_esp8266.cpp +6 -6
- esphome/components/mdns/mdns_libretiny.cpp +3 -3
- esphome/components/mdns/mdns_rp2040.cpp +3 -3
- esphome/components/mipi/__init__.py +1 -5
- esphome/components/mipi_spi/display.py +24 -8
- esphome/components/mipi_spi/mipi_spi.h +3 -3
- esphome/components/mixer/speaker/mixer_speaker.cpp +3 -3
- esphome/components/mmc5603/mmc5603.cpp +3 -3
- esphome/components/modbus/modbus.cpp +27 -13
- esphome/components/modbus/modbus.h +5 -3
- esphome/components/modbus/modbus_definitions.h +86 -0
- esphome/components/modbus_controller/__init__.py +29 -1
- esphome/components/modbus_controller/const.py +4 -0
- esphome/components/modbus_controller/modbus_controller.cpp +38 -13
- esphome/components/modbus_controller/modbus_controller.h +18 -29
- esphome/components/mpr121/mpr121.cpp +41 -42
- esphome/components/mpr121/mpr121.h +0 -1
- esphome/components/nau7802/nau7802.cpp +2 -2
- esphome/components/network/__init__.py +7 -3
- esphome/components/nextion/display.py +4 -4
- esphome/components/nextion/nextion.cpp +8 -8
- esphome/components/number/__init__.py +2 -0
- esphome/components/number/number_call.cpp +23 -12
- esphome/components/number/number_call.h +5 -0
- esphome/components/online_image/bmp_image.cpp +2 -1
- esphome/components/online_image/jpeg_image.cpp +4 -2
- esphome/components/openthread/openthread.cpp +6 -7
- esphome/components/openthread/openthread.h +0 -1
- esphome/components/ota/ota_backend.h +1 -0
- esphome/components/packages/__init__.py +10 -8
- esphome/components/packet_transport/packet_transport.cpp +2 -0
- esphome/components/pid/pid_controller.cpp +1 -1
- esphome/components/prometheus/prometheus_handler.cpp +239 -239
- esphome/components/psram/__init__.py +30 -28
- esphome/components/qmc5883l/qmc5883l.cpp +15 -0
- esphome/components/qmc5883l/qmc5883l.h +3 -0
- esphome/components/qmc5883l/sensor.py +31 -12
- esphome/components/remote_base/gobox_protocol.cpp +3 -3
- esphome/components/remote_receiver/__init__.py +14 -2
- esphome/components/remote_receiver/{remote_receiver_esp8266.cpp → remote_receiver.cpp} +2 -2
- esphome/components/remote_receiver/remote_receiver.h +4 -0
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +18 -1
- esphome/components/remote_transmitter/__init__.py +2 -2
- esphome/components/remote_transmitter/remote_transmitter.cpp +103 -0
- esphome/components/rp2040/__init__.py +11 -11
- esphome/components/rtttl/rtttl.cpp +2 -2
- esphome/components/scd30/sensor.py +1 -1
- esphome/components/script/__init__.py +1 -1
- esphome/components/script/script.h +7 -7
- esphome/components/select/select.cpp +5 -4
- esphome/components/select/select_call.cpp +1 -1
- esphome/components/sensirion_common/i2c_sensirion.cpp +2 -1
- esphome/components/sensor/__init__.py +2 -0
- esphome/components/sha256/__init__.py +22 -0
- esphome/components/sha256/sha256.cpp +116 -0
- esphome/components/sha256/sha256.h +60 -0
- esphome/components/sim800l/sim800l.cpp +8 -4
- esphome/components/socket/lwip_raw_tcp_impl.cpp +34 -6
- esphome/components/sonoff_d1/sonoff_d1.cpp +1 -1
- esphome/components/spi/__init__.py +0 -3
- esphome/components/split_buffer/__init__.py +5 -0
- esphome/components/split_buffer/split_buffer.cpp +133 -0
- esphome/components/split_buffer/split_buffer.h +40 -0
- esphome/components/sps30/sps30.cpp +14 -10
- esphome/components/sps30/sps30.h +2 -0
- esphome/components/st7567_i2c/st7567_i2c.cpp +3 -1
- esphome/components/st7789v/st7789v.cpp +3 -2
- esphome/components/statsd/statsd.cpp +1 -1
- esphome/components/substitutions/__init__.py +3 -1
- esphome/components/substitutions/jinja.py +13 -3
- esphome/components/sx126x/__init__.py +16 -0
- esphome/components/sx126x/sx126x.cpp +15 -1
- esphome/components/sx126x/sx126x.h +9 -1
- esphome/components/sx126x/sx126x_reg.h +2 -0
- esphome/components/text_sensor/text_sensor.cpp +16 -0
- esphome/components/text_sensor/text_sensor.h +3 -10
- esphome/components/tormatic/tormatic_cover.cpp +1 -1
- esphome/components/tuya/select/tuya_select.cpp +1 -1
- esphome/components/tuya/tuya.cpp +29 -4
- esphome/components/uart/__init__.py +36 -26
- esphome/components/uart/uart.h +6 -0
- esphome/components/uart/uart_component.cpp +8 -0
- esphome/components/uart/uart_component.h +28 -0
- esphome/components/uart/uart_component_esp_idf.cpp +64 -10
- esphome/components/uart/uart_component_esp_idf.h +5 -2
- esphome/components/uponor_smatrix/climate/uponor_smatrix_climate.cpp +1 -1
- esphome/components/uponor_smatrix/sensor/uponor_smatrix_sensor.cpp +1 -1
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +3 -3
- esphome/components/usb_host/__init__.py +2 -1
- esphome/components/usb_host/usb_host.h +82 -13
- esphome/components/usb_host/usb_host_client.cpp +180 -24
- esphome/components/usb_host/usb_host_component.cpp +1 -1
- esphome/components/usb_uart/__init__.py +0 -1
- esphome/components/usb_uart/ch34x.cpp +4 -4
- esphome/components/usb_uart/cp210x.cpp +3 -3
- esphome/components/usb_uart/usb_uart.cpp +88 -32
- esphome/components/usb_uart/usb_uart.h +30 -6
- esphome/components/valve/valve.cpp +1 -0
- esphome/components/veml7700/veml7700.cpp +7 -6
- esphome/components/version/version_text_sensor.cpp +2 -1
- esphome/components/voice_assistant/voice_assistant.cpp +3 -3
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +4 -4
- esphome/components/web_server/list_entities.cpp +3 -4
- esphome/components/web_server/list_entities.h +8 -10
- esphome/components/web_server/ota/__init__.py +1 -1
- esphome/components/web_server/ota/ota_web_server.cpp +9 -3
- esphome/components/web_server/web_server.cpp +509 -404
- esphome/components/web_server/web_server.h +5 -6
- esphome/components/web_server/web_server_v1.cpp +21 -19
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.h +27 -7
- esphome/components/web_server_idf/__init__.py +1 -1
- esphome/components/web_server_idf/multipart.cpp +2 -2
- esphome/components/web_server_idf/multipart.h +2 -2
- esphome/components/web_server_idf/utils.cpp +2 -2
- esphome/components/web_server_idf/utils.h +2 -2
- esphome/components/web_server_idf/web_server_idf.cpp +118 -26
- esphome/components/web_server_idf/web_server_idf.h +12 -10
- esphome/components/wifi/__init__.py +13 -11
- esphome/components/wifi/wifi_component.cpp +73 -56
- esphome/components/wifi/wifi_component.h +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +1 -1
- esphome/components/wifi/wifi_component_esp_idf.cpp +24 -4
- esphome/components/wireguard/__init__.py +1 -1
- esphome/components/wts01/__init__.py +0 -0
- esphome/components/wts01/sensor.py +41 -0
- esphome/components/wts01/wts01.cpp +91 -0
- esphome/components/wts01/wts01.h +27 -0
- esphome/components/zephyr/__init__.py +5 -5
- esphome/components/zwave_proxy/__init__.py +43 -0
- esphome/components/zwave_proxy/zwave_proxy.cpp +346 -0
- esphome/components/zwave_proxy/zwave_proxy.h +93 -0
- esphome/config.py +79 -24
- esphome/config_validation.py +13 -15
- esphome/const.py +9 -2
- esphome/core/__init__.py +31 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +19 -0
- esphome/core/hash_base.h +56 -0
- esphome/core/helpers.cpp +19 -3
- esphome/core/helpers.h +26 -0
- esphome/core/scheduler.cpp +5 -21
- esphome/core/scheduler.h +19 -8
- esphome/core/string_ref.h +1 -1
- esphome/core/time.cpp +5 -5
- esphome/cpp_generator.py +4 -29
- esphome/dashboard/const.py +21 -4
- esphome/dashboard/core.py +10 -8
- esphome/dashboard/dns.py +15 -0
- esphome/dashboard/entries.py +15 -21
- esphome/dashboard/models.py +76 -0
- esphome/dashboard/settings.py +7 -7
- esphome/dashboard/status/mdns.py +46 -2
- esphome/dashboard/web_server.py +367 -93
- esphome/espota2.py +111 -31
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/platformio_api.py +25 -18
- esphome/storage_json.py +26 -21
- esphome/types.py +30 -2
- esphome/util.py +32 -16
- esphome/vscode.py +8 -8
- esphome/wizard.py +10 -10
- esphome/writer.py +50 -15
- esphome/yaml_util.py +37 -31
- esphome/zeroconf.py +12 -3
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +333 -313
- esphome/components/event_emitter/__init__.py +0 -5
- esphome/components/event_emitter/event_emitter.cpp +0 -14
- esphome/components/event_emitter/event_emitter.h +0 -63
- esphome/components/remote_receiver/remote_receiver_libretiny.cpp +0 -125
- esphome/components/remote_transmitter/remote_transmitter_esp8266.cpp +0 -107
- esphome/components/remote_transmitter/remote_transmitter_libretiny.cpp +0 -110
- esphome/components/uart/uart_component_esp32_arduino.cpp +0 -214
- esphome/components/uart/uart_component_esp32_arduino.h +0 -60
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +0 -860
- esphome/core/string_ref.cpp +0 -12
- esphome/dashboard/util/file.py +0 -63
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.2.dist-info → esphome-2025.10.0b1.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::
|
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.
|
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.
|
40
|
-
s_pending_save.emplace_back(save);
|
41
|
-
ESP_LOGVV(TAG, "s_pending_save: key: %s, 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.
|
55
|
+
if (obj.len != len) {
|
49
56
|
// size mismatch
|
50
57
|
return false;
|
51
58
|
}
|
52
|
-
memcpy(data, obj.data.
|
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 (%
|
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: %
|
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 %
|
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.
|
127
|
-
ESP_LOGV(TAG, "sync: key: %s, len: %
|
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=%
|
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=%
|
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.
|
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.
|
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.
|
178
|
-
|
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.
|
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,56 @@ 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
|
+
ble_data = CORE.data.get(KEY_ESP32_BLE, {})
|
289
|
+
used_slots = ble_data.get(KEY_USED_CONNECTION_SLOTS, [])
|
290
|
+
num_used = len(used_slots)
|
291
|
+
|
292
|
+
if num_used <= max_connections:
|
293
|
+
return
|
294
|
+
|
295
|
+
slot_users = ", ".join(used_slots)
|
296
|
+
|
297
|
+
if num_used > IDF_MAX_CONNECTIONS:
|
298
|
+
raise cv.Invalid(
|
299
|
+
f"BLE components require {num_used} connection slots but maximum is {IDF_MAX_CONNECTIONS}. "
|
300
|
+
f"Reduce the number of BLE clients. Components: {slot_users}"
|
301
|
+
)
|
302
|
+
|
303
|
+
_LOGGER.warning(
|
304
|
+
"BLE components require %d connection slot(s) but only %d configured. "
|
305
|
+
"Please set 'max_connections: %d' in the 'esp32_ble' component. "
|
306
|
+
"Components: %s",
|
307
|
+
num_used,
|
308
|
+
max_connections,
|
309
|
+
num_used,
|
310
|
+
slot_users,
|
311
|
+
)
|
312
|
+
|
313
|
+
|
237
314
|
def final_validation(config):
|
238
315
|
validate_variant(config)
|
239
316
|
if (name := config.get(CONF_NAME)) is not None:
|
@@ -246,6 +323,43 @@ def final_validation(config):
|
|
246
323
|
f"Name '{name}' is too long, maximum length is {max_length} characters"
|
247
324
|
)
|
248
325
|
|
326
|
+
# Set GATT Client/Server sdkconfig options based on which components are loaded
|
327
|
+
full_config = fv.full_config.get()
|
328
|
+
|
329
|
+
# Validate connection slots usage
|
330
|
+
max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
|
331
|
+
validate_connection_slots(max_connections)
|
332
|
+
|
333
|
+
# Check if BLE Server is needed
|
334
|
+
has_ble_server = "esp32_ble_server" in full_config
|
335
|
+
add_idf_sdkconfig_option("CONFIG_BT_GATTS_ENABLE", has_ble_server)
|
336
|
+
|
337
|
+
# Check if BLE Client is needed (via esp32_ble_tracker or esp32_ble_client)
|
338
|
+
has_ble_client = (
|
339
|
+
"esp32_ble_tracker" in full_config or "esp32_ble_client" in full_config
|
340
|
+
)
|
341
|
+
add_idf_sdkconfig_option("CONFIG_BT_GATTC_ENABLE", has_ble_client)
|
342
|
+
|
343
|
+
# Handle max_connections: check for deprecated location in esp32_ble_tracker
|
344
|
+
max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
|
345
|
+
|
346
|
+
# Use value from tracker if esp32_ble doesn't have it explicitly set (backward compat)
|
347
|
+
if "esp32_ble_tracker" in full_config:
|
348
|
+
tracker_config = full_config["esp32_ble_tracker"]
|
349
|
+
if "max_connections" in tracker_config and CONF_MAX_CONNECTIONS not in config:
|
350
|
+
max_connections = tracker_config["max_connections"]
|
351
|
+
|
352
|
+
# Set CONFIG_BT_ACL_CONNECTIONS to the maximum connections needed + 1 for ADV/SCAN
|
353
|
+
# This is the Bluedroid host stack total instance limit (range 1-9, default 4)
|
354
|
+
# Total instances = ADV/SCAN (1) + connection slots (max_connections)
|
355
|
+
# Shared between client (tracker/ble_client) and server
|
356
|
+
add_idf_sdkconfig_option("CONFIG_BT_ACL_CONNECTIONS", max_connections + 1)
|
357
|
+
|
358
|
+
# Set controller-specific max connections for ESP32 (classic)
|
359
|
+
# CONFIG_BTDM_CTRL_BLE_MAX_CONN is ESP32-specific controller limit (just connections, not ADV/SCAN)
|
360
|
+
# For newer chips (C3/S3/etc), different configs are used automatically
|
361
|
+
add_idf_sdkconfig_option("CONFIG_BTDM_CTRL_BLE_MAX_CONN", max_connections)
|
362
|
+
|
249
363
|
return config
|
250
364
|
|
251
365
|
|
@@ -261,43 +375,44 @@ async def to_code(config):
|
|
261
375
|
cg.add(var.set_name(name))
|
262
376
|
await cg.register_component(var, config)
|
263
377
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
378
|
+
# Define max connections for use in C++ code (e.g., ble_server.h)
|
379
|
+
max_connections = config.get(CONF_MAX_CONNECTIONS, DEFAULT_MAX_CONNECTIONS)
|
380
|
+
cg.add_define("USE_ESP32_BLE_MAX_CONNECTIONS", max_connections)
|
381
|
+
|
382
|
+
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
383
|
+
add_idf_sdkconfig_option("CONFIG_BT_BLE_42_FEATURES_SUPPORTED", True)
|
384
|
+
|
385
|
+
# Register the core BLE loggers that are always needed
|
386
|
+
register_bt_logger(BTLoggers.GAP, BTLoggers.BTM, BTLoggers.HCI)
|
387
|
+
|
388
|
+
# Apply logger settings if log disabling is enabled
|
389
|
+
if config.get(CONF_DISABLE_BT_LOGS, False):
|
390
|
+
# Disable all Bluetooth loggers that are not required
|
391
|
+
for logger in BTLoggers:
|
392
|
+
if logger not in _required_loggers:
|
393
|
+
add_idf_sdkconfig_option(f"{logger.value}_NONE", True)
|
394
|
+
|
395
|
+
# Set BLE connection establishment timeout to match aioesphomeapi/bleak-retry-connector
|
396
|
+
# Default is 20 seconds instead of ESP-IDF's 30 seconds. Because there is no way to
|
397
|
+
# cancel a BLE connection in progress, when aioesphomeapi times out at 20 seconds,
|
398
|
+
# the connection slot remains occupied for the remaining time, preventing new connection
|
399
|
+
# attempts and wasting valuable connection slots.
|
400
|
+
if CONF_CONNECTION_TIMEOUT in config:
|
401
|
+
timeout_seconds = int(config[CONF_CONNECTION_TIMEOUT].total_seconds)
|
402
|
+
add_idf_sdkconfig_option("CONFIG_BT_BLE_ESTAB_LINK_CONN_TOUT", timeout_seconds)
|
403
|
+
# Increase GATT client connection retry count for problematic devices
|
404
|
+
# Default in ESP-IDF is 3, we increase to 10 for better reliability with
|
405
|
+
# low-power/timing-sensitive devices
|
406
|
+
add_idf_sdkconfig_option("CONFIG_BT_GATTC_CONNECT_RETRY_COUNT", 10)
|
407
|
+
|
408
|
+
# Set the maximum number of notification registrations
|
409
|
+
# This controls how many BLE characteristics can have notifications enabled
|
410
|
+
# across all connections for a single GATT client interface
|
411
|
+
# https://github.com/esphome/issues/issues/6808
|
412
|
+
if CONF_MAX_NOTIFICATIONS in config:
|
413
|
+
add_idf_sdkconfig_option(
|
414
|
+
"CONFIG_BT_GATTC_NOTIF_REG_MAX", config[CONF_MAX_NOTIFICATIONS]
|
415
|
+
)
|
301
416
|
|
302
417
|
cg.add_define("USE_ESP32_BLE")
|
303
418
|
|
@@ -73,6 +73,28 @@ void ESP32BLE::advertising_set_manufacturer_data(const std::vector<uint8_t> &dat
|
|
73
73
|
this->advertising_start();
|
74
74
|
}
|
75
75
|
|
76
|
+
void ESP32BLE::advertising_set_service_data_and_name(std::span<const uint8_t> data, bool include_name) {
|
77
|
+
// This method atomically updates both service data and device name inclusion in BLE advertising.
|
78
|
+
// When include_name is true, the device name is included in the advertising packet making it
|
79
|
+
// visible to passive BLE scanners. When false, the name is only visible in scan response
|
80
|
+
// (requires active scanning). This atomic operation ensures we only restart advertising once
|
81
|
+
// when changing both properties, avoiding the brief gap that would occur with separate calls.
|
82
|
+
|
83
|
+
this->advertising_init_();
|
84
|
+
|
85
|
+
if (include_name) {
|
86
|
+
// When including name, clear service data first to avoid packet overflow
|
87
|
+
this->advertising_->set_service_data(std::span<const uint8_t>{});
|
88
|
+
this->advertising_->set_include_name(true);
|
89
|
+
} else {
|
90
|
+
// When including service data, clear name first to avoid packet overflow
|
91
|
+
this->advertising_->set_include_name(false);
|
92
|
+
this->advertising_->set_service_data(data);
|
93
|
+
}
|
94
|
+
|
95
|
+
this->advertising_start();
|
96
|
+
}
|
97
|
+
|
76
98
|
void ESP32BLE::advertising_register_raw_advertisement_callback(std::function<void(bool)> &&callback) {
|
77
99
|
this->advertising_init_();
|
78
100
|
this->advertising_->register_raw_advertisement_callback(std::move(callback));
|
@@ -167,6 +189,7 @@ bool ESP32BLE::ble_setup_() {
|
|
167
189
|
}
|
168
190
|
}
|
169
191
|
|
192
|
+
#ifdef USE_ESP32_BLE_SERVER
|
170
193
|
if (!this->gatts_event_handlers_.empty()) {
|
171
194
|
err = esp_ble_gatts_register_callback(ESP32BLE::gatts_event_handler);
|
172
195
|
if (err != ESP_OK) {
|
@@ -174,7 +197,9 @@ bool ESP32BLE::ble_setup_() {
|
|
174
197
|
return false;
|
175
198
|
}
|
176
199
|
}
|
200
|
+
#endif
|
177
201
|
|
202
|
+
#ifdef USE_ESP32_BLE_CLIENT
|
178
203
|
if (!this->gattc_event_handlers_.empty()) {
|
179
204
|
err = esp_ble_gattc_register_callback(ESP32BLE::gattc_event_handler);
|
180
205
|
if (err != ESP_OK) {
|
@@ -182,20 +207,23 @@ bool ESP32BLE::ble_setup_() {
|
|
182
207
|
return false;
|
183
208
|
}
|
184
209
|
}
|
210
|
+
#endif
|
185
211
|
|
186
212
|
std::string name;
|
187
213
|
if (this->name_.has_value()) {
|
188
214
|
name = this->name_.value();
|
189
215
|
if (App.is_name_add_mac_suffix_enabled()) {
|
190
|
-
name += "-"
|
216
|
+
name += "-";
|
217
|
+
name += get_mac_address().substr(6);
|
191
218
|
}
|
192
219
|
} else {
|
193
220
|
name = App.get_name();
|
194
221
|
if (name.length() > 20) {
|
195
222
|
if (App.is_name_add_mac_suffix_enabled()) {
|
196
|
-
|
223
|
+
// Keep first 13 chars and last 7 chars (MAC suffix), remove middle
|
224
|
+
name.erase(13, name.length() - 20);
|
197
225
|
} else {
|
198
|
-
name
|
226
|
+
name.resize(20);
|
199
227
|
}
|
200
228
|
}
|
201
229
|
}
|
@@ -303,6 +331,7 @@ void ESP32BLE::loop() {
|
|
303
331
|
BLEEvent *ble_event = this->ble_events_.pop();
|
304
332
|
while (ble_event != nullptr) {
|
305
333
|
switch (ble_event->type_) {
|
334
|
+
#ifdef USE_ESP32_BLE_SERVER
|
306
335
|
case BLEEvent::GATTS: {
|
307
336
|
esp_gatts_cb_event_t event = ble_event->event_.gatts.gatts_event;
|
308
337
|
esp_gatt_if_t gatts_if = ble_event->event_.gatts.gatts_if;
|
@@ -313,6 +342,8 @@ void ESP32BLE::loop() {
|
|
313
342
|
}
|
314
343
|
break;
|
315
344
|
}
|
345
|
+
#endif
|
346
|
+
#ifdef USE_ESP32_BLE_CLIENT
|
316
347
|
case BLEEvent::GATTC: {
|
317
348
|
esp_gattc_cb_event_t event = ble_event->event_.gattc.gattc_event;
|
318
349
|
esp_gatt_if_t gattc_if = ble_event->event_.gattc.gattc_if;
|
@@ -323,6 +354,7 @@ void ESP32BLE::loop() {
|
|
323
354
|
}
|
324
355
|
break;
|
325
356
|
}
|
357
|
+
#endif
|
326
358
|
case BLEEvent::GAP: {
|
327
359
|
esp_gap_ble_cb_event_t gap_event = ble_event->event_.gap.gap_event;
|
328
360
|
switch (gap_event) {
|
@@ -416,13 +448,17 @@ void load_ble_event(BLEEvent *event, esp_gap_ble_cb_event_t e, esp_ble_gap_cb_pa
|
|
416
448
|
event->load_gap_event(e, p);
|
417
449
|
}
|
418
450
|
|
451
|
+
#ifdef USE_ESP32_BLE_CLIENT
|
419
452
|
void load_ble_event(BLEEvent *event, esp_gattc_cb_event_t e, esp_gatt_if_t i, esp_ble_gattc_cb_param_t *p) {
|
420
453
|
event->load_gattc_event(e, i, p);
|
421
454
|
}
|
455
|
+
#endif
|
422
456
|
|
457
|
+
#ifdef USE_ESP32_BLE_SERVER
|
423
458
|
void load_ble_event(BLEEvent *event, esp_gatts_cb_event_t e, esp_gatt_if_t i, esp_ble_gatts_cb_param_t *p) {
|
424
459
|
event->load_gatts_event(e, i, p);
|
425
460
|
}
|
461
|
+
#endif
|
426
462
|
|
427
463
|
template<typename... Args> void enqueue_ble_event(Args... args) {
|
428
464
|
// Allocate an event from the pool
|
@@ -443,8 +479,12 @@ template<typename... Args> void enqueue_ble_event(Args... args) {
|
|
443
479
|
|
444
480
|
// Explicit template instantiations for the friend function
|
445
481
|
template void enqueue_ble_event(esp_gap_ble_cb_event_t, esp_ble_gap_cb_param_t *);
|
482
|
+
#ifdef USE_ESP32_BLE_SERVER
|
446
483
|
template void enqueue_ble_event(esp_gatts_cb_event_t, esp_gatt_if_t, esp_ble_gatts_cb_param_t *);
|
484
|
+
#endif
|
485
|
+
#ifdef USE_ESP32_BLE_CLIENT
|
447
486
|
template void enqueue_ble_event(esp_gattc_cb_event_t, esp_gatt_if_t, esp_ble_gattc_cb_param_t *);
|
487
|
+
#endif
|
448
488
|
|
449
489
|
void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
|
450
490
|
switch (event) {
|
@@ -484,15 +524,19 @@ void ESP32BLE::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_pa
|
|
484
524
|
ESP_LOGW(TAG, "Ignoring unexpected GAP event type: %d", event);
|
485
525
|
}
|
486
526
|
|
527
|
+
#ifdef USE_ESP32_BLE_SERVER
|
487
528
|
void ESP32BLE::gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if,
|
488
529
|
esp_ble_gatts_cb_param_t *param) {
|
489
530
|
enqueue_ble_event(event, gatts_if, param);
|
490
531
|
}
|
532
|
+
#endif
|
491
533
|
|
534
|
+
#ifdef USE_ESP32_BLE_CLIENT
|
492
535
|
void ESP32BLE::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,
|
493
536
|
esp_ble_gattc_cb_param_t *param) {
|
494
537
|
enqueue_ble_event(event, gattc_if, param);
|
495
538
|
}
|
539
|
+
#endif
|
496
540
|
|
497
541
|
float ESP32BLE::get_setup_priority() const { return setup_priority::BLUETOOTH; }
|
498
542
|
|