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.
- esphome/__main__.py +94 -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 +7 -7
- 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/dashboard_import/dashboard_import.cpp +1 -1
- esphome/components/dashboard_import/dashboard_import.h +1 -1
- 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 +256 -340
- esphome/components/esp32/boards.py +81 -0
- esphome/components/esp32/preferences.cpp +23 -17
- esphome/components/esp32_ble/__init__.py +167 -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_beacon/esp32_ble_beacon.cpp +0 -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 -8
- 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 +135 -65
- esphome/components/esp32_improv/esp32_improv_component.h +7 -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 +456 -146
- 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 +42 -44
- 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/mcp23xxx_base/mcp23xxx_base.h +3 -3
- 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 +93 -19
- esphome/components/mdns/mdns_component.cpp +57 -94
- esphome/components/mdns/mdns_component.h +35 -11
- esphome/components/mdns/mdns_esp32.cpp +7 -13
- esphome/components/mdns/mdns_esp8266.cpp +7 -7
- esphome/components/mdns/mdns_libretiny.cpp +3 -4
- esphome/components/mdns/mdns_rp2040.cpp +3 -4
- 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/opentherm/opentherm.cpp +5 -5
- esphome/components/opentherm/opentherm.h +3 -3
- esphome/components/openthread/openthread.cpp +11 -10
- 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 +37 -27
- 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 +12 -2
- esphome/components/usb_host/usb_host.h +89 -14
- esphome/components/usb_host/usb_host_client.cpp +157 -22
- 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 +74 -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 +33 -22
- esphome/core/component.cpp +28 -18
- esphome/core/component_iterator.h +2 -1
- esphome/core/config.py +15 -15
- esphome/core/defines.h +21 -0
- esphome/core/entity_helpers.py +9 -6
- 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 +112 -32
- esphome/external_files.py +6 -7
- esphome/git.py +8 -0
- esphome/helpers.py +124 -77
- esphome/loader.py +8 -9
- esphome/pins.py +2 -2
- esphome/platformio_api.py +56 -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.0b2.dist-info}/METADATA +12 -12
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/RECORD +340 -320
- 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.0b2.dist-info}/WHEEL +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/entry_points.txt +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.9.3.dist-info → esphome-2025.10.0b2.dist-info}/top_level.txt +0 -0
@@ -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,54 +136,33 @@ 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
|
146
|
+
this->check_wifi_connection_();
|
131
147
|
break;
|
132
148
|
}
|
133
149
|
case improv::STATE_AUTHORIZED: {
|
134
150
|
#ifdef USE_BINARY_SENSOR
|
135
|
-
if (this->authorizer_ != nullptr) {
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
return;
|
140
|
-
}
|
151
|
+
if (this->authorizer_ != nullptr && now - this->authorized_start_ > this->authorized_duration_) {
|
152
|
+
ESP_LOGD(TAG, "Authorization timeout");
|
153
|
+
this->set_state_(improv::STATE_AWAITING_AUTHORIZATION);
|
154
|
+
return;
|
141
155
|
}
|
142
156
|
#endif
|
143
157
|
if (!this->check_identify_()) {
|
144
158
|
this->set_status_indicator_state_((now % 1000) < 500);
|
145
159
|
}
|
160
|
+
this->check_wifi_connection_();
|
146
161
|
break;
|
147
162
|
}
|
148
163
|
case improv::STATE_PROVISIONING: {
|
149
164
|
this->set_status_indicator_state_((now % 200) < 100);
|
150
|
-
|
151
|
-
wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(),
|
152
|
-
this->connecting_sta_.get_password());
|
153
|
-
this->connecting_sta_ = {};
|
154
|
-
this->cancel_timeout("wifi-connect-timeout");
|
155
|
-
this->set_state_(improv::STATE_PROVISIONED);
|
156
|
-
|
157
|
-
std::vector<std::string> urls = {ESPHOME_MY_LINK};
|
158
|
-
#ifdef USE_WEBSERVER
|
159
|
-
for (auto &ip : wifi::global_wifi_component->wifi_sta_ip_addresses()) {
|
160
|
-
if (ip.is_ip4()) {
|
161
|
-
std::string webserver_url = "http://" + ip.str() + ":" + to_string(USE_WEBSERVER_PORT);
|
162
|
-
urls.push_back(webserver_url);
|
163
|
-
break;
|
164
|
-
}
|
165
|
-
}
|
166
|
-
#endif
|
167
|
-
std::vector<uint8_t> data = improv::build_rpc_response(improv::WIFI_SETTINGS, urls);
|
168
|
-
this->send_response_(data);
|
169
|
-
this->stop();
|
170
|
-
}
|
165
|
+
this->check_wifi_connection_();
|
171
166
|
break;
|
172
167
|
}
|
173
168
|
case improv::STATE_PROVISIONED: {
|
@@ -226,12 +221,15 @@ bool ESP32ImprovComponent::check_identify_() {
|
|
226
221
|
return identify;
|
227
222
|
}
|
228
223
|
|
229
|
-
void ESP32ImprovComponent::set_state_(improv::State state) {
|
230
|
-
|
231
|
-
if (this->state_
|
232
|
-
|
233
|
-
this->state_to_string_(state), state);
|
224
|
+
void ESP32ImprovComponent::set_state_(improv::State state, bool update_advertising) {
|
225
|
+
// Skip if state hasn't changed
|
226
|
+
if (this->state_ == state) {
|
227
|
+
return;
|
234
228
|
}
|
229
|
+
|
230
|
+
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
231
|
+
ESP_LOGD(TAG, "State transition: %s (0x%02X) -> %s (0x%02X)", this->state_to_string_(this->state_), this->state_,
|
232
|
+
this->state_to_string_(state), state);
|
235
233
|
#endif
|
236
234
|
this->state_ = state;
|
237
235
|
if (this->status_ != nullptr && (this->status_->get_value().empty() || this->status_->get_value()[0] != state)) {
|
@@ -243,25 +241,13 @@ void ESP32ImprovComponent::set_state_(improv::State state) {
|
|
243
241
|
// STATE_STOPPED (0x00) is internal only and not part of the Improv spec.
|
244
242
|
// Advertising 0x00 causes undefined behavior in some clients and makes them
|
245
243
|
// 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);
|
244
|
+
if (state != improv::STATE_STOPPED && update_advertising) {
|
245
|
+
// State change always overrides name advertising and resets the timer
|
246
|
+
this->advertising_device_name_ = false;
|
247
|
+
// Reset the timer so we wait another 60 seconds before advertising name
|
248
|
+
this->last_name_adv_time_ = App.get_loop_component_start_time();
|
249
|
+
// Advertise the new state via service data
|
250
|
+
this->advertise_service_data_();
|
265
251
|
}
|
266
252
|
#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
|
267
253
|
this->state_callback_.call(this->state_, this->error_state_);
|
@@ -388,6 +374,90 @@ void ESP32ImprovComponent::on_wifi_connect_timeout_() {
|
|
388
374
|
wifi::global_wifi_component->clear_sta();
|
389
375
|
}
|
390
376
|
|
377
|
+
void ESP32ImprovComponent::check_wifi_connection_() {
|
378
|
+
if (!wifi::global_wifi_component->is_connected()) {
|
379
|
+
return;
|
380
|
+
}
|
381
|
+
|
382
|
+
if (this->state_ == improv::STATE_PROVISIONING) {
|
383
|
+
wifi::global_wifi_component->save_wifi_sta(this->connecting_sta_.get_ssid(), this->connecting_sta_.get_password());
|
384
|
+
this->connecting_sta_ = {};
|
385
|
+
this->cancel_timeout("wifi-connect-timeout");
|
386
|
+
|
387
|
+
std::vector<std::string> urls = {ESPHOME_MY_LINK};
|
388
|
+
#ifdef USE_WEBSERVER
|
389
|
+
for (auto &ip : wifi::global_wifi_component->wifi_sta_ip_addresses()) {
|
390
|
+
if (ip.is_ip4()) {
|
391
|
+
std::string webserver_url = "http://" + ip.str() + ":" + to_string(USE_WEBSERVER_PORT);
|
392
|
+
urls.push_back(webserver_url);
|
393
|
+
break;
|
394
|
+
}
|
395
|
+
}
|
396
|
+
#endif
|
397
|
+
std::vector<uint8_t> data = improv::build_rpc_response(improv::WIFI_SETTINGS, urls);
|
398
|
+
this->send_response_(data);
|
399
|
+
} else if (this->is_active() && this->state_ != improv::STATE_PROVISIONED) {
|
400
|
+
ESP_LOGD(TAG, "WiFi provisioned externally");
|
401
|
+
}
|
402
|
+
|
403
|
+
this->set_state_(improv::STATE_PROVISIONED);
|
404
|
+
this->stop();
|
405
|
+
}
|
406
|
+
|
407
|
+
void ESP32ImprovComponent::advertise_service_data_() {
|
408
|
+
uint8_t service_data[IMPROV_SERVICE_DATA_SIZE] = {};
|
409
|
+
service_data[0] = IMPROV_PROTOCOL_ID_1; // PR
|
410
|
+
service_data[1] = IMPROV_PROTOCOL_ID_2; // IM
|
411
|
+
service_data[2] = static_cast<uint8_t>(this->state_);
|
412
|
+
|
413
|
+
uint8_t capabilities = 0x00;
|
414
|
+
#ifdef USE_OUTPUT
|
415
|
+
if (this->status_indicator_ != nullptr)
|
416
|
+
capabilities |= improv::CAPABILITY_IDENTIFY;
|
417
|
+
#endif
|
418
|
+
|
419
|
+
service_data[3] = capabilities;
|
420
|
+
// service_data[4-7] are already 0 (Reserved)
|
421
|
+
|
422
|
+
// Atomically set service data and disable name in advertising
|
423
|
+
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>(service_data), false);
|
424
|
+
}
|
425
|
+
|
426
|
+
void ESP32ImprovComponent::update_advertising_type_() {
|
427
|
+
uint32_t now = App.get_loop_component_start_time();
|
428
|
+
|
429
|
+
// If we're advertising the device name and it's been more than NAME_ADVERTISING_DURATION, switch back to service data
|
430
|
+
if (this->advertising_device_name_) {
|
431
|
+
if (now - this->last_name_adv_time_ >= NAME_ADVERTISING_DURATION) {
|
432
|
+
ESP_LOGV(TAG, "Switching back to service data advertising");
|
433
|
+
this->advertising_device_name_ = false;
|
434
|
+
// Restore service data advertising
|
435
|
+
this->advertise_service_data_();
|
436
|
+
}
|
437
|
+
return;
|
438
|
+
}
|
439
|
+
|
440
|
+
// Check if it's time to advertise the device name (every NAME_ADVERTISING_INTERVAL)
|
441
|
+
if (now - this->last_name_adv_time_ >= NAME_ADVERTISING_INTERVAL) {
|
442
|
+
ESP_LOGV(TAG, "Switching to device name advertising");
|
443
|
+
this->advertising_device_name_ = true;
|
444
|
+
this->last_name_adv_time_ = now;
|
445
|
+
|
446
|
+
// Atomically clear service data and enable name in advertising data
|
447
|
+
esp32_ble::global_ble->advertising_set_service_data_and_name(std::span<const uint8_t>{}, true);
|
448
|
+
}
|
449
|
+
}
|
450
|
+
|
451
|
+
improv::State ESP32ImprovComponent::get_initial_state_() const {
|
452
|
+
#ifdef USE_BINARY_SENSOR
|
453
|
+
// If we have an authorizer, start in awaiting authorization state
|
454
|
+
return this->authorizer_ == nullptr ? improv::STATE_AUTHORIZED : improv::STATE_AWAITING_AUTHORIZATION;
|
455
|
+
#else
|
456
|
+
// No binary_sensor support = no authorizer possible, start as authorized
|
457
|
+
return improv::STATE_AUTHORIZED;
|
458
|
+
#endif
|
459
|
+
}
|
460
|
+
|
391
461
|
ESP32ImprovComponent *global_improv_component = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
392
462
|
|
393
463
|
} // namespace esp32_improv
|
@@ -100,14 +100,20 @@ 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_();
|
114
|
+
void check_wifi_connection_();
|
110
115
|
bool check_identify_();
|
116
|
+
void advertise_service_data_();
|
111
117
|
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
|
112
118
|
const char *state_to_string_(improv::State state);
|
113
119
|
#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)
|