esphome 2025.9.3__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 +166 -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 +68 -10
- 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/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 -2
- 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.3.dist-info → esphome-2025.10.0b1.dist-info}/METADATA +11 -11
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/RECORD +332 -312
- 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.3.dist-info → esphome-2025.10.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b1.dist-info}/top_level.txt +0 -0
@@ -1,14 +1,13 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from collections.abc import Callable, MutableMapping
|
4
3
|
import logging
|
5
|
-
from typing import Any
|
6
4
|
|
7
5
|
from esphome import automation
|
8
6
|
import esphome.codegen as cg
|
9
7
|
from esphome.components import esp32_ble
|
10
8
|
from esphome.components.esp32 import add_idf_sdkconfig_option
|
11
9
|
from esphome.components.esp32_ble import (
|
10
|
+
IDF_MAX_CONNECTIONS,
|
12
11
|
BTLoggers,
|
13
12
|
bt_uuid,
|
14
13
|
bt_uuid16_format,
|
@@ -24,6 +23,7 @@ from esphome.const import (
|
|
24
23
|
CONF_INTERVAL,
|
25
24
|
CONF_MAC_ADDRESS,
|
26
25
|
CONF_MANUFACTURER_ID,
|
26
|
+
CONF_MAX_CONNECTIONS,
|
27
27
|
CONF_ON_BLE_ADVERTISE,
|
28
28
|
CONF_ON_BLE_MANUFACTURER_DATA_ADVERTISE,
|
29
29
|
CONF_ON_BLE_SERVICE_DATA_ADVERTISE,
|
@@ -38,19 +38,12 @@ AUTO_LOAD = ["esp32_ble"]
|
|
38
38
|
DEPENDENCIES = ["esp32"]
|
39
39
|
CODEOWNERS = ["@bdraco"]
|
40
40
|
|
41
|
-
KEY_ESP32_BLE_TRACKER = "esp32_ble_tracker"
|
42
|
-
KEY_USED_CONNECTION_SLOTS = "used_connection_slots"
|
43
|
-
|
44
|
-
CONF_MAX_CONNECTIONS = "max_connections"
|
45
41
|
CONF_ESP32_BLE_ID = "esp32_ble_id"
|
46
42
|
CONF_SCAN_PARAMETERS = "scan_parameters"
|
47
43
|
CONF_WINDOW = "window"
|
48
44
|
CONF_ON_SCAN_END = "on_scan_end"
|
49
45
|
CONF_SOFTWARE_COEXISTENCE = "software_coexistence"
|
50
46
|
|
51
|
-
DEFAULT_MAX_CONNECTIONS = 3
|
52
|
-
IDF_MAX_CONNECTIONS = 9
|
53
|
-
|
54
47
|
_LOGGER = logging.getLogger(__name__)
|
55
48
|
|
56
49
|
|
@@ -128,6 +121,15 @@ def validate_scan_parameters(config):
|
|
128
121
|
return config
|
129
122
|
|
130
123
|
|
124
|
+
def validate_max_connections_deprecated(config: ConfigType) -> ConfigType:
|
125
|
+
if CONF_MAX_CONNECTIONS in config:
|
126
|
+
_LOGGER.warning(
|
127
|
+
"The 'max_connections' option in 'esp32_ble_tracker' is deprecated. "
|
128
|
+
"Please move it to the 'esp32_ble' component instead."
|
129
|
+
)
|
130
|
+
return config
|
131
|
+
|
132
|
+
|
131
133
|
def as_hex(value):
|
132
134
|
return cg.RawExpression(f"0x{value}ULL")
|
133
135
|
|
@@ -150,29 +152,13 @@ def as_reversed_hex_array(value):
|
|
150
152
|
)
|
151
153
|
|
152
154
|
|
153
|
-
def max_connections() -> int:
|
154
|
-
return IDF_MAX_CONNECTIONS if CORE.using_esp_idf else DEFAULT_MAX_CONNECTIONS
|
155
|
-
|
156
|
-
|
157
|
-
def consume_connection_slots(
|
158
|
-
value: int, consumer: str
|
159
|
-
) -> Callable[[MutableMapping], MutableMapping]:
|
160
|
-
def _consume_connection_slots(config: MutableMapping) -> MutableMapping:
|
161
|
-
data: dict[str, Any] = CORE.data.setdefault(KEY_ESP32_BLE_TRACKER, {})
|
162
|
-
slots: list[str] = data.setdefault(KEY_USED_CONNECTION_SLOTS, [])
|
163
|
-
slots.extend([consumer] * value)
|
164
|
-
return config
|
165
|
-
|
166
|
-
return _consume_connection_slots
|
167
|
-
|
168
|
-
|
169
155
|
CONFIG_SCHEMA = cv.All(
|
170
156
|
cv.Schema(
|
171
157
|
{
|
172
158
|
cv.GenerateID(): cv.declare_id(ESP32BLETracker),
|
173
159
|
cv.GenerateID(esp32_ble.CONF_BLE_ID): cv.use_id(esp32_ble.ESP32BLE),
|
174
|
-
cv.Optional(CONF_MAX_CONNECTIONS
|
175
|
-
cv.positive_int, cv.Range(min=0, max=
|
160
|
+
cv.Optional(CONF_MAX_CONNECTIONS): cv.All(
|
161
|
+
cv.positive_int, cv.Range(min=0, max=IDF_MAX_CONNECTIONS)
|
176
162
|
),
|
177
163
|
cv.Optional(CONF_SCAN_PARAMETERS, default={}): cv.All(
|
178
164
|
cv.Schema(
|
@@ -228,49 +214,11 @@ CONFIG_SCHEMA = cv.All(
|
|
228
214
|
cv.OnlyWith(CONF_SOFTWARE_COEXISTENCE, "wifi", default=True): bool,
|
229
215
|
}
|
230
216
|
).extend(cv.COMPONENT_SCHEMA),
|
217
|
+
validate_max_connections_deprecated,
|
231
218
|
)
|
232
219
|
|
233
220
|
|
234
|
-
|
235
|
-
data: dict[str, Any] = CORE.data.get(KEY_ESP32_BLE_TRACKER, {})
|
236
|
-
slots: list[str] = data.get(KEY_USED_CONNECTION_SLOTS, [])
|
237
|
-
used_slots = len(slots)
|
238
|
-
if used_slots <= config[CONF_MAX_CONNECTIONS]:
|
239
|
-
return config
|
240
|
-
slot_users = ", ".join(slots)
|
241
|
-
hard_limit = max_connections()
|
242
|
-
|
243
|
-
if used_slots < hard_limit:
|
244
|
-
_LOGGER.warning(
|
245
|
-
"esp32_ble_tracker exceeded `%s`: components attempted to consume %d "
|
246
|
-
"connection slot(s) out of available configured maximum %d connection "
|
247
|
-
"slot(s); The system automatically increased `%s` to %d to match the "
|
248
|
-
"number of used connection slot(s) by components: %s.",
|
249
|
-
CONF_MAX_CONNECTIONS,
|
250
|
-
used_slots,
|
251
|
-
config[CONF_MAX_CONNECTIONS],
|
252
|
-
CONF_MAX_CONNECTIONS,
|
253
|
-
used_slots,
|
254
|
-
slot_users,
|
255
|
-
)
|
256
|
-
config[CONF_MAX_CONNECTIONS] = used_slots
|
257
|
-
return config
|
258
|
-
|
259
|
-
msg = (
|
260
|
-
f"esp32_ble_tracker exceeded `{CONF_MAX_CONNECTIONS}`: "
|
261
|
-
f"components attempted to consume {used_slots} connection slot(s) "
|
262
|
-
f"out of available configured maximum {config[CONF_MAX_CONNECTIONS]} "
|
263
|
-
f"connection slot(s); Decrease the number of BLE clients ({slot_users})"
|
264
|
-
)
|
265
|
-
if config[CONF_MAX_CONNECTIONS] < hard_limit:
|
266
|
-
msg += f" or increase {CONF_MAX_CONNECTIONS}` to {used_slots}"
|
267
|
-
msg += f" to stay under the {hard_limit} connection slot(s) limit."
|
268
|
-
raise cv.Invalid(msg)
|
269
|
-
|
270
|
-
|
271
|
-
FINAL_VALIDATE_SCHEMA = cv.All(
|
272
|
-
validate_remaining_connections, esp32_ble.validate_variant
|
273
|
-
)
|
221
|
+
FINAL_VALIDATE_SCHEMA = esp32_ble.validate_variant
|
274
222
|
|
275
223
|
ESP_BLE_DEVICE_SCHEMA = cv.Schema(
|
276
224
|
{
|
@@ -342,19 +290,16 @@ async def to_code(config):
|
|
342
290
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
343
291
|
await automation.build_automation(trigger, [], conf)
|
344
292
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
add_idf_sdkconfig_option(
|
356
|
-
"CONFIG_BTDM_CTRL_BLE_MAX_CONN", config[CONF_MAX_CONNECTIONS]
|
357
|
-
)
|
293
|
+
add_idf_sdkconfig_option("CONFIG_BT_ENABLED", True)
|
294
|
+
if config.get(CONF_SOFTWARE_COEXISTENCE):
|
295
|
+
add_idf_sdkconfig_option("CONFIG_SW_COEXIST_ENABLE", True)
|
296
|
+
# https://github.com/espressif/esp-idf/issues/4101
|
297
|
+
# https://github.com/espressif/esp-idf/issues/2503
|
298
|
+
# Match arduino CONFIG_BTU_TASK_STACK_SIZE
|
299
|
+
# https://github.com/espressif/arduino-esp32/blob/fd72cf46ad6fc1a6de99c1d83ba8eba17d80a4ee/tools/sdk/esp32/sdkconfig#L1866
|
300
|
+
add_idf_sdkconfig_option("CONFIG_BT_BTU_TASK_STACK_SIZE", 8192)
|
301
|
+
# Note: CONFIG_BT_ACL_CONNECTIONS and CONFIG_BTDM_CTRL_BLE_MAX_CONN are now
|
302
|
+
# configured in esp32_ble component based on max_connections setting
|
358
303
|
|
359
304
|
cg.add_define("USE_OTA_STATE_CALLBACK") # To be notified when an OTA update starts
|
360
305
|
cg.add_define("USE_ESP32_BLE_CLIENT")
|
@@ -51,8 +51,6 @@ const char *client_state_to_string(ClientState state) {
|
|
51
51
|
return "IDLE";
|
52
52
|
case ClientState::DISCOVERED:
|
53
53
|
return "DISCOVERED";
|
54
|
-
case ClientState::READY_TO_CONNECT:
|
55
|
-
return "READY_TO_CONNECT";
|
56
54
|
case ClientState::CONNECTING:
|
57
55
|
return "CONNECTING";
|
58
56
|
case ClientState::CONNECTED:
|
@@ -297,7 +295,7 @@ void ESP32BLETracker::gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_ga
|
|
297
295
|
void ESP32BLETracker::gap_scan_event_handler(const BLEScanResult &scan_result) {
|
298
296
|
// Note: This handler is called from the main loop context via esp32_ble's event queue.
|
299
297
|
// We process advertisements immediately instead of buffering them.
|
300
|
-
|
298
|
+
ESP_LOGVV(TAG, "gap_scan_result - event %d", scan_result.search_evt);
|
301
299
|
|
302
300
|
if (scan_result.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {
|
303
301
|
// Process the scan result immediately
|
@@ -794,7 +792,7 @@ void ESP32BLETracker::try_promote_discovered_clients_() {
|
|
794
792
|
#ifdef USE_ESP32_BLE_SOFTWARE_COEXISTENCE
|
795
793
|
this->update_coex_preference_(true);
|
796
794
|
#endif
|
797
|
-
client->
|
795
|
+
client->connect();
|
798
796
|
break;
|
799
797
|
}
|
800
798
|
}
|
@@ -159,8 +159,6 @@ enum class ClientState : uint8_t {
|
|
159
159
|
IDLE,
|
160
160
|
// Device advertisement found.
|
161
161
|
DISCOVERED,
|
162
|
-
// Device is discovered and the scanner is stopped
|
163
|
-
READY_TO_CONNECT,
|
164
162
|
// Connection in progress.
|
165
163
|
CONNECTING,
|
166
164
|
// Initial connection established.
|
@@ -313,7 +311,6 @@ class ESP32BLETracker : public Component,
|
|
313
311
|
counts.discovered++;
|
314
312
|
break;
|
315
313
|
case ClientState::CONNECTING:
|
316
|
-
case ClientState::READY_TO_CONNECT:
|
317
314
|
counts.connecting++;
|
318
315
|
break;
|
319
316
|
default:
|
@@ -21,7 +21,6 @@ from esphome.const import (
|
|
21
21
|
CONF_TRIGGER_ID,
|
22
22
|
CONF_VSYNC_PIN,
|
23
23
|
)
|
24
|
-
from esphome.core import CORE
|
25
24
|
from esphome.core.entity_helpers import setup_entity
|
26
25
|
import esphome.final_validate as fv
|
27
26
|
|
@@ -344,8 +343,7 @@ async def to_code(config):
|
|
344
343
|
|
345
344
|
cg.add_define("USE_CAMERA")
|
346
345
|
|
347
|
-
|
348
|
-
add_idf_component(name="espressif/esp32-camera", ref="2.1.1")
|
346
|
+
add_idf_component(name="espressif/esp32-camera", ref="2.1.1")
|
349
347
|
|
350
348
|
for conf in config.get(CONF_ON_STREAM_START, []):
|
351
349
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
@@ -67,8 +67,16 @@ static bool get_bitrate(canbus::CanSpeed bitrate, twai_timing_config_t *t_config
|
|
67
67
|
}
|
68
68
|
|
69
69
|
bool ESP32Can::setup_internal() {
|
70
|
+
static int next_twai_ctrl_num = 0;
|
71
|
+
if (static_cast<unsigned>(next_twai_ctrl_num) >= SOC_TWAI_CONTROLLER_NUM) {
|
72
|
+
ESP_LOGW(TAG, "Maximum number of esp32_can components created already");
|
73
|
+
this->mark_failed();
|
74
|
+
return false;
|
75
|
+
}
|
76
|
+
|
70
77
|
twai_general_config_t g_config =
|
71
78
|
TWAI_GENERAL_CONFIG_DEFAULT((gpio_num_t) this->tx_, (gpio_num_t) this->rx_, TWAI_MODE_NORMAL);
|
79
|
+
g_config.controller_id = next_twai_ctrl_num++;
|
72
80
|
if (this->tx_queue_len_.has_value()) {
|
73
81
|
g_config.tx_queue_len = this->tx_queue_len_.value();
|
74
82
|
}
|
@@ -86,14 +94,14 @@ bool ESP32Can::setup_internal() {
|
|
86
94
|
}
|
87
95
|
|
88
96
|
// Install TWAI driver
|
89
|
-
if (
|
97
|
+
if (twai_driver_install_v2(&g_config, &t_config, &f_config, &(this->twai_handle_)) != ESP_OK) {
|
90
98
|
// Failed to install driver
|
91
99
|
this->mark_failed();
|
92
100
|
return false;
|
93
101
|
}
|
94
102
|
|
95
103
|
// Start TWAI driver
|
96
|
-
if (
|
104
|
+
if (twai_start_v2(this->twai_handle_) != ESP_OK) {
|
97
105
|
// Failed to start driver
|
98
106
|
this->mark_failed();
|
99
107
|
return false;
|
@@ -102,6 +110,11 @@ bool ESP32Can::setup_internal() {
|
|
102
110
|
}
|
103
111
|
|
104
112
|
canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
|
113
|
+
if (this->twai_handle_ == nullptr) {
|
114
|
+
// not setup yet or setup failed
|
115
|
+
return canbus::ERROR_FAIL;
|
116
|
+
}
|
117
|
+
|
105
118
|
if (frame->can_data_length_code > canbus::CAN_MAX_DATA_LENGTH) {
|
106
119
|
return canbus::ERROR_FAILTX;
|
107
120
|
}
|
@@ -124,7 +137,7 @@ canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
|
|
124
137
|
memcpy(message.data, frame->data, frame->can_data_length_code);
|
125
138
|
}
|
126
139
|
|
127
|
-
if (
|
140
|
+
if (twai_transmit_v2(this->twai_handle_, &message, this->tx_enqueue_timeout_ticks_) == ESP_OK) {
|
128
141
|
return canbus::ERROR_OK;
|
129
142
|
} else {
|
130
143
|
return canbus::ERROR_ALLTXBUSY;
|
@@ -132,9 +145,14 @@ canbus::Error ESP32Can::send_message(struct canbus::CanFrame *frame) {
|
|
132
145
|
}
|
133
146
|
|
134
147
|
canbus::Error ESP32Can::read_message(struct canbus::CanFrame *frame) {
|
148
|
+
if (this->twai_handle_ == nullptr) {
|
149
|
+
// not setup yet or setup failed
|
150
|
+
return canbus::ERROR_FAIL;
|
151
|
+
}
|
152
|
+
|
135
153
|
twai_message_t message;
|
136
154
|
|
137
|
-
if (
|
155
|
+
if (twai_receive_v2(this->twai_handle_, &message, 0) != ESP_OK) {
|
138
156
|
return canbus::ERROR_NOMSG;
|
139
157
|
}
|
140
158
|
|
@@ -5,6 +5,8 @@
|
|
5
5
|
#include "esphome/components/canbus/canbus.h"
|
6
6
|
#include "esphome/core/component.h"
|
7
7
|
|
8
|
+
#include <driver/twai.h>
|
9
|
+
|
8
10
|
namespace esphome {
|
9
11
|
namespace esp32_can {
|
10
12
|
|
@@ -29,6 +31,7 @@ class ESP32Can : public canbus::Canbus {
|
|
29
31
|
TickType_t tx_enqueue_timeout_ticks_{};
|
30
32
|
optional<uint32_t> tx_queue_len_{};
|
31
33
|
optional<uint32_t> rx_queue_len_{};
|
34
|
+
twai_handle_t twai_handle_{nullptr};
|
32
35
|
};
|
33
36
|
|
34
37
|
} // namespace esp32_can
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import os
|
2
|
+
from pathlib import Path
|
2
3
|
|
3
4
|
from esphome import pins
|
4
5
|
from esphome.components import esp32
|
@@ -97,5 +98,5 @@ async def to_code(config):
|
|
97
98
|
esp32.add_extra_script(
|
98
99
|
"post",
|
99
100
|
"esp32_hosted.py",
|
100
|
-
|
101
|
+
Path(__file__).parent / "esp32_hosted.py.script",
|
101
102
|
)
|
@@ -17,6 +17,13 @@ static const char *const TAG = "esp32_improv.component";
|
|
17
17
|
static const char *const ESPHOME_MY_LINK = "https://my.home-assistant.io/redirect/config_flow_start?domain=esphome";
|
18
18
|
static constexpr uint16_t STOP_ADVERTISING_DELAY =
|
19
19
|
10000; // Delay (ms) before stopping service to allow BLE clients to read the final state
|
20
|
+
static constexpr uint16_t NAME_ADVERTISING_INTERVAL = 60000; // Advertise name every 60 seconds
|
21
|
+
static constexpr uint16_t NAME_ADVERTISING_DURATION = 1000; // Advertise name for 1 second
|
22
|
+
|
23
|
+
// Improv service data constants
|
24
|
+
static constexpr uint8_t IMPROV_SERVICE_DATA_SIZE = 8;
|
25
|
+
static constexpr uint8_t IMPROV_PROTOCOL_ID_1 = 0x77; // 'P' << 1 | 'R' >> 7
|
26
|
+
static constexpr uint8_t IMPROV_PROTOCOL_ID_2 = 0x46; // 'I' << 1 | 'M' >> 7
|
20
27
|
|
21
28
|
ESP32ImprovComponent::ESP32ImprovComponent() { global_improv_component = this; }
|
22
29
|
|
@@ -31,8 +38,7 @@ void ESP32ImprovComponent::setup() {
|
|
31
38
|
});
|
32
39
|
}
|
33
40
|
#endif
|
34
|
-
global_ble_server->
|
35
|
-
[this](uint16_t conn_id) { this->set_error_(improv::ERROR_NONE); });
|
41
|
+
global_ble_server->on_disconnect([this](uint16_t conn_id) { this->set_error_(improv::ERROR_NONE); });
|
36
42
|
|
37
43
|
// Start with loop disabled - will be enabled by start() when needed
|
38
44
|
this->disable_loop();
|
@@ -50,12 +56,11 @@ void ESP32ImprovComponent::setup_characteristics() {
|
|
50
56
|
this->error_->add_descriptor(error_descriptor);
|
51
57
|
|
52
58
|
this->rpc_ = this->service_->create_characteristic(improv::RPC_COMMAND_UUID, BLECharacteristic::PROPERTY_WRITE);
|
53
|
-
this->rpc_->
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
});
|
59
|
+
this->rpc_->on_write([this](std::span<const uint8_t> data, uint16_t id) {
|
60
|
+
if (!data.empty()) {
|
61
|
+
this->incoming_data_.insert(this->incoming_data_.end(), data.begin(), data.end());
|
62
|
+
}
|
63
|
+
});
|
59
64
|
BLEDescriptor *rpc_descriptor = new BLE2902();
|
60
65
|
this->rpc_->add_descriptor(rpc_descriptor);
|
61
66
|
|
@@ -99,6 +104,11 @@ void ESP32ImprovComponent::loop() {
|
|
99
104
|
this->process_incoming_data_();
|
100
105
|
uint32_t now = App.get_loop_component_start_time();
|
101
106
|
|
107
|
+
// Check if we need to update advertising type
|
108
|
+
if (this->state_ != improv::STATE_STOPPED && this->state_ != improv::STATE_PROVISIONED) {
|
109
|
+
this->update_advertising_type_();
|
110
|
+
}
|
111
|
+
|
102
112
|
switch (this->state_) {
|
103
113
|
case improv::STATE_STOPPED:
|
104
114
|
this->set_status_indicator_state_(false);
|
@@ -107,9 +117,15 @@ void ESP32ImprovComponent::loop() {
|
|
107
117
|
if (this->service_->is_created()) {
|
108
118
|
this->service_->start();
|
109
119
|
} else if (this->service_->is_running()) {
|
120
|
+
// Start by advertising the device name first BEFORE setting any state
|
121
|
+
ESP_LOGV(TAG, "Starting with device name advertising");
|
122
|
+
this->advertising_device_name_ = true;
|
123
|
+
this->last_name_adv_time_ = App.get_loop_component_start_time();
|
124
|
+
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>{}, true);
|
110
125
|
esp32_ble::global_ble->advertising_start();
|
111
126
|
|
112
|
-
|
127
|
+
// Set initial state based on whether we have an authorizer
|
128
|
+
this->set_state_(this->get_initial_state_(), false);
|
113
129
|
this->set_error_(improv::ERROR_NONE);
|
114
130
|
ESP_LOGD(TAG, "Service started!");
|
115
131
|
}
|
@@ -120,24 +136,21 @@ void ESP32ImprovComponent::loop() {
|
|
120
136
|
if (this->authorizer_ == nullptr ||
|
121
137
|
(this->authorized_start_ != 0 && ((now - this->authorized_start_) < this->authorized_duration_))) {
|
122
138
|
this->set_state_(improv::STATE_AUTHORIZED);
|
123
|
-
} else
|
124
|
-
#else
|
125
|
-
{ this->set_state_(improv::STATE_AUTHORIZED); }
|
126
|
-
#endif
|
127
|
-
{
|
139
|
+
} else {
|
128
140
|
if (!this->check_identify_())
|
129
141
|
this->set_status_indicator_state_(true);
|
130
142
|
}
|
143
|
+
#else
|
144
|
+
this->set_state_(improv::STATE_AUTHORIZED);
|
145
|
+
#endif
|
131
146
|
break;
|
132
147
|
}
|
133
148
|
case improv::STATE_AUTHORIZED: {
|
134
149
|
#ifdef USE_BINARY_SENSOR
|
135
|
-
if (this->authorizer_ != nullptr) {
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
return;
|
140
|
-
}
|
150
|
+
if (this->authorizer_ != nullptr && now - this->authorized_start_ > this->authorized_duration_) {
|
151
|
+
ESP_LOGD(TAG, "Authorization timeout");
|
152
|
+
this->set_state_(improv::STATE_AWAITING_AUTHORIZATION);
|
153
|
+
return;
|
141
154
|
}
|
142
155
|
#endif
|
143
156
|
if (!this->check_identify_()) {
|
@@ -226,12 +239,15 @@ bool ESP32ImprovComponent::check_identify_() {
|
|
226
239
|
return identify;
|
227
240
|
}
|
228
241
|
|
229
|
-
void ESP32ImprovComponent::set_state_(improv::State state) {
|
230
|
-
|
231
|
-
if (this->state_
|
232
|
-
|
233
|
-
this->state_to_string_(state), state);
|
242
|
+
void ESP32ImprovComponent::set_state_(improv::State state, bool update_advertising) {
|
243
|
+
// Skip if state hasn't changed
|
244
|
+
if (this->state_ == state) {
|
245
|
+
return;
|
234
246
|
}
|
247
|
+
|
248
|
+
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
249
|
+
ESP_LOGD(TAG, "State transition: %s (0x%02X) -> %s (0x%02X)", this->state_to_string_(this->state_), this->state_,
|
250
|
+
this->state_to_string_(state), state);
|
235
251
|
#endif
|
236
252
|
this->state_ = state;
|
237
253
|
if (this->status_ != nullptr && (this->status_->get_value().empty() || this->status_->get_value()[0] != state)) {
|
@@ -243,25 +259,13 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
|
|
243
259
|
// STATE_STOPPED (0x00) is internal only and not part of the Improv spec.
|
244
260
|
// Advertising 0x00 causes undefined behavior in some clients and makes them
|
245
261
|
// repeatedly connect trying to determine the actual state.
|
246
|
-
if (state != improv::STATE_STOPPED) {
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
#ifdef USE_OUTPUT
|
254
|
-
if (this->status_indicator_ != nullptr)
|
255
|
-
capabilities |= improv::CAPABILITY_IDENTIFY;
|
256
|
-
#endif
|
257
|
-
|
258
|
-
service_data[3] = capabilities;
|
259
|
-
service_data[4] = 0x00; // Reserved
|
260
|
-
service_data[5] = 0x00; // Reserved
|
261
|
-
service_data[6] = 0x00; // Reserved
|
262
|
-
service_data[7] = 0x00; // Reserved
|
263
|
-
|
264
|
-
esp32_ble::global_ble->advertising_set_service_data(service_data);
|
262
|
+
if (state != improv::STATE_STOPPED && update_advertising) {
|
263
|
+
// State change always overrides name advertising and resets the timer
|
264
|
+
this->advertising_device_name_ = false;
|
265
|
+
// Reset the timer so we wait another 60 seconds before advertising name
|
266
|
+
this->last_name_adv_time_ = App.get_loop_component_start_time();
|
267
|
+
// Advertise the new state via service data
|
268
|
+
this->advertise_service_data_();
|
265
269
|
}
|
266
270
|
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
|
267
271
|
this->state_callback_.call(this->state_, this->error_state_);
|
@@ -388,6 +392,60 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() {
|
|
388
392
|
wifi::global_wifi_component->clear_sta();
|
389
393
|
}
|
390
394
|
|
395
|
+
void ESP32ImprovComponent::advertise_service_data_() {
|
396
|
+
uint8_t service_data[IMPROV_SERVICE_DATA_SIZE] = {};
|
397
|
+
service_data[0] = IMPROV_PROTOCOL_ID_1; // PR
|
398
|
+
service_data[1] = IMPROV_PROTOCOL_ID_2; // IM
|
399
|
+
service_data[2] = static_cast<uint8_t>(this->state_);
|
400
|
+
|
401
|
+
uint8_t capabilities = 0x00;
|
402
|
+
#ifdef USE_OUTPUT
|
403
|
+
if (this->status_indicator_ != nullptr)
|
404
|
+
capabilities |= improv::CAPABILITY_IDENTIFY;
|
405
|
+
#endif
|
406
|
+
|
407
|
+
service_data[3] = capabilities;
|
408
|
+
// service_data[4-7] are already 0 (Reserved)
|
409
|
+
|
410
|
+
// Atomically set service data and disable name in advertising
|
411
|
+
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>(service_data), false);
|
412
|
+
}
|
413
|
+
|
414
|
+
void ESP32ImprovComponent::update_advertising_type_() {
|
415
|
+
uint32_t now = App.get_loop_component_start_time();
|
416
|
+
|
417
|
+
// If we're advertising the device name and it's been more than NAME_ADVERTISING_DURATION, switch back to service data
|
418
|
+
if (this->advertising_device_name_) {
|
419
|
+
if (now - this->last_name_adv_time_ >= NAME_ADVERTISING_DURATION) {
|
420
|
+
ESP_LOGV(TAG, "Switching back to service data advertising");
|
421
|
+
this->advertising_device_name_ = false;
|
422
|
+
// Restore service data advertising
|
423
|
+
this->advertise_service_data_();
|
424
|
+
}
|
425
|
+
return;
|
426
|
+
}
|
427
|
+
|
428
|
+
// Check if it's time to advertise the device name (every NAME_ADVERTISING_INTERVAL)
|
429
|
+
if (now - this->last_name_adv_time_ >= NAME_ADVERTISING_INTERVAL) {
|
430
|
+
ESP_LOGV(TAG, "Switching to device name advertising");
|
431
|
+
this->advertising_device_name_ = true;
|
432
|
+
this->last_name_adv_time_ = now;
|
433
|
+
|
434
|
+
// Atomically clear service data and enable name in advertising data
|
435
|
+
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>{}, true);
|
436
|
+
}
|
437
|
+
}
|
438
|
+
|
439
|
+
improv::State ESP32ImprovComponent::get_initial_state_() const {
|
440
|
+
#ifdef USE_BINARY_SENSOR
|
441
|
+
// If we have an authorizer, start in awaiting authorization state
|
442
|
+
return this->authorizer_ == nullptr ? improv::STATE_AUTHORIZED : improv::STATE_AWAITING_AUTHORIZATION;
|
443
|
+
#else
|
444
|
+
// No binary_sensor support = no authorizer possible, start as authorized
|
445
|
+
return improv::STATE_AUTHORIZED;
|
446
|
+
#endif
|
447
|
+
}
|
448
|
+
|
391
449
|
ESP32ImprovComponent *global_improv_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
392
450
|
|
393
451
|
} // namespace esp32_improv
|
@@ -100,14 +100,19 @@ class ESP32ImprovComponent : public Component {
|
|
100
100
|
#endif
|
101
101
|
|
102
102
|
bool status_indicator_state_{false};
|
103
|
+
uint32_t last_name_adv_time_{0};
|
104
|
+
bool advertising_device_name_{false};
|
103
105
|
void set_status_indicator_state_(bool state);
|
106
|
+
void update_advertising_type_();
|
104
107
|
|
105
|
-
void set_state_(improv::State state);
|
108
|
+
void set_state_(improv::State state, bool update_advertising = true);
|
106
109
|
void set_error_(improv::Error error);
|
110
|
+
improv::State get_initial_state_() const;
|
107
111
|
void send_response_(std::vector<uint8_t> &response);
|
108
112
|
void process_incoming_data_();
|
109
113
|
void on_wifi_connect_timeout_();
|
110
114
|
bool check_identify_();
|
115
|
+
void advertise_service_data_();
|
111
116
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
112
117
|
const char *state_to_string_(improv::State state);
|
113
118
|
#endif
|
@@ -35,7 +35,7 @@ static size_t IRAM_ATTR HOT encoder_callback(const void *data, size_t size, size
|
|
35
35
|
if (symbols_free < RMT_SYMBOLS_PER_BYTE) {
|
36
36
|
return 0;
|
37
37
|
}
|
38
|
-
for (
|
38
|
+
for (size_t i = 0; i < RMT_SYMBOLS_PER_BYTE; i++) {
|
39
39
|
if (bytes[index] & (1 << (7 - i))) {
|
40
40
|
symbols[i] = params->bit1;
|
41
41
|
} else {
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import logging
|
2
|
-
import
|
2
|
+
from pathlib import Path
|
3
3
|
|
4
4
|
import esphome.codegen as cg
|
5
5
|
import esphome.config_validation as cv
|
@@ -259,8 +259,8 @@ async def to_code(config):
|
|
259
259
|
|
260
260
|
# Called by writer.py
|
261
261
|
def copy_files():
|
262
|
-
dir =
|
263
|
-
post_build_file =
|
262
|
+
dir = Path(__file__).parent
|
263
|
+
post_build_file = dir / "post_build.py.script"
|
264
264
|
copy_file_if_changed(
|
265
265
|
post_build_file,
|
266
266
|
CORE.relative_build_path("post_build.py"),
|
@@ -16,7 +16,7 @@ from esphome.const import (
|
|
16
16
|
CONF_SAFE_MODE,
|
17
17
|
CONF_VERSION,
|
18
18
|
)
|
19
|
-
from esphome.core import coroutine_with_priority
|
19
|
+
from esphome.core import CORE, coroutine_with_priority
|
20
20
|
from esphome.coroutine import CoroPriority
|
21
21
|
import esphome.final_validate as fv
|
22
22
|
|
@@ -24,9 +24,22 @@ _LOGGER = logging.getLogger(__name__)
|
|
24
24
|
|
25
25
|
|
26
26
|
CODEOWNERS = ["@esphome/core"]
|
27
|
-
AUTO_LOAD = ["md5", "socket"]
|
28
27
|
DEPENDENCIES = ["network"]
|
29
28
|
|
29
|
+
|
30
|
+
def supports_sha256() -> bool:
|
31
|
+
"""Check if the current platform supports SHA256 for OTA authentication."""
|
32
|
+
return bool(CORE.is_esp32 or CORE.is_esp8266 or CORE.is_rp2040 or CORE.is_libretiny)
|
33
|
+
|
34
|
+
|
35
|
+
def AUTO_LOAD() -> list[str]:
|
36
|
+
"""Conditionally auto-load sha256 only on platforms that support it."""
|
37
|
+
base_components = ["md5", "socket"]
|
38
|
+
if supports_sha256():
|
39
|
+
return base_components + ["sha256"]
|
40
|
+
return base_components
|
41
|
+
|
42
|
+
|
30
43
|
esphome = cg.esphome_ns.namespace("esphome")
|
31
44
|
ESPHomeOTAComponent = esphome.class_("ESPHomeOTAComponent", OTAComponent)
|
32
45
|
|
@@ -126,9 +139,15 @@ FINAL_VALIDATE_SCHEMA = ota_esphome_final_validate
|
|
126
139
|
async def to_code(config):
|
127
140
|
var = cg.new_Pvariable(config[CONF_ID])
|
128
141
|
cg.add(var.set_port(config[CONF_PORT]))
|
142
|
+
|
129
143
|
if CONF_PASSWORD in config:
|
130
144
|
cg.add(var.set_auth_password(config[CONF_PASSWORD]))
|
131
145
|
cg.add_define("USE_OTA_PASSWORD")
|
146
|
+
# Only include hash algorithms when password is configured
|
147
|
+
cg.add_define("USE_OTA_MD5")
|
148
|
+
# Only include SHA256 support on platforms that have it
|
149
|
+
if supports_sha256():
|
150
|
+
cg.add_define("USE_OTA_SHA256")
|
132
151
|
cg.add_define("USE_OTA_VERSION", config[CONF_VERSION])
|
133
152
|
|
134
153
|
await cg.register_component(var, config)
|