esphome 2025.6.2__py3-none-any.whl → 2025.7.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 +1 -3
- esphome/codegen.py +2 -0
- esphome/components/ac_dimmer/ac_dimmer.cpp +6 -6
- esphome/components/adc/__init__.py +25 -1
- esphome/components/adc/adc_sensor.h +11 -11
- esphome/components/adc/adc_sensor_common.cpp +1 -1
- esphome/components/adc/adc_sensor_esp32.cpp +16 -8
- esphome/components/ade7880/ade7880.h +0 -2
- esphome/components/ads1115/ads1115.h +0 -1
- esphome/components/ads1118/ads1118.h +0 -1
- esphome/components/ags10/ags10.h +0 -2
- esphome/components/aic3204/aic3204.h +0 -1
- esphome/components/alarm_control_panel/__init__.py +5 -2
- esphome/components/alpha3/alpha3.h +0 -1
- esphome/components/am43/cover/am43_cover.h +0 -1
- esphome/components/am43/sensor/am43_sensor.h +0 -1
- esphome/components/analog_threshold/analog_threshold_binary_sensor.h +0 -2
- esphome/components/anova/anova.cpp +5 -1
- esphome/components/anova/anova.h +0 -1
- esphome/components/apds9960/apds9960.cpp +1 -1
- esphome/components/api/__init__.py +42 -20
- esphome/components/api/api_connection.cpp +318 -391
- esphome/components/api/api_connection.h +206 -126
- esphome/components/api/api_frame_helper.cpp +89 -124
- esphome/components/api/api_frame_helper.h +57 -45
- esphome/components/api/api_pb2.cpp +414 -4350
- esphome/components/api/api_pb2.h +287 -198
- esphome/components/api/api_pb2_dump.cpp +4333 -0
- esphome/components/api/api_pb2_service.cpp +180 -425
- esphome/components/api/api_pb2_service.h +7 -6
- esphome/components/api/api_pb2_size.h +2 -4
- esphome/components/api/api_server.cpp +138 -167
- esphome/components/api/api_server.h +66 -12
- esphome/components/api/client.py +10 -4
- esphome/components/api/list_entities.cpp +36 -105
- esphome/components/api/list_entities.h +31 -23
- esphome/components/api/proto.h +26 -3
- esphome/components/api/subscribe_state.cpp +23 -29
- esphome/components/api/subscribe_state.h +26 -19
- esphome/components/as5600/as5600.h +0 -1
- esphome/components/async_tcp/__init__.py +14 -5
- esphome/components/atc_mithermometer/atc_mithermometer.h +0 -1
- esphome/components/atm90e32/atm90e32.cpp +2 -1
- esphome/components/audio/audio_decoder.cpp +1 -1
- esphome/components/audio/audio_transfer_buffer.cpp +2 -2
- esphome/components/b_parasite/b_parasite.h +0 -1
- esphome/components/bedjet/bedjet_hub.cpp +5 -1
- esphome/components/bedjet/climate/bedjet_climate.cpp +5 -1
- esphome/components/beken_spi_led_strip/led_strip.cpp +4 -2
- esphome/components/bh1750/bh1750.cpp +5 -5
- esphome/components/binary_sensor/__init__.py +82 -5
- esphome/components/binary_sensor/automation.h +19 -1
- esphome/components/binary_sensor/binary_sensor.cpp +12 -30
- esphome/components/binary_sensor/binary_sensor.h +11 -25
- esphome/components/binary_sensor/filter.cpp +29 -24
- esphome/components/binary_sensor/filter.h +20 -10
- esphome/components/ble_client/output/ble_binary_output.h +0 -1
- esphome/components/ble_client/sensor/ble_rssi_sensor.cpp +5 -1
- esphome/components/ble_client/sensor/ble_rssi_sensor.h +0 -1
- esphome/components/ble_client/sensor/ble_sensor.cpp +5 -1
- esphome/components/ble_client/sensor/ble_sensor.h +0 -1
- esphome/components/ble_client/switch/ble_switch.h +0 -1
- esphome/components/ble_client/text_sensor/ble_text_sensor.cpp +5 -1
- esphome/components/ble_client/text_sensor/ble_text_sensor.h +0 -1
- esphome/components/ble_presence/ble_presence_device.h +0 -1
- esphome/components/ble_rssi/ble_rssi_sensor.h +0 -1
- esphome/components/ble_scanner/ble_scanner.h +0 -1
- esphome/components/bluetooth_proxy/bluetooth_connection.h +9 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +16 -6
- esphome/components/bluetooth_proxy/bluetooth_proxy.h +8 -2
- esphome/components/bme680/sensor.py +1 -1
- esphome/components/bmp581/bmp581.h +0 -2
- esphome/components/button/__init__.py +5 -2
- esphome/components/camera/__init__.py +1 -0
- esphome/components/camera/camera.cpp +22 -0
- esphome/components/camera/camera.h +80 -0
- esphome/components/canbus/__init__.py +1 -0
- esphome/components/cap1188/cap1188.h +0 -1
- esphome/components/captive_portal/__init__.py +12 -2
- esphome/components/captive_portal/captive_portal.cpp +12 -2
- esphome/components/captive_portal/captive_portal.h +5 -2
- esphome/components/ccs811/ccs811.h +0 -2
- esphome/components/climate/__init__.py +5 -2
- esphome/components/cm1106/sensor.py +2 -2
- esphome/components/const/__init__.py +2 -0
- esphome/components/copy/binary_sensor/copy_binary_sensor.h +0 -1
- esphome/components/copy/button/copy_button.h +0 -1
- esphome/components/copy/cover/copy_cover.h +0 -1
- esphome/components/copy/fan/copy_fan.h +0 -1
- esphome/components/copy/lock/copy_lock.h +0 -1
- esphome/components/copy/number/copy_number.h +0 -1
- esphome/components/copy/select/copy_select.h +0 -1
- esphome/components/copy/sensor/copy_sensor.h +0 -1
- esphome/components/copy/switch/copy_switch.h +0 -1
- esphome/components/copy/text/copy_text.h +0 -1
- esphome/components/copy/text_sensor/copy_text_sensor.h +0 -1
- esphome/components/cover/__init__.py +5 -2
- esphome/components/cs5460a/cs5460a.h +0 -1
- esphome/components/datetime/__init__.py +4 -2
- esphome/components/debug/__init__.py +20 -0
- esphome/components/deep_sleep/__init__.py +43 -9
- esphome/components/demo/__init__.py +2 -2
- esphome/components/display/display.cpp +4 -3
- esphome/components/display/display.h +0 -2
- esphome/components/display/display_buffer.cpp +1 -1
- esphome/components/ds2484/__init__.py +1 -0
- esphome/components/ds2484/ds2484.cpp +209 -0
- esphome/components/ds2484/ds2484.h +43 -0
- esphome/components/ds2484/one_wire.py +37 -0
- esphome/components/duty_time/duty_time_sensor.h +0 -1
- esphome/components/ens160_base/ens160_base.h +0 -1
- esphome/components/es7210/es7210.h +0 -1
- esphome/components/es7243e/es7243e.h +0 -1
- esphome/components/es8156/es8156.h +0 -1
- esphome/components/es8311/es8311.h +0 -1
- esphome/components/es8388/es8388.h +0 -1
- esphome/components/esp32/__init__.py +102 -135
- esphome/components/esp32/core.cpp +0 -4
- esphome/components/esp32/gpio.h +1 -1
- esphome/components/esp32/helpers.cpp +69 -0
- esphome/components/esp32_ble/ble.cpp +5 -6
- esphome/components/esp32_ble/ble.h +29 -14
- esphome/components/esp32_ble/ble_event.h +6 -6
- esphome/components/esp32_ble_client/ble_client_base.cpp +21 -6
- esphome/components/esp32_ble_client/ble_client_base.h +24 -9
- esphome/components/esp32_ble_tracker/__init__.py +2 -8
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +5 -5
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +11 -7
- esphome/components/esp32_camera/__init__.py +111 -97
- esphome/components/esp32_camera/esp32_camera.cpp +41 -31
- esphome/components/esp32_camera/esp32_camera.h +35 -30
- esphome/components/esp32_camera_web_server/__init__.py +2 -1
- esphome/components/esp32_camera_web_server/camera_web_server.cpp +8 -8
- esphome/components/esp32_camera_web_server/camera_web_server.h +3 -3
- esphome/components/esp32_hall/sensor.py +2 -21
- esphome/components/esp32_hosted/__init__.py +101 -0
- esphome/components/esp32_hosted/esp32_hosted.py.script +12 -0
- esphome/components/esp32_improv/esp32_improv_component.cpp +3 -0
- esphome/components/esp32_rmt/__init__.py +0 -58
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +77 -63
- esphome/components/esp32_rmt_led_strip/led_strip.h +11 -17
- esphome/components/esp32_rmt_led_strip/light.py +14 -76
- esphome/components/esp32_touch/esp32_touch.h +174 -28
- esphome/components/esp32_touch/esp32_touch_common.cpp +162 -0
- esphome/components/esp32_touch/esp32_touch_v1.cpp +238 -0
- esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
- esphome/components/esp8266/__init__.py +1 -0
- esphome/components/esp8266/gpio.cpp +10 -10
- esphome/components/esp8266/helpers.cpp +31 -0
- esphome/components/esphome/ota/__init__.py +1 -0
- esphome/components/esphome/ota/ota_esphome.cpp +24 -19
- esphome/components/ethernet/__init__.py +42 -23
- esphome/components/ethernet/esp_eth_phy_jl1101.c +0 -16
- esphome/components/ethernet/ethernet_component.cpp +69 -29
- esphome/components/ethernet/ethernet_component.h +18 -10
- esphome/components/event/__init__.py +5 -2
- esphome/components/ezo/ezo.h +0 -1
- esphome/components/ezo_pmp/ezo_pmp.h +0 -1
- esphome/components/fan/__init__.py +5 -2
- esphome/components/feedback/feedback_cover.h +0 -1
- esphome/components/font/__init__.py +92 -82
- esphome/components/font/font.cpp +9 -2
- esphome/components/font/font.h +20 -5
- esphome/components/fs3000/fs3000.h +0 -1
- esphome/components/gcja5/gcja5.h +0 -1
- esphome/components/gl_r01_i2c/__init__.py +0 -0
- esphome/components/gl_r01_i2c/gl_r01_i2c.cpp +68 -0
- esphome/components/gl_r01_i2c/gl_r01_i2c.h +22 -0
- esphome/components/gl_r01_i2c/sensor.py +36 -0
- esphome/components/gp8403/gp8403.h +0 -1
- esphome/components/gpio/binary_sensor/__init__.py +17 -0
- esphome/components/gpio/binary_sensor/gpio_binary_sensor.cpp +77 -3
- esphome/components/gpio/binary_sensor/gpio_binary_sensor.h +40 -0
- esphome/components/grove_gas_mc_v2/grove_gas_mc_v2.h +0 -2
- esphome/components/he60r/he60r.h +0 -1
- esphome/components/heatpumpir/climate.py +2 -1
- esphome/components/heatpumpir/heatpumpir.cpp +1 -0
- esphome/components/heatpumpir/heatpumpir.h +1 -0
- esphome/components/honeywellabp2_i2c/honeywellabp2.h +0 -1
- esphome/components/host/__init__.py +2 -1
- esphome/components/host/helpers.cpp +57 -0
- esphome/components/http_request/__init__.py +19 -1
- esphome/components/http_request/http_request.h +1 -1
- esphome/components/http_request/http_request_arduino.cpp +0 -1
- esphome/components/http_request/http_request_arduino.h +1 -0
- esphome/components/http_request/http_request_idf.cpp +0 -1
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +28 -9
- esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +3 -9
- esphome/components/hydreon_rgxx/sensor.py +1 -1
- esphome/components/i2c/__init__.py +23 -11
- esphome/components/i2c/i2c_bus.h +8 -1
- esphome/components/i2c/i2c_bus_arduino.cpp +4 -3
- esphome/components/i2c/i2c_bus_arduino.h +6 -3
- esphome/components/i2c/i2c_bus_esp_idf.h +5 -3
- esphome/components/i2c_device/i2c_device.h +0 -1
- esphome/components/i2s_audio/__init__.py +2 -10
- esphome/components/i2s_audio/i2s_audio.cpp +1 -5
- esphome/components/i2s_audio/media_player/__init__.py +2 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +2 -2
- esphome/components/iaqcore/iaqcore.h +0 -2
- esphome/components/image/__init__.py +123 -24
- esphome/components/improv_serial/improv_serial_component.cpp +0 -4
- esphome/components/ina219/ina219.cpp +7 -0
- esphome/components/ina219/ina219.h +1 -0
- esphome/components/ina260/ina260.h +0 -2
- esphome/components/inkbird_ibsth1_mini/inkbird_ibsth1_mini.h +0 -1
- esphome/components/inkplate6/display.py +15 -0
- esphome/components/inkplate6/inkplate.cpp +2 -2
- esphome/components/integration/integration_sensor.h +0 -1
- esphome/components/internal_temperature/internal_temperature.cpp +8 -27
- esphome/components/internal_temperature/sensor.py +0 -26
- esphome/components/interval/interval.h +0 -2
- esphome/components/ld2410/button/__init__.py +3 -3
- esphome/components/ld2410/button/factory_reset_button.cpp +9 -0
- esphome/components/ld2410/button/{reset_button.h → factory_reset_button.h} +2 -2
- esphome/components/ld2410/ld2410.cpp +430 -261
- esphome/components/ld2410/ld2410.h +44 -146
- esphome/components/ld2410/number/__init__.py +2 -2
- esphome/components/ld2410/sensor.py +1 -1
- esphome/components/ld2410/switch/__init__.py +1 -1
- esphome/components/ld2420/ld2420.cpp +196 -100
- esphome/components/ld2420/ld2420.h +46 -118
- esphome/components/ld2420/number/__init__.py +2 -2
- esphome/components/ld2420/sensor/__init__.py +6 -2
- esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
- esphome/components/ld2450/button/__init__.py +3 -3
- esphome/components/ld2450/button/factory_reset_button.cpp +9 -0
- esphome/components/ld2450/button/{reset_button.h → factory_reset_button.h} +2 -2
- esphome/components/ld2450/ld2450.cpp +384 -232
- esphome/components/ld2450/ld2450.h +60 -69
- esphome/components/ld2450/switch/__init__.py +1 -1
- esphome/components/ledc/ledc_output.cpp +1 -63
- esphome/components/libretiny/__init__.py +4 -3
- esphome/components/libretiny/const.py +5 -0
- esphome/components/libretiny/generate_components.py +1 -0
- esphome/components/libretiny/helpers.cpp +35 -0
- esphome/components/libretiny/lt_component.cpp +5 -3
- esphome/components/light/__init__.py +4 -2
- esphome/components/light/addressable_light.h +3 -3
- esphome/components/light/light_call.cpp +180 -243
- esphome/components/light/light_call.h +72 -20
- esphome/components/light/light_color_values.h +14 -14
- esphome/components/light/light_state.h +15 -13
- esphome/components/light/transformers.h +2 -2
- esphome/components/ln882x/__init__.py +52 -0
- esphome/components/ln882x/boards.py +285 -0
- esphome/components/lock/__init__.py +5 -2
- esphome/components/logger/__init__.py +40 -3
- esphome/components/logger/logger.cpp +47 -12
- esphome/components/logger/logger.h +80 -49
- esphome/components/logger/logger_esp32.cpp +3 -3
- esphome/components/lps22/__init__.py +0 -0
- esphome/components/lps22/lps22.cpp +75 -0
- esphome/components/lps22/lps22.h +27 -0
- esphome/components/lps22/sensor.py +58 -0
- esphome/components/ltr390/ltr390.h +0 -1
- esphome/components/ltr501/ltr501.h +0 -1
- esphome/components/ltr_als_ps/ltr_als_ps.h +0 -1
- esphome/components/lvgl/__init__.py +1 -1
- esphome/components/lvgl/schemas.py +66 -6
- esphome/components/lvgl/styles.py +24 -16
- esphome/components/lvgl/widgets/__init__.py +12 -2
- esphome/components/lvgl/widgets/lv_bar.py +40 -19
- esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +1 -1
- esphome/components/max9611/max9611.h +0 -1
- esphome/components/mcp23016/__init__.py +1 -1
- esphome/components/mcp23xxx_base/__init__.py +1 -1
- esphome/components/mcp4461/__init__.py +1 -1
- esphome/components/mcp4461/output/__init__.py +3 -2
- esphome/components/mcp9600/mcp9600.h +0 -2
- esphome/components/md5/md5.cpp +3 -3
- esphome/components/md5/md5.h +1 -6
- esphome/components/mdns/__init__.py +22 -11
- esphome/components/media_player/__init__.py +4 -3
- esphome/components/micro_wake_word/__init__.py +1 -5
- esphome/components/micro_wake_word/streaming_model.cpp +2 -2
- esphome/components/microphone/microphone.cpp +7 -9
- esphome/components/microphone/microphone.h +0 -2
- esphome/components/mipi_spi/display.py +1 -0
- esphome/components/mmc5603/mmc5603.cpp +1 -1
- esphome/components/modbus/modbus.cpp +33 -15
- esphome/components/modbus/modbus.h +9 -0
- esphome/components/modbus_controller/__init__.py +42 -10
- esphome/components/modbus_controller/modbus_controller.cpp +92 -11
- esphome/components/modbus_controller/modbus_controller.h +61 -7
- esphome/components/mopeka_pro_check/mopeka_pro_check.h +0 -1
- esphome/components/mopeka_std_check/mopeka_std_check.h +0 -1
- esphome/components/mpl3115a2/mpl3115a2.h +0 -2
- esphome/components/mqtt/__init__.py +16 -0
- esphome/components/mqtt/mqtt_backend.h +2 -1
- esphome/components/mqtt/mqtt_backend_esp32.cpp +126 -45
- esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
- esphome/components/mqtt/mqtt_client.cpp +15 -9
- esphome/components/mqtt/mqtt_client.h +8 -3
- esphome/components/ms8607/ms8607.h +0 -1
- esphome/components/neopixelbus/light.py +4 -1
- esphome/components/neopixelbus/neopixelbus_light.h +1 -1
- esphome/components/network/__init__.py +4 -1
- esphome/components/network/ip_address.h +1 -0
- esphome/components/nextion/__init__.py +16 -0
- esphome/components/nextion/base_component.py +1 -0
- esphome/components/nextion/binary_sensor/nextion_binarysensor.cpp +1 -1
- esphome/components/nextion/display.py +14 -4
- esphome/components/nextion/nextion.cpp +166 -101
- esphome/components/nextion/nextion.h +84 -53
- esphome/components/nextion/nextion_commands.cpp +11 -10
- esphome/components/nextion/nextion_component.cpp +28 -28
- esphome/components/nextion/nextion_component.h +53 -18
- esphome/components/nextion/nextion_component_base.h +3 -0
- esphome/components/nextion/nextion_upload.cpp +36 -0
- esphome/components/nextion/nextion_upload_arduino.cpp +10 -35
- esphome/components/nextion/nextion_upload_idf.cpp +9 -33
- esphome/components/nextion/sensor/nextion_sensor.cpp +1 -1
- esphome/components/nextion/switch/nextion_switch.cpp +1 -1
- esphome/components/nextion/text_sensor/nextion_textsensor.cpp +1 -1
- esphome/components/nfc/nfc.cpp +3 -22
- esphome/components/nfc/nfc.h +3 -3
- esphome/components/number/__init__.py +5 -2
- esphome/components/online_image/__init__.py +5 -0
- esphome/components/online_image/online_image.cpp +6 -2
- esphome/components/online_image/online_image.h +4 -1
- esphome/components/opentherm/opentherm.cpp +7 -12
- esphome/components/openthread/__init__.py +47 -40
- esphome/components/openthread/const.py +1 -0
- esphome/components/openthread/openthread_esp.cpp +27 -5
- esphome/components/opt3001/__init__.py +0 -0
- esphome/components/opt3001/opt3001.cpp +122 -0
- esphome/components/opt3001/opt3001.h +27 -0
- esphome/components/opt3001/sensor.py +35 -0
- esphome/components/ota/__init__.py +17 -0
- esphome/components/ota/ota_backend.h +27 -1
- esphome/components/ota/ota_backend_arduino_esp32.cpp +12 -2
- esphome/components/ota/ota_backend_arduino_esp32.h +3 -0
- esphome/components/ota/ota_backend_arduino_esp8266.cpp +18 -4
- esphome/components/ota/ota_backend_arduino_esp8266.h +3 -0
- esphome/components/ota/ota_backend_arduino_libretiny.cpp +12 -2
- esphome/components/ota/ota_backend_arduino_libretiny.h +3 -0
- esphome/components/ota/ota_backend_arduino_rp2040.cpp +9 -2
- esphome/components/ota/ota_backend_arduino_rp2040.h +3 -0
- esphome/components/ota/ota_backend_esp_idf.cpp +10 -16
- esphome/components/ota/ota_backend_esp_idf.h +1 -0
- esphome/components/packages/__init__.py +5 -2
- esphome/components/packet_transport/binary_sensor.py +61 -4
- esphome/components/packet_transport/packet_transport.cpp +31 -1
- esphome/components/packet_transport/packet_transport.h +11 -5
- esphome/components/pcf8574/__init__.py +1 -1
- esphome/components/pi4ioe5v6408/__init__.py +84 -0
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.cpp +171 -0
- esphome/components/pi4ioe5v6408/pi4ioe5v6408.h +70 -0
- esphome/components/pmsa003i/pmsa003i.h +0 -1
- esphome/components/pmsx003/pmsx003.h +0 -1
- esphome/components/pn7150/pn7150.cpp +7 -7
- esphome/components/pn7150/pn7150.h +0 -1
- esphome/components/pn7160/pn7160.cpp +7 -7
- esphome/components/pn7160/pn7160.h +0 -1
- esphome/components/preferences/syncer.h +2 -0
- esphome/components/prometheus/prometheus_handler.h +1 -1
- esphome/components/psram/psram.cpp +0 -20
- esphome/components/pulse_counter/pulse_counter_sensor.h +0 -1
- esphome/components/pulse_meter/pulse_meter_sensor.cpp +8 -4
- esphome/components/pulse_width/pulse_width.h +0 -1
- esphome/components/pvvx_mithermometer/display/pvvx_display.cpp +0 -4
- esphome/components/pvvx_mithermometer/display/pvvx_display.h +0 -2
- esphome/components/pvvx_mithermometer/pvvx_mithermometer.h +0 -1
- esphome/components/qr_code/__init__.py +13 -10
- esphome/components/qwiic_pir/qwiic_pir.h +0 -1
- esphome/components/radon_eye_ble/radon_eye_listener.cpp +1 -1
- esphome/components/rc522/rc522.h +0 -1
- esphome/components/rdm6300/rdm6300.h +0 -2
- esphome/components/remote_base/__init__.py +7 -5
- esphome/components/remote_base/remote_base.cpp +24 -21
- esphome/components/remote_base/remote_base.h +3 -26
- esphome/components/remote_receiver/__init__.py +40 -46
- esphome/components/remote_receiver/remote_receiver.h +4 -18
- esphome/components/remote_receiver/remote_receiver_esp32.cpp +0 -87
- esphome/components/remote_receiver/remote_receiver_esp8266.cpp +1 -1
- esphome/components/remote_transmitter/__init__.py +42 -43
- esphome/components/remote_transmitter/remote_transmitter.h +2 -14
- esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +0 -77
- esphome/components/resistance/resistance_sensor.h +0 -1
- esphome/components/rp2040/__init__.py +1 -0
- esphome/components/rp2040/helpers.cpp +55 -0
- esphome/components/rp2040_pio_led_strip/led_strip.cpp +2 -2
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +0 -4
- esphome/components/rtttl/__init__.py +4 -4
- esphome/components/rtttl/rtttl.cpp +10 -1
- esphome/components/ruuvitag/ruuvitag.h +0 -1
- esphome/components/safe_mode/safe_mode.cpp +2 -0
- esphome/components/safe_mode/safe_mode.h +4 -1
- esphome/components/scd30/scd30.h +0 -1
- esphome/components/scd30/sensor.py +2 -2
- esphome/components/scd4x/scd4x.cpp +61 -54
- esphome/components/scd4x/scd4x.h +17 -15
- esphome/components/scd4x/sensor.py +4 -4
- esphome/components/script/script.h +0 -2
- esphome/components/sdp3x/sensor.py +1 -1
- esphome/components/select/__init__.py +5 -2
- esphome/components/sen5x/sen5x.h +0 -1
- esphome/components/senseair/senseair.h +0 -1
- esphome/components/sensor/__init__.py +4 -2
- esphome/components/sensor/filter.cpp +1 -1
- esphome/components/sensor/sensor.cpp +12 -6
- esphome/components/sensor/sensor.h +13 -5
- esphome/components/servo/servo.h +0 -1
- esphome/components/sfa30/sfa30.h +0 -1
- esphome/components/sgp30/sgp30.h +0 -1
- esphome/components/sgp4x/sgp4x.h +0 -1
- esphome/components/shelly_dimmer/stm32flash.cpp +1 -2
- esphome/components/sht4x/sht4x.h +0 -1
- esphome/components/sm300d2/sm300d2.h +0 -2
- esphome/components/smt100/sensor.py +8 -4
- esphome/components/smt100/smt100.cpp +5 -5
- esphome/components/smt100/smt100.h +3 -3
- esphome/components/sn74hc595/__init__.py +1 -1
- esphome/components/sn74hc595/sn74hc595.cpp +5 -4
- esphome/components/sntp/sntp_component.cpp +9 -3
- esphome/components/sntp/time.py +2 -0
- esphome/components/socket/__init__.py +17 -0
- esphome/components/spi/__init__.py +27 -6
- esphome/components/spi/spi.cpp +3 -2
- esphome/components/spi/spi.h +9 -3
- esphome/components/spi/spi_arduino.cpp +3 -5
- esphome/components/spi/spi_esp_idf.cpp +40 -21
- esphome/components/spi_led_strip/spi_led_strip.cpp +1 -1
- esphome/components/sps30/sps30.h +0 -1
- esphome/components/ssd1306_base/ssd1306_base.cpp +1 -1
- esphome/components/st7701s/st7701s.cpp +0 -4
- esphome/components/status/status_binary_sensor.h +0 -2
- esphome/components/substitutions/__init__.py +76 -19
- esphome/components/substitutions/jinja.py +99 -0
- esphome/components/sun/sun.cpp +3 -4
- esphome/components/switch/__init__.py +5 -2
- esphome/components/switch/binary_sensor/switch_binary_sensor.h +0 -1
- esphome/components/sx126x/__init__.py +317 -0
- esphome/components/sx126x/automation.h +62 -0
- esphome/components/sx126x/packet_transport/__init__.py +26 -0
- esphome/components/sx126x/packet_transport/sx126x_transport.cpp +26 -0
- esphome/components/sx126x/packet_transport/sx126x_transport.h +25 -0
- esphome/components/sx126x/sx126x.cpp +523 -0
- esphome/components/sx126x/sx126x.h +140 -0
- esphome/components/sx126x/sx126x_reg.h +163 -0
- esphome/components/sx127x/__init__.py +325 -0
- esphome/components/sx127x/automation.h +62 -0
- esphome/components/sx127x/packet_transport/__init__.py +26 -0
- esphome/components/sx127x/packet_transport/sx127x_transport.cpp +26 -0
- esphome/components/sx127x/packet_transport/sx127x_transport.h +25 -0
- esphome/components/sx127x/sx127x.cpp +498 -0
- esphome/components/sx127x/sx127x.h +128 -0
- esphome/components/sx127x/sx127x_reg.h +295 -0
- esphome/components/syslog/esphome_syslog.cpp +5 -3
- esphome/components/syslog/esphome_syslog.h +1 -1
- esphome/components/tca9555/__init__.py +1 -1
- esphome/components/template/binary_sensor/template_binary_sensor.cpp +1 -9
- esphome/components/text/__init__.py +5 -2
- esphome/components/text_sensor/__init__.py +5 -2
- esphome/components/thermostat/thermostat_climate.cpp +34 -31
- esphome/components/thermostat/thermostat_climate.h +43 -39
- esphome/components/time/__init__.py +16 -2
- esphome/components/time/real_time_clock.cpp +4 -0
- esphome/components/time/real_time_clock.h +5 -1
- esphome/components/tlc5971/tlc5971.cpp +4 -1
- esphome/components/tmp1075/tmp1075.h +0 -2
- esphome/components/tof10120/tof10120_sensor.h +0 -1
- esphome/components/tormatic/tormatic_cover.h +0 -1
- esphome/components/total_daily_energy/total_daily_energy.h +0 -1
- esphome/components/tsl2591/tsl2591.cpp +1 -1
- esphome/components/ttp229_bsf/ttp229_bsf.h +0 -1
- esphome/components/ttp229_lsf/ttp229_lsf.h +0 -1
- esphome/components/tx20/tx20.cpp +2 -2
- esphome/components/uart/__init__.py +18 -0
- esphome/components/uart/uart_component_esp_idf.cpp +1 -5
- esphome/components/update/__init__.py +5 -2
- esphome/components/update/update_entity.h +8 -0
- esphome/components/usb_host/__init__.py +5 -2
- esphome/components/valve/__init__.py +5 -2
- esphome/components/vbus/vbus.h +0 -1
- esphome/components/veml3235/veml3235.h +0 -1
- esphome/components/veml7700/veml7700.h +0 -1
- esphome/components/vl53l0x/vl53l0x_sensor.h +0 -1
- esphome/components/voice_assistant/voice_assistant.cpp +4 -4
- esphome/components/watchdog/watchdog.cpp +0 -4
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +6 -6
- esphome/components/web_server/__init__.py +34 -19
- esphome/components/web_server/ota/__init__.py +32 -0
- esphome/components/web_server/ota/ota_web_server.cpp +210 -0
- esphome/components/web_server/ota/ota_web_server.h +26 -0
- esphome/components/web_server/web_server.cpp +311 -430
- esphome/components/web_server/web_server.h +33 -23
- esphome/components/web_server/web_server_v1.cpp +4 -5
- esphome/components/web_server_base/__init__.py +5 -2
- esphome/components/web_server_base/web_server_base.cpp +2 -94
- esphome/components/web_server_base/web_server_base.h +5 -25
- esphome/components/web_server_idf/multipart.cpp +254 -0
- esphome/components/web_server_idf/multipart.h +86 -0
- esphome/components/web_server_idf/utils.cpp +32 -0
- esphome/components/web_server_idf/utils.h +10 -0
- esphome/components/web_server_idf/web_server_idf.cpp +162 -16
- esphome/components/web_server_idf/web_server_idf.h +11 -10
- esphome/components/wiegand/wiegand.cpp +2 -2
- esphome/components/wifi/__init__.py +18 -0
- esphome/components/wifi/wifi_component.cpp +17 -22
- esphome/components/wifi/wifi_component.h +27 -23
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +52 -59
- esphome/components/wifi/wifi_component_esp8266.cpp +46 -46
- esphome/components/wifi/wifi_component_esp_idf.cpp +35 -36
- esphome/components/wifi/wifi_component_libretiny.cpp +26 -27
- esphome/components/wifi/wifi_component_pico_w.cpp +3 -3
- esphome/components/wifi_info/wifi_info_text_sensor.cpp +6 -6
- esphome/components/wireguard/__init__.py +2 -11
- esphome/components/xiaomi_ble/xiaomi_ble.cpp +13 -1
- esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
- esphome/components/xiaomi_cgd1/xiaomi_cgd1.h +0 -1
- esphome/components/xiaomi_cgdk2/xiaomi_cgdk2.h +0 -1
- esphome/components/xiaomi_cgg1/xiaomi_cgg1.h +0 -1
- esphome/components/xiaomi_cgpr1/xiaomi_cgpr1.h +0 -1
- esphome/components/xiaomi_gcls002/xiaomi_gcls002.h +0 -1
- esphome/components/xiaomi_hhccjcy01/xiaomi_hhccjcy01.h +0 -1
- esphome/components/xiaomi_hhccjcy10/xiaomi_hhccjcy10.h +0 -1
- esphome/components/xiaomi_hhccpot002/xiaomi_hhccpot002.h +0 -1
- esphome/components/xiaomi_jqjcy01ym/xiaomi_jqjcy01ym.h +0 -1
- esphome/components/xiaomi_lywsd02/xiaomi_lywsd02.h +0 -1
- esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +0 -1
- esphome/components/xiaomi_lywsd03mmc/xiaomi_lywsd03mmc.h +0 -1
- esphome/components/xiaomi_lywsdcgq/xiaomi_lywsdcgq.h +0 -1
- esphome/components/xiaomi_mhoc303/xiaomi_mhoc303.h +0 -1
- esphome/components/xiaomi_mhoc401/xiaomi_mhoc401.h +0 -1
- esphome/components/xiaomi_miscale/xiaomi_miscale.h +0 -1
- esphome/components/xiaomi_mjyd02yla/xiaomi_mjyd02yla.h +0 -1
- esphome/components/xiaomi_mue4094rt/xiaomi_mue4094rt.h +0 -1
- esphome/components/xiaomi_rtcgq02lm/xiaomi_rtcgq02lm.h +0 -1
- esphome/components/xiaomi_wx08zm/xiaomi_wx08zm.h +0 -1
- esphome/components/xiaomi_xmwsdj04mmc/__init__.py +0 -0
- esphome/components/xiaomi_xmwsdj04mmc/sensor.py +77 -0
- esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.cpp +77 -0
- esphome/components/xiaomi_xmwsdj04mmc/xiaomi_xmwsdj04mmc.h +36 -0
- esphome/components/zio_ultrasonic/zio_ultrasonic.h +0 -2
- esphome/components/zyaura/zyaura.h +0 -1
- esphome/config.py +88 -22
- esphome/config_helpers.py +74 -1
- esphome/config_validation.py +12 -1
- esphome/const.py +65 -10
- esphome/core/__init__.py +18 -2
- esphome/core/application.cpp +163 -10
- esphome/core/application.h +145 -165
- esphome/core/area.h +19 -0
- esphome/core/automation.h +58 -9
- esphome/core/color.cpp +3 -5
- esphome/core/color.h +16 -16
- esphome/core/component.cpp +151 -18
- esphome/core/component.h +98 -4
- esphome/core/component_iterator.cpp +7 -7
- esphome/core/component_iterator.h +9 -7
- esphome/core/config.py +155 -6
- esphome/core/controller.cpp +4 -2
- esphome/core/controller.h +1 -1
- esphome/core/datatypes.h +2 -2
- esphome/core/defines.h +17 -2
- esphome/core/device.h +20 -0
- esphome/core/entity_base.cpp +20 -15
- esphome/core/entity_base.h +76 -0
- esphome/core/entity_helpers.py +162 -1
- esphome/core/event_pool.h +81 -0
- esphome/core/helpers.cpp +75 -230
- esphome/core/helpers.h +164 -104
- esphome/core/lock_free_queue.h +151 -0
- esphome/core/log.cpp +2 -2
- esphome/core/log.h +2 -0
- esphome/core/optional.h +5 -0
- esphome/core/ring_buffer.cpp +2 -2
- esphome/core/scheduler.cpp +278 -103
- esphome/core/scheduler.h +157 -17
- esphome/core/time.cpp +5 -5
- esphome/core/time.h +5 -5
- esphome/cpp_generator.py +17 -0
- esphome/cpp_helpers.py +0 -22
- esphome/cpp_types.py +3 -1
- esphome/dashboard/entries.py +1 -1
- esphome/dashboard/util/text.py +5 -21
- esphome/dashboard/web_server.py +9 -1
- esphome/helpers.py +47 -0
- esphome/loader.py +15 -1
- esphome/pins.py +14 -8
- esphome/wizard.py +16 -3
- esphome/writer.py +21 -3
- esphome/yaml_util.py +0 -2
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/METADATA +10 -9
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/RECORD +593 -533
- esphome/components/esp32_ble/ble_event_pool.h +0 -72
- esphome/components/esp32_ble/queue.h +0 -85
- esphome/components/esp32_hall/esp32_hall.cpp +0 -25
- esphome/components/esp32_hall/esp32_hall.h +0 -23
- esphome/components/esp32_touch/esp32_touch.cpp +0 -355
- esphome/components/ld2410/button/reset_button.cpp +0 -9
- esphome/components/ld2450/button/reset_button.cpp +0 -9
- esphome/components/openthread/tlv.py +0 -65
- /esphome/{dashboard/enum.py → enum.py} +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/WHEEL +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.6.2.dist-info → esphome-2025.7.0b1.dist-info}/top_level.txt +0 -0
esphome/core/scheduler.cpp
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
#include "esphome/core/log.h"
|
|
8
8
|
#include <algorithm>
|
|
9
9
|
#include <cinttypes>
|
|
10
|
+
#include <cstring>
|
|
10
11
|
|
|
11
12
|
namespace esphome {
|
|
12
13
|
|
|
@@ -17,67 +18,150 @@ static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10;
|
|
|
17
18
|
// Uncomment to debug scheduler
|
|
18
19
|
// #define ESPHOME_DEBUG_SCHEDULER
|
|
19
20
|
|
|
21
|
+
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
22
|
+
// Helper to validate that a pointer looks like it's in static memory
|
|
23
|
+
static void validate_static_string(const char *name) {
|
|
24
|
+
if (name == nullptr)
|
|
25
|
+
return;
|
|
26
|
+
|
|
27
|
+
// This is a heuristic check - stack and heap pointers are typically
|
|
28
|
+
// much higher in memory than static data
|
|
29
|
+
uintptr_t addr = reinterpret_cast<uintptr_t>(name);
|
|
30
|
+
|
|
31
|
+
// Create a stack variable to compare against
|
|
32
|
+
int stack_var;
|
|
33
|
+
uintptr_t stack_addr = reinterpret_cast<uintptr_t>(&stack_var);
|
|
34
|
+
|
|
35
|
+
// If the string pointer is near our stack variable, it's likely on the stack
|
|
36
|
+
// Using 8KB range as ESP32 main task stack is typically 8192 bytes
|
|
37
|
+
if (addr > (stack_addr - 0x2000) && addr < (stack_addr + 0x2000)) {
|
|
38
|
+
ESP_LOGW(TAG,
|
|
39
|
+
"WARNING: Scheduler name '%s' at %p appears to be on the stack - this is unsafe!\n"
|
|
40
|
+
" Stack reference at %p",
|
|
41
|
+
name, name, &stack_var);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Also check if it might be on the heap by seeing if it's in a very different range
|
|
45
|
+
// This is platform-specific but generally heap is allocated far from static memory
|
|
46
|
+
static const char *static_str = "test";
|
|
47
|
+
uintptr_t static_addr = reinterpret_cast<uintptr_t>(static_str);
|
|
48
|
+
|
|
49
|
+
// If the address is very far from known static memory, it might be heap
|
|
50
|
+
if (addr > static_addr + 0x100000 || (static_addr > 0x100000 && addr < static_addr - 0x100000)) {
|
|
51
|
+
ESP_LOGW(TAG, "WARNING: Scheduler name '%s' at %p might be on heap (static ref at %p)", name, name, static_str);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
#endif
|
|
55
|
+
|
|
20
56
|
// A note on locking: the `lock_` lock protects the `items_` and `to_add_` containers. It must be taken when writing to
|
|
21
57
|
// them (i.e. when adding/removing items, but not when changing items). As items are only deleted from the loop task,
|
|
22
58
|
// iterating over them from the loop task is fine; but iterating from any other context requires the lock to be held to
|
|
23
59
|
// avoid the main thread modifying the list while it is being accessed.
|
|
24
60
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
this->cancel_timeout(component, name);
|
|
61
|
+
// Common implementation for both timeout and interval
|
|
62
|
+
void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type type, bool is_static_string,
|
|
63
|
+
const void *name_ptr, uint32_t delay, std::function<void()> func) {
|
|
64
|
+
// Get the name as const char*
|
|
65
|
+
const char *name_cstr = this->get_name_cstr_(is_static_string, name_ptr);
|
|
31
66
|
|
|
32
|
-
if (
|
|
67
|
+
if (delay == SCHEDULER_DONT_RUN) {
|
|
68
|
+
// Still need to cancel existing timer if name is not empty
|
|
69
|
+
if (this->is_name_valid_(name_cstr)) {
|
|
70
|
+
LockGuard guard{this->lock_};
|
|
71
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
72
|
+
}
|
|
33
73
|
return;
|
|
74
|
+
}
|
|
34
75
|
|
|
76
|
+
// Create and populate the scheduler item
|
|
35
77
|
auto item = make_unique<SchedulerItem>();
|
|
36
78
|
item->component = component;
|
|
37
|
-
item->
|
|
38
|
-
item->type =
|
|
39
|
-
item->next_execution_ = now + timeout;
|
|
79
|
+
item->set_name(name_cstr, !is_static_string);
|
|
80
|
+
item->type = type;
|
|
40
81
|
item->callback = std::move(func);
|
|
41
82
|
item->remove = false;
|
|
83
|
+
|
|
84
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
85
|
+
// Special handling for defer() (delay = 0, type = TIMEOUT)
|
|
86
|
+
// ESP8266 and RP2040 are excluded because they don't need thread-safe defer handling
|
|
87
|
+
if (delay == 0 && type == SchedulerItem::TIMEOUT) {
|
|
88
|
+
// Put in defer queue for guaranteed FIFO execution
|
|
89
|
+
LockGuard guard{this->lock_};
|
|
90
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
91
|
+
this->defer_queue_.push_back(std::move(item));
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
#endif
|
|
95
|
+
|
|
96
|
+
const auto now = this->millis_();
|
|
97
|
+
|
|
98
|
+
// Type-specific setup
|
|
99
|
+
if (type == SchedulerItem::INTERVAL) {
|
|
100
|
+
item->interval = delay;
|
|
101
|
+
// Calculate random offset (0 to interval/2)
|
|
102
|
+
uint32_t offset = (delay != 0) ? (random_uint32() % delay) / 2 : 0;
|
|
103
|
+
item->next_execution_ = now + offset;
|
|
104
|
+
} else {
|
|
105
|
+
item->interval = 0;
|
|
106
|
+
item->next_execution_ = now + delay;
|
|
107
|
+
}
|
|
108
|
+
|
|
42
109
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
43
|
-
|
|
110
|
+
// Validate static strings in debug mode
|
|
111
|
+
if (is_static_string && name_cstr != nullptr) {
|
|
112
|
+
validate_static_string(name_cstr);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Debug logging
|
|
116
|
+
const char *type_str = (type == SchedulerItem::TIMEOUT) ? "timeout" : "interval";
|
|
117
|
+
if (type == SchedulerItem::TIMEOUT) {
|
|
118
|
+
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ")", type_str, item->get_source(),
|
|
119
|
+
name_cstr ? name_cstr : "(null)", type_str, delay);
|
|
120
|
+
} else {
|
|
121
|
+
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, item->get_source(),
|
|
122
|
+
name_cstr ? name_cstr : "(null)", type_str, delay, static_cast<uint32_t>(item->next_execution_ - now));
|
|
123
|
+
}
|
|
44
124
|
#endif
|
|
45
|
-
|
|
125
|
+
|
|
126
|
+
LockGuard guard{this->lock_};
|
|
127
|
+
// If name is provided, do atomic cancel-and-add
|
|
128
|
+
if (this->is_name_valid_(name_cstr)) {
|
|
129
|
+
// Cancel existing items
|
|
130
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
131
|
+
}
|
|
132
|
+
// Add new item directly to to_add_
|
|
133
|
+
// since we have the lock held
|
|
134
|
+
this->to_add_.push_back(std::move(item));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void HOT Scheduler::set_timeout(Component *component, const char *name, uint32_t timeout, std::function<void()> func) {
|
|
138
|
+
this->set_timer_common_(component, SchedulerItem::TIMEOUT, true, name, timeout, std::move(func));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
|
|
142
|
+
std::function<void()> func) {
|
|
143
|
+
this->set_timer_common_(component, SchedulerItem::TIMEOUT, false, &name, timeout, std::move(func));
|
|
46
144
|
}
|
|
47
145
|
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
|
|
48
|
-
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
|
|
146
|
+
return this->cancel_item_(component, false, &name, SchedulerItem::TIMEOUT);
|
|
147
|
+
}
|
|
148
|
+
bool HOT Scheduler::cancel_timeout(Component *component, const char *name) {
|
|
149
|
+
return this->cancel_item_(component, true, name, SchedulerItem::TIMEOUT);
|
|
49
150
|
}
|
|
50
151
|
void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval,
|
|
51
152
|
std::function<void()> func) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
if (!name.empty())
|
|
55
|
-
this->cancel_interval(component, name);
|
|
56
|
-
|
|
57
|
-
if (interval == SCHEDULER_DONT_RUN)
|
|
58
|
-
return;
|
|
59
|
-
|
|
60
|
-
// only put offset in lower half
|
|
61
|
-
uint32_t offset = 0;
|
|
62
|
-
if (interval != 0)
|
|
63
|
-
offset = (random_uint32() % interval) / 2;
|
|
153
|
+
this->set_timer_common_(component, SchedulerItem::INTERVAL, false, &name, interval, std::move(func));
|
|
154
|
+
}
|
|
64
155
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
item->type = SchedulerItem::INTERVAL;
|
|
69
|
-
item->interval = interval;
|
|
70
|
-
item->next_execution_ = now + offset;
|
|
71
|
-
item->callback = std::move(func);
|
|
72
|
-
item->remove = false;
|
|
73
|
-
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
74
|
-
ESP_LOGD(TAG, "set_interval(name='%s/%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", item->get_source(),
|
|
75
|
-
name.c_str(), interval, offset);
|
|
76
|
-
#endif
|
|
77
|
-
this->push_(std::move(item));
|
|
156
|
+
void HOT Scheduler::set_interval(Component *component, const char *name, uint32_t interval,
|
|
157
|
+
std::function<void()> func) {
|
|
158
|
+
this->set_timer_common_(component, SchedulerItem::INTERVAL, true, name, interval, std::move(func));
|
|
78
159
|
}
|
|
79
160
|
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
|
|
80
|
-
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
|
161
|
+
return this->cancel_item_(component, false, &name, SchedulerItem::INTERVAL);
|
|
162
|
+
}
|
|
163
|
+
bool HOT Scheduler::cancel_interval(Component *component, const char *name) {
|
|
164
|
+
return this->cancel_item_(component, true, name, SchedulerItem::INTERVAL);
|
|
81
165
|
}
|
|
82
166
|
|
|
83
167
|
struct RetryArgs {
|
|
@@ -85,7 +169,7 @@ struct RetryArgs {
|
|
|
85
169
|
uint8_t retry_countdown;
|
|
86
170
|
uint32_t current_interval;
|
|
87
171
|
Component *component;
|
|
88
|
-
std::string name;
|
|
172
|
+
std::string name; // Keep as std::string since retry uses it dynamically
|
|
89
173
|
float backoff_increase_factor;
|
|
90
174
|
Scheduler *scheduler;
|
|
91
175
|
};
|
|
@@ -136,6 +220,9 @@ bool HOT Scheduler::cancel_retry(Component *component, const std::string &name)
|
|
|
136
220
|
}
|
|
137
221
|
|
|
138
222
|
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
|
223
|
+
// IMPORTANT: This method should only be called from the main thread (loop task).
|
|
224
|
+
// It calls empty_() and accesses items_[0] without holding a lock, which is only
|
|
225
|
+
// safe when called from the main thread. Other threads must not call this method.
|
|
139
226
|
if (this->empty_())
|
|
140
227
|
return {};
|
|
141
228
|
auto &item = this->items_[0];
|
|
@@ -145,6 +232,39 @@ optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
|
|
145
232
|
return item->next_execution_ - now;
|
|
146
233
|
}
|
|
147
234
|
void HOT Scheduler::call() {
|
|
235
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
236
|
+
// Process defer queue first to guarantee FIFO execution order for deferred items.
|
|
237
|
+
// Previously, defer() used the heap which gave undefined order for equal timestamps,
|
|
238
|
+
// causing race conditions on multi-core systems (ESP32, BK7200).
|
|
239
|
+
// With the defer queue:
|
|
240
|
+
// - Deferred items (delay=0) go directly to defer_queue_ in set_timer_common_
|
|
241
|
+
// - Items execute in exact order they were deferred (FIFO guarantee)
|
|
242
|
+
// - No deferred items exist in to_add_, so processing order doesn't affect correctness
|
|
243
|
+
// ESP8266 and RP2040 don't use this queue - they fall back to the heap-based approach
|
|
244
|
+
// (ESP8266: single-core, RP2040: empty mutex implementation).
|
|
245
|
+
//
|
|
246
|
+
// Note: Items cancelled via cancel_item_locked_() are marked with remove=true but still
|
|
247
|
+
// processed here. They are removed from the queue normally via pop_front() but skipped
|
|
248
|
+
// during execution by should_skip_item_(). This is intentional - no memory leak occurs.
|
|
249
|
+
while (!this->defer_queue_.empty()) {
|
|
250
|
+
// The outer check is done without a lock for performance. If the queue
|
|
251
|
+
// appears non-empty, we lock and process an item. We don't need to check
|
|
252
|
+
// empty() again inside the lock because only this thread can remove items.
|
|
253
|
+
std::unique_ptr<SchedulerItem> item;
|
|
254
|
+
{
|
|
255
|
+
LockGuard lock(this->lock_);
|
|
256
|
+
item = std::move(this->defer_queue_.front());
|
|
257
|
+
this->defer_queue_.pop_front();
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Execute callback without holding lock to prevent deadlocks
|
|
261
|
+
// if the callback tries to call defer() again
|
|
262
|
+
if (!this->should_skip_item_(item.get())) {
|
|
263
|
+
this->execute_item_(item.get());
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
#endif
|
|
267
|
+
|
|
148
268
|
const auto now = this->millis_();
|
|
149
269
|
this->process_to_add();
|
|
150
270
|
|
|
@@ -154,16 +274,19 @@ void HOT Scheduler::call() {
|
|
|
154
274
|
if (now - last_print > 2000) {
|
|
155
275
|
last_print = now;
|
|
156
276
|
std::vector<std::unique_ptr<SchedulerItem>> old_items;
|
|
157
|
-
ESP_LOGD(TAG, "Items: count=%
|
|
277
|
+
ESP_LOGD(TAG, "Items: count=%zu, now=%" PRIu64 " (%u, %" PRIu32 ")", this->items_.size(), now, this->millis_major_,
|
|
158
278
|
this->last_millis_);
|
|
159
279
|
while (!this->empty_()) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
280
|
+
std::unique_ptr<SchedulerItem> item;
|
|
281
|
+
{
|
|
282
|
+
LockGuard guard{this->lock_};
|
|
283
|
+
item = std::move(this->items_[0]);
|
|
284
|
+
this->pop_raw_();
|
|
285
|
+
}
|
|
164
286
|
|
|
287
|
+
const char *name = item->get_name();
|
|
165
288
|
ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64,
|
|
166
|
-
item->get_type_str(), item->get_source(),
|
|
289
|
+
item->get_type_str(), item->get_source(), name ? name : "(null)", item->interval,
|
|
167
290
|
item->next_execution_ - now, item->next_execution_);
|
|
168
291
|
|
|
169
292
|
old_items.push_back(std::move(item));
|
|
@@ -173,33 +296,35 @@ void HOT Scheduler::call() {
|
|
|
173
296
|
{
|
|
174
297
|
LockGuard guard{this->lock_};
|
|
175
298
|
this->items_ = std::move(old_items);
|
|
299
|
+
// Rebuild heap after moving items back
|
|
300
|
+
std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
176
301
|
}
|
|
177
302
|
}
|
|
178
303
|
#endif // ESPHOME_DEBUG_SCHEDULER
|
|
179
304
|
|
|
180
|
-
auto to_remove_was = to_remove_;
|
|
181
|
-
auto items_was = this->items_.size();
|
|
182
305
|
// If we have too many items to remove
|
|
183
|
-
if (to_remove_ > MAX_LOGICALLY_DELETED_ITEMS) {
|
|
306
|
+
if (this->to_remove_ > MAX_LOGICALLY_DELETED_ITEMS) {
|
|
307
|
+
// We hold the lock for the entire cleanup operation because:
|
|
308
|
+
// 1. We're rebuilding the entire items_ list, so we need exclusive access throughout
|
|
309
|
+
// 2. Other threads must see either the old state or the new state, not intermediate states
|
|
310
|
+
// 3. The operation is already expensive (O(n)), so lock overhead is negligible
|
|
311
|
+
// 4. No operations inside can block or take other locks, so no deadlock risk
|
|
312
|
+
LockGuard guard{this->lock_};
|
|
313
|
+
|
|
184
314
|
std::vector<std::unique_ptr<SchedulerItem>> valid_items;
|
|
185
|
-
while (!this->empty_()) {
|
|
186
|
-
LockGuard guard{this->lock_};
|
|
187
|
-
auto item = std::move(this->items_[0]);
|
|
188
|
-
this->pop_raw_();
|
|
189
|
-
valid_items.push_back(std::move(item));
|
|
190
|
-
}
|
|
191
315
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
316
|
+
// Move all non-removed items to valid_items
|
|
317
|
+
for (auto &item : this->items_) {
|
|
318
|
+
if (!item->remove) {
|
|
319
|
+
valid_items.push_back(std::move(item));
|
|
320
|
+
}
|
|
195
321
|
}
|
|
196
322
|
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
323
|
+
// Replace items_ with the filtered list
|
|
324
|
+
this->items_ = std::move(valid_items);
|
|
325
|
+
// Rebuild the heap structure since items are no longer in heap order
|
|
326
|
+
std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
327
|
+
this->to_remove_ = 0;
|
|
203
328
|
}
|
|
204
329
|
|
|
205
330
|
while (!this->empty_()) {
|
|
@@ -217,47 +342,39 @@ void HOT Scheduler::call() {
|
|
|
217
342
|
this->pop_raw_();
|
|
218
343
|
continue;
|
|
219
344
|
}
|
|
220
|
-
App.set_current_component(item->component);
|
|
221
|
-
|
|
222
345
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
346
|
+
const char *item_name = item->get_name();
|
|
223
347
|
ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
|
|
224
|
-
item->get_type_str(), item->get_source(),
|
|
225
|
-
now);
|
|
348
|
+
item->get_type_str(), item->get_source(), item_name ? item_name : "(null)", item->interval,
|
|
349
|
+
item->next_execution_, now);
|
|
226
350
|
#endif
|
|
227
351
|
|
|
228
352
|
// Warning: During callback(), a lot of stuff can happen, including:
|
|
229
353
|
// - timeouts/intervals get added, potentially invalidating vector pointers
|
|
230
354
|
// - timeouts/intervals get cancelled
|
|
231
|
-
|
|
232
|
-
uint32_t now_ms = millis();
|
|
233
|
-
WarnIfComponentBlockingGuard guard{item->component, now_ms};
|
|
234
|
-
item->callback();
|
|
235
|
-
// Call finish to ensure blocking time is properly calculated and reported
|
|
236
|
-
guard.finish();
|
|
237
|
-
}
|
|
355
|
+
this->execute_item_(item.get());
|
|
238
356
|
}
|
|
239
357
|
|
|
240
358
|
{
|
|
241
|
-
this->lock_
|
|
359
|
+
LockGuard guard{this->lock_};
|
|
242
360
|
|
|
243
361
|
// new scope, item from before might have been moved in the vector
|
|
244
362
|
auto item = std::move(this->items_[0]);
|
|
245
|
-
|
|
246
363
|
// Only pop after function call, this ensures we were reachable
|
|
247
364
|
// during the function call and know if we were cancelled.
|
|
248
365
|
this->pop_raw_();
|
|
249
366
|
|
|
250
|
-
this->lock_.unlock();
|
|
251
|
-
|
|
252
367
|
if (item->remove) {
|
|
253
368
|
// We were removed/cancelled in the function call, stop
|
|
254
|
-
to_remove_--;
|
|
369
|
+
this->to_remove_--;
|
|
255
370
|
continue;
|
|
256
371
|
}
|
|
257
372
|
|
|
258
373
|
if (item->type == SchedulerItem::INTERVAL) {
|
|
259
374
|
item->next_execution_ = now + item->interval;
|
|
260
|
-
|
|
375
|
+
// Add new item directly to to_add_
|
|
376
|
+
// since we have the lock held
|
|
377
|
+
this->to_add_.push_back(std::move(item));
|
|
261
378
|
}
|
|
262
379
|
}
|
|
263
380
|
}
|
|
@@ -277,55 +394,113 @@ void HOT Scheduler::process_to_add() {
|
|
|
277
394
|
this->to_add_.clear();
|
|
278
395
|
}
|
|
279
396
|
void HOT Scheduler::cleanup_() {
|
|
397
|
+
// Fast path: if nothing to remove, just return
|
|
398
|
+
// Reading to_remove_ without lock is safe because:
|
|
399
|
+
// 1. We only call this from the main thread during call()
|
|
400
|
+
// 2. If it's 0, there's definitely nothing to cleanup
|
|
401
|
+
// 3. If it becomes non-zero after we check, cleanup will happen on the next loop iteration
|
|
402
|
+
// 4. Not all platforms support atomics, so we accept this race in favor of performance
|
|
403
|
+
// 5. The worst case is a one-loop-iteration delay in cleanup, which is harmless
|
|
404
|
+
if (this->to_remove_ == 0)
|
|
405
|
+
return;
|
|
406
|
+
|
|
407
|
+
// We must hold the lock for the entire cleanup operation because:
|
|
408
|
+
// 1. We're modifying items_ (via pop_raw_) which requires exclusive access
|
|
409
|
+
// 2. We're decrementing to_remove_ which is also modified by other threads
|
|
410
|
+
// (though all modifications are already under lock)
|
|
411
|
+
// 3. Other threads read items_ when searching for items to cancel in cancel_item_locked_()
|
|
412
|
+
// 4. We need a consistent view of items_ and to_remove_ throughout the operation
|
|
413
|
+
// Without the lock, we could access items_ while another thread is reading it,
|
|
414
|
+
// leading to race conditions
|
|
415
|
+
LockGuard guard{this->lock_};
|
|
280
416
|
while (!this->items_.empty()) {
|
|
281
417
|
auto &item = this->items_[0];
|
|
282
418
|
if (!item->remove)
|
|
283
419
|
return;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
{
|
|
288
|
-
LockGuard guard{this->lock_};
|
|
289
|
-
this->pop_raw_();
|
|
290
|
-
}
|
|
420
|
+
this->to_remove_--;
|
|
421
|
+
this->pop_raw_();
|
|
291
422
|
}
|
|
292
423
|
}
|
|
293
424
|
void HOT Scheduler::pop_raw_() {
|
|
294
425
|
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
295
426
|
this->items_.pop_back();
|
|
296
427
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
428
|
+
|
|
429
|
+
// Helper to execute a scheduler item
|
|
430
|
+
void HOT Scheduler::execute_item_(SchedulerItem *item) {
|
|
431
|
+
App.set_current_component(item->component);
|
|
432
|
+
|
|
433
|
+
uint32_t now_ms = millis();
|
|
434
|
+
WarnIfComponentBlockingGuard guard{item->component, now_ms};
|
|
435
|
+
item->callback();
|
|
436
|
+
guard.finish();
|
|
300
437
|
}
|
|
301
|
-
|
|
438
|
+
|
|
439
|
+
// Common implementation for cancel operations
|
|
440
|
+
bool HOT Scheduler::cancel_item_(Component *component, bool is_static_string, const void *name_ptr,
|
|
441
|
+
SchedulerItem::Type type) {
|
|
442
|
+
// Get the name as const char*
|
|
443
|
+
const char *name_cstr = this->get_name_cstr_(is_static_string, name_ptr);
|
|
444
|
+
|
|
445
|
+
// Handle null or empty names
|
|
446
|
+
if (!this->is_name_valid_(name_cstr))
|
|
447
|
+
return false;
|
|
448
|
+
|
|
302
449
|
// obtain lock because this function iterates and can be called from non-loop task context
|
|
303
450
|
LockGuard guard{this->lock_};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
451
|
+
return this->cancel_item_locked_(component, name_cstr, type);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Helper to cancel items by name - must be called with lock held
|
|
455
|
+
bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_cstr, SchedulerItem::Type type) {
|
|
456
|
+
size_t total_cancelled = 0;
|
|
457
|
+
|
|
458
|
+
// Check all containers for matching items
|
|
459
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
460
|
+
// Only check defer queue for timeouts (intervals never go there)
|
|
461
|
+
if (type == SchedulerItem::TIMEOUT) {
|
|
462
|
+
for (auto &item : this->defer_queue_) {
|
|
463
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
464
|
+
item->remove = true;
|
|
465
|
+
total_cancelled++;
|
|
466
|
+
}
|
|
310
467
|
}
|
|
311
468
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
469
|
+
#endif
|
|
470
|
+
|
|
471
|
+
// Cancel items in the main heap
|
|
472
|
+
for (auto &item : this->items_) {
|
|
473
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
474
|
+
item->remove = true;
|
|
475
|
+
total_cancelled++;
|
|
476
|
+
this->to_remove_++; // Track removals for heap items
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Cancel items in to_add_
|
|
481
|
+
for (auto &item : this->to_add_) {
|
|
482
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
483
|
+
item->remove = true;
|
|
484
|
+
total_cancelled++;
|
|
485
|
+
// Don't track removals for to_add_ items
|
|
316
486
|
}
|
|
317
487
|
}
|
|
318
488
|
|
|
319
|
-
return
|
|
489
|
+
return total_cancelled > 0;
|
|
320
490
|
}
|
|
491
|
+
|
|
321
492
|
uint64_t Scheduler::millis_() {
|
|
493
|
+
// Get the current 32-bit millis value
|
|
322
494
|
const uint32_t now = millis();
|
|
495
|
+
// Check for rollover by comparing with last value
|
|
323
496
|
if (now < this->last_millis_) {
|
|
497
|
+
// Detected rollover (happens every ~49.7 days)
|
|
324
498
|
this->millis_major_++;
|
|
325
499
|
ESP_LOGD(TAG, "Incrementing scheduler major at %" PRIu64 "ms",
|
|
326
500
|
now + (static_cast<uint64_t>(this->millis_major_) << 32));
|
|
327
501
|
}
|
|
328
502
|
this->last_millis_ = now;
|
|
503
|
+
// Combine major (high 32 bits) and now (low 32 bits) into 64-bit time
|
|
329
504
|
return now + (static_cast<uint64_t>(this->millis_major_) << 32);
|
|
330
505
|
}
|
|
331
506
|
|