esphome 2025.6.3__py3-none-any.whl → 2025.7.0__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 +57 -21
- esphome/components/api/api_connection.cpp +344 -539
- esphome/components/api/api_connection.h +224 -141
- esphome/components/api/api_frame_helper.cpp +91 -127
- esphome/components/api/api_frame_helper.h +64 -54
- esphome/components/api/api_pb2.cpp +1837 -9044
- esphome/components/api/api_pb2.h +532 -685
- esphome/components/api/api_pb2_dump.cpp +4432 -0
- esphome/components/api/api_pb2_service.cpp +184 -425
- esphome/components/api/api_pb2_service.h +13 -6
- esphome/components/api/api_server.cpp +131 -167
- esphome/components/api/api_server.h +38 -10
- esphome/components/api/client.py +8 -2
- esphome/components/api/custom_api_device.h +8 -0
- esphome/components/api/list_entities.cpp +37 -104
- esphome/components/api/list_entities.h +33 -23
- esphome/components/api/proto.h +532 -26
- esphome/components/api/subscribe_state.cpp +23 -29
- esphome/components/api/subscribe_state.h +26 -19
- esphome/components/api/user_services.h +2 -0
- esphome/components/as3935_spi/as3935_spi.h +0 -2
- 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/debug/debug_esp32.cpp +2 -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 +103 -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 +112 -98
- 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 +240 -0
- esphome/components/esp32_touch/esp32_touch_v2.cpp +397 -0
- esphome/components/esp8266/__init__.py +2 -0
- esphome/components/esp8266/gpio.cpp +10 -10
- esphome/components/esp8266/helpers.cpp +31 -0
- esphome/components/esp_ldo/__init__.py +10 -8
- esphome/components/esp_ldo/esp_ldo.h +3 -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/fan/fan.cpp +4 -0
- 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 +39 -1
- 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 +3 -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.h +1 -0
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +35 -16
- 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/__init__.py +1 -1
- 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/json/__init__.py +1 -1
- esphome/components/json/json_util.cpp +56 -63
- 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 +421 -268
- 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/binary_sensor/ld2420_binary_sensor.cpp +2 -2
- esphome/components/ld2420/button/reconfig_buttons.cpp +1 -1
- esphome/components/ld2420/ld2420.cpp +252 -147
- esphome/components/ld2420/ld2420.h +52 -126
- esphome/components/ld2420/number/__init__.py +2 -2
- esphome/components/ld2420/number/gate_config_number.cpp +1 -1
- esphome/components/ld2420/select/operating_mode_select.cpp +1 -1
- esphome/components/ld2420/sensor/__init__.py +6 -2
- esphome/components/ld2420/sensor/ld2420_sensor.cpp +2 -2
- esphome/components/ld2420/sensor/ld2420_sensor.h +1 -1
- esphome/components/ld2420/text_sensor/text_sensor.cpp +2 -2
- 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 +5 -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_json_schema.cpp +17 -16
- 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/lvgl/widgets/meter.py +20 -13
- 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_alarm_control_panel.cpp +2 -1
- esphome/components/mqtt/mqtt_backend.h +2 -1
- esphome/components/mqtt/mqtt_backend_esp32.cpp +132 -47
- esphome/components/mqtt/mqtt_backend_esp32.h +106 -4
- esphome/components/mqtt/mqtt_binary_sensor.cpp +1 -0
- esphome/components/mqtt/mqtt_button.cpp +4 -1
- esphome/components/mqtt/mqtt_client.cpp +17 -9
- esphome/components/mqtt/mqtt_client.h +8 -3
- esphome/components/mqtt/mqtt_climate.cpp +6 -4
- esphome/components/mqtt/mqtt_component.cpp +3 -1
- esphome/components/mqtt/mqtt_cover.cpp +1 -0
- esphome/components/mqtt/mqtt_date.cpp +4 -3
- esphome/components/mqtt/mqtt_datetime.cpp +7 -6
- esphome/components/mqtt/mqtt_event.cpp +6 -3
- esphome/components/mqtt/mqtt_fan.cpp +1 -0
- esphome/components/mqtt/mqtt_light.cpp +8 -4
- esphome/components/mqtt/mqtt_lock.cpp +3 -1
- esphome/components/mqtt/mqtt_number.cpp +1 -0
- esphome/components/mqtt/mqtt_select.cpp +2 -1
- esphome/components/mqtt/mqtt_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_switch.cpp +3 -1
- esphome/components/mqtt/mqtt_text.cpp +1 -0
- esphome/components/mqtt/mqtt_text_sensor.cpp +3 -1
- esphome/components/mqtt/mqtt_time.cpp +4 -3
- esphome/components/mqtt/mqtt_update.cpp +1 -0
- esphome/components/mqtt/mqtt_valve.cpp +3 -1
- esphome/components/ms8607/ms8607.cpp +1 -1
- 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 +9 -1
- esphome/components/online_image/online_image.cpp +17 -7
- esphome/components/online_image/online_image.h +10 -2
- esphome/components/opentherm/opentherm.cpp +7 -12
- esphome/components/opentherm/output/output.cpp +1 -1
- 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 +34 -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 +2 -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.cpp +2 -2
- 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 +81 -21
- 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 +0 -4
- 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/usb_host/usb_host_client.cpp +10 -10
- esphome/components/usb_uart/cp210x.cpp +1 -1
- esphome/components/usb_uart/usb_uart.cpp +41 -44
- esphome/components/usb_uart/usb_uart.h +4 -3
- 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 +318 -436
- 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 +164 -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 +169 -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 +156 -22
- esphome/core/component.h +98 -4
- esphome/core/component_iterator.cpp +11 -9
- esphome/core/component_iterator.h +12 -10
- 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 +168 -1
- esphome/core/event_pool.h +81 -0
- esphome/core/helpers.cpp +75 -230
- esphome/core/helpers.h +165 -105
- 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 +275 -103
- esphome/core/scheduler.h +154 -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/platformio_api.py +2 -0
- esphome/wizard.py +17 -4
- esphome/writer.py +44 -3
- esphome/yaml_util.py +0 -2
- {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/METADATA +10 -9
- {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/RECORD +637 -578
- esphome/components/api/api_pb2_size.h +0 -361
- 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.3.dist-info → esphome-2025.7.0.dist-info}/WHEEL +0 -0
- {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/entry_points.txt +0 -0
- {esphome-2025.6.3.dist-info → esphome-2025.7.0.dist-info}/licenses/LICENSE +0 -0
- {esphome-2025.6.3.dist-info → esphome-2025.7.0.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,146 @@ 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
|
+
LockGuard guard{this->lock_};
|
|
70
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
33
71
|
return;
|
|
72
|
+
}
|
|
34
73
|
|
|
74
|
+
// Create and populate the scheduler item
|
|
35
75
|
auto item = make_unique<SchedulerItem>();
|
|
36
76
|
item->component = component;
|
|
37
|
-
item->
|
|
38
|
-
item->type =
|
|
39
|
-
item->next_execution_ = now + timeout;
|
|
77
|
+
item->set_name(name_cstr, !is_static_string);
|
|
78
|
+
item->type = type;
|
|
40
79
|
item->callback = std::move(func);
|
|
41
80
|
item->remove = false;
|
|
81
|
+
|
|
82
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
83
|
+
// Special handling for defer() (delay = 0, type = TIMEOUT)
|
|
84
|
+
// ESP8266 and RP2040 are excluded because they don't need thread-safe defer handling
|
|
85
|
+
if (delay == 0 && type == SchedulerItem::TIMEOUT) {
|
|
86
|
+
// Put in defer queue for guaranteed FIFO execution
|
|
87
|
+
LockGuard guard{this->lock_};
|
|
88
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
89
|
+
this->defer_queue_.push_back(std::move(item));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
#endif
|
|
93
|
+
|
|
94
|
+
const auto now = this->millis_();
|
|
95
|
+
|
|
96
|
+
// Type-specific setup
|
|
97
|
+
if (type == SchedulerItem::INTERVAL) {
|
|
98
|
+
item->interval = delay;
|
|
99
|
+
// Calculate random offset (0 to interval/2)
|
|
100
|
+
uint32_t offset = (delay != 0) ? (random_uint32() % delay) / 2 : 0;
|
|
101
|
+
item->next_execution_ = now + offset;
|
|
102
|
+
} else {
|
|
103
|
+
item->interval = 0;
|
|
104
|
+
item->next_execution_ = now + delay;
|
|
105
|
+
}
|
|
106
|
+
|
|
42
107
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
43
|
-
|
|
108
|
+
// Validate static strings in debug mode
|
|
109
|
+
if (is_static_string && name_cstr != nullptr) {
|
|
110
|
+
validate_static_string(name_cstr);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Debug logging
|
|
114
|
+
const char *type_str = (type == SchedulerItem::TIMEOUT) ? "timeout" : "interval";
|
|
115
|
+
if (type == SchedulerItem::TIMEOUT) {
|
|
116
|
+
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ")", type_str, item->get_source(),
|
|
117
|
+
name_cstr ? name_cstr : "(null)", type_str, delay);
|
|
118
|
+
} else {
|
|
119
|
+
ESP_LOGD(TAG, "set_%s(name='%s/%s', %s=%" PRIu32 ", offset=%" PRIu32 ")", type_str, item->get_source(),
|
|
120
|
+
name_cstr ? name_cstr : "(null)", type_str, delay, static_cast<uint32_t>(item->next_execution_ - now));
|
|
121
|
+
}
|
|
44
122
|
#endif
|
|
45
|
-
|
|
123
|
+
|
|
124
|
+
LockGuard guard{this->lock_};
|
|
125
|
+
// If name is provided, do atomic cancel-and-add
|
|
126
|
+
// Cancel existing items
|
|
127
|
+
this->cancel_item_locked_(component, name_cstr, type);
|
|
128
|
+
// Add new item directly to to_add_
|
|
129
|
+
// since we have the lock held
|
|
130
|
+
this->to_add_.push_back(std::move(item));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
void HOT Scheduler::set_timeout(Component *component, const char *name, uint32_t timeout, std::function<void()> func) {
|
|
134
|
+
this->set_timer_common_(component, SchedulerItem::TIMEOUT, true, name, timeout, std::move(func));
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
|
|
138
|
+
std::function<void()> func) {
|
|
139
|
+
this->set_timer_common_(component, SchedulerItem::TIMEOUT, false, &name, timeout, std::move(func));
|
|
46
140
|
}
|
|
47
141
|
bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
|
|
48
|
-
return this->cancel_item_(component, name, SchedulerItem::TIMEOUT);
|
|
142
|
+
return this->cancel_item_(component, false, &name, SchedulerItem::TIMEOUT);
|
|
143
|
+
}
|
|
144
|
+
bool HOT Scheduler::cancel_timeout(Component *component, const char *name) {
|
|
145
|
+
return this->cancel_item_(component, true, name, SchedulerItem::TIMEOUT);
|
|
49
146
|
}
|
|
50
147
|
void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval,
|
|
51
148
|
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;
|
|
149
|
+
this->set_timer_common_(component, SchedulerItem::INTERVAL, false, &name, interval, std::move(func));
|
|
150
|
+
}
|
|
64
151
|
|
|
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));
|
|
152
|
+
void HOT Scheduler::set_interval(Component *component, const char *name, uint32_t interval,
|
|
153
|
+
std::function<void()> func) {
|
|
154
|
+
this->set_timer_common_(component, SchedulerItem::INTERVAL, true, name, interval, std::move(func));
|
|
78
155
|
}
|
|
79
156
|
bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
|
|
80
|
-
return this->cancel_item_(component, name, SchedulerItem::INTERVAL);
|
|
157
|
+
return this->cancel_item_(component, false, &name, SchedulerItem::INTERVAL);
|
|
158
|
+
}
|
|
159
|
+
bool HOT Scheduler::cancel_interval(Component *component, const char *name) {
|
|
160
|
+
return this->cancel_item_(component, true, name, SchedulerItem::INTERVAL);
|
|
81
161
|
}
|
|
82
162
|
|
|
83
163
|
struct RetryArgs {
|
|
@@ -85,7 +165,7 @@ struct RetryArgs {
|
|
|
85
165
|
uint8_t retry_countdown;
|
|
86
166
|
uint32_t current_interval;
|
|
87
167
|
Component *component;
|
|
88
|
-
std::string name;
|
|
168
|
+
std::string name; // Keep as std::string since retry uses it dynamically
|
|
89
169
|
float backoff_increase_factor;
|
|
90
170
|
Scheduler *scheduler;
|
|
91
171
|
};
|
|
@@ -136,6 +216,9 @@ bool HOT Scheduler::cancel_retry(Component *component, const std::string &name)
|
|
|
136
216
|
}
|
|
137
217
|
|
|
138
218
|
optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
|
219
|
+
// IMPORTANT: This method should only be called from the main thread (loop task).
|
|
220
|
+
// It calls empty_() and accesses items_[0] without holding a lock, which is only
|
|
221
|
+
// safe when called from the main thread. Other threads must not call this method.
|
|
139
222
|
if (this->empty_())
|
|
140
223
|
return {};
|
|
141
224
|
auto &item = this->items_[0];
|
|
@@ -145,6 +228,39 @@ optional<uint32_t> HOT Scheduler::next_schedule_in() {
|
|
|
145
228
|
return item->next_execution_ - now;
|
|
146
229
|
}
|
|
147
230
|
void HOT Scheduler::call() {
|
|
231
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
232
|
+
// Process defer queue first to guarantee FIFO execution order for deferred items.
|
|
233
|
+
// Previously, defer() used the heap which gave undefined order for equal timestamps,
|
|
234
|
+
// causing race conditions on multi-core systems (ESP32, BK7200).
|
|
235
|
+
// With the defer queue:
|
|
236
|
+
// - Deferred items (delay=0) go directly to defer_queue_ in set_timer_common_
|
|
237
|
+
// - Items execute in exact order they were deferred (FIFO guarantee)
|
|
238
|
+
// - No deferred items exist in to_add_, so processing order doesn't affect correctness
|
|
239
|
+
// ESP8266 and RP2040 don't use this queue - they fall back to the heap-based approach
|
|
240
|
+
// (ESP8266: single-core, RP2040: empty mutex implementation).
|
|
241
|
+
//
|
|
242
|
+
// Note: Items cancelled via cancel_item_locked_() are marked with remove=true but still
|
|
243
|
+
// processed here. They are removed from the queue normally via pop_front() but skipped
|
|
244
|
+
// during execution by should_skip_item_(). This is intentional - no memory leak occurs.
|
|
245
|
+
while (!this->defer_queue_.empty()) {
|
|
246
|
+
// The outer check is done without a lock for performance. If the queue
|
|
247
|
+
// appears non-empty, we lock and process an item. We don't need to check
|
|
248
|
+
// empty() again inside the lock because only this thread can remove items.
|
|
249
|
+
std::unique_ptr<SchedulerItem> item;
|
|
250
|
+
{
|
|
251
|
+
LockGuard lock(this->lock_);
|
|
252
|
+
item = std::move(this->defer_queue_.front());
|
|
253
|
+
this->defer_queue_.pop_front();
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Execute callback without holding lock to prevent deadlocks
|
|
257
|
+
// if the callback tries to call defer() again
|
|
258
|
+
if (!this->should_skip_item_(item.get())) {
|
|
259
|
+
this->execute_item_(item.get());
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
#endif
|
|
263
|
+
|
|
148
264
|
const auto now = this->millis_();
|
|
149
265
|
this->process_to_add();
|
|
150
266
|
|
|
@@ -154,16 +270,19 @@ void HOT Scheduler::call() {
|
|
|
154
270
|
if (now - last_print > 2000) {
|
|
155
271
|
last_print = now;
|
|
156
272
|
std::vector<std::unique_ptr<SchedulerItem>> old_items;
|
|
157
|
-
ESP_LOGD(TAG, "Items: count=%
|
|
273
|
+
ESP_LOGD(TAG, "Items: count=%zu, now=%" PRIu64 " (%u, %" PRIu32 ")", this->items_.size(), now, this->millis_major_,
|
|
158
274
|
this->last_millis_);
|
|
159
275
|
while (!this->empty_()) {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
276
|
+
std::unique_ptr<SchedulerItem> item;
|
|
277
|
+
{
|
|
278
|
+
LockGuard guard{this->lock_};
|
|
279
|
+
item = std::move(this->items_[0]);
|
|
280
|
+
this->pop_raw_();
|
|
281
|
+
}
|
|
164
282
|
|
|
283
|
+
const char *name = item->get_name();
|
|
165
284
|
ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64,
|
|
166
|
-
item->get_type_str(), item->get_source(),
|
|
285
|
+
item->get_type_str(), item->get_source(), name ? name : "(null)", item->interval,
|
|
167
286
|
item->next_execution_ - now, item->next_execution_);
|
|
168
287
|
|
|
169
288
|
old_items.push_back(std::move(item));
|
|
@@ -173,33 +292,35 @@ void HOT Scheduler::call() {
|
|
|
173
292
|
{
|
|
174
293
|
LockGuard guard{this->lock_};
|
|
175
294
|
this->items_ = std::move(old_items);
|
|
295
|
+
// Rebuild heap after moving items back
|
|
296
|
+
std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
176
297
|
}
|
|
177
298
|
}
|
|
178
299
|
#endif // ESPHOME_DEBUG_SCHEDULER
|
|
179
300
|
|
|
180
|
-
auto to_remove_was = to_remove_;
|
|
181
|
-
auto items_was = this->items_.size();
|
|
182
301
|
// If we have too many items to remove
|
|
183
|
-
if (to_remove_ > MAX_LOGICALLY_DELETED_ITEMS) {
|
|
302
|
+
if (this->to_remove_ > MAX_LOGICALLY_DELETED_ITEMS) {
|
|
303
|
+
// We hold the lock for the entire cleanup operation because:
|
|
304
|
+
// 1. We're rebuilding the entire items_ list, so we need exclusive access throughout
|
|
305
|
+
// 2. Other threads must see either the old state or the new state, not intermediate states
|
|
306
|
+
// 3. The operation is already expensive (O(n)), so lock overhead is negligible
|
|
307
|
+
// 4. No operations inside can block or take other locks, so no deadlock risk
|
|
308
|
+
LockGuard guard{this->lock_};
|
|
309
|
+
|
|
184
310
|
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
311
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
312
|
+
// Move all non-removed items to valid_items
|
|
313
|
+
for (auto &item : this->items_) {
|
|
314
|
+
if (!item->remove) {
|
|
315
|
+
valid_items.push_back(std::move(item));
|
|
316
|
+
}
|
|
195
317
|
}
|
|
196
318
|
|
|
197
|
-
//
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
319
|
+
// Replace items_ with the filtered list
|
|
320
|
+
this->items_ = std::move(valid_items);
|
|
321
|
+
// Rebuild the heap structure since items are no longer in heap order
|
|
322
|
+
std::make_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
323
|
+
this->to_remove_ = 0;
|
|
203
324
|
}
|
|
204
325
|
|
|
205
326
|
while (!this->empty_()) {
|
|
@@ -217,47 +338,39 @@ void HOT Scheduler::call() {
|
|
|
217
338
|
this->pop_raw_();
|
|
218
339
|
continue;
|
|
219
340
|
}
|
|
220
|
-
App.set_current_component(item->component);
|
|
221
|
-
|
|
222
341
|
#ifdef ESPHOME_DEBUG_SCHEDULER
|
|
342
|
+
const char *item_name = item->get_name();
|
|
223
343
|
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);
|
|
344
|
+
item->get_type_str(), item->get_source(), item_name ? item_name : "(null)", item->interval,
|
|
345
|
+
item->next_execution_, now);
|
|
226
346
|
#endif
|
|
227
347
|
|
|
228
348
|
// Warning: During callback(), a lot of stuff can happen, including:
|
|
229
349
|
// - timeouts/intervals get added, potentially invalidating vector pointers
|
|
230
350
|
// - 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
|
-
}
|
|
351
|
+
this->execute_item_(item.get());
|
|
238
352
|
}
|
|
239
353
|
|
|
240
354
|
{
|
|
241
|
-
this->lock_
|
|
355
|
+
LockGuard guard{this->lock_};
|
|
242
356
|
|
|
243
357
|
// new scope, item from before might have been moved in the vector
|
|
244
358
|
auto item = std::move(this->items_[0]);
|
|
245
|
-
|
|
246
359
|
// Only pop after function call, this ensures we were reachable
|
|
247
360
|
// during the function call and know if we were cancelled.
|
|
248
361
|
this->pop_raw_();
|
|
249
362
|
|
|
250
|
-
this->lock_.unlock();
|
|
251
|
-
|
|
252
363
|
if (item->remove) {
|
|
253
364
|
// We were removed/cancelled in the function call, stop
|
|
254
|
-
to_remove_--;
|
|
365
|
+
this->to_remove_--;
|
|
255
366
|
continue;
|
|
256
367
|
}
|
|
257
368
|
|
|
258
369
|
if (item->type == SchedulerItem::INTERVAL) {
|
|
259
370
|
item->next_execution_ = now + item->interval;
|
|
260
|
-
|
|
371
|
+
// Add new item directly to to_add_
|
|
372
|
+
// since we have the lock held
|
|
373
|
+
this->to_add_.push_back(std::move(item));
|
|
261
374
|
}
|
|
262
375
|
}
|
|
263
376
|
}
|
|
@@ -277,55 +390,114 @@ void HOT Scheduler::process_to_add() {
|
|
|
277
390
|
this->to_add_.clear();
|
|
278
391
|
}
|
|
279
392
|
void HOT Scheduler::cleanup_() {
|
|
393
|
+
// Fast path: if nothing to remove, just return
|
|
394
|
+
// Reading to_remove_ without lock is safe because:
|
|
395
|
+
// 1. We only call this from the main thread during call()
|
|
396
|
+
// 2. If it's 0, there's definitely nothing to cleanup
|
|
397
|
+
// 3. If it becomes non-zero after we check, cleanup will happen on the next loop iteration
|
|
398
|
+
// 4. Not all platforms support atomics, so we accept this race in favor of performance
|
|
399
|
+
// 5. The worst case is a one-loop-iteration delay in cleanup, which is harmless
|
|
400
|
+
if (this->to_remove_ == 0)
|
|
401
|
+
return;
|
|
402
|
+
|
|
403
|
+
// We must hold the lock for the entire cleanup operation because:
|
|
404
|
+
// 1. We're modifying items_ (via pop_raw_) which requires exclusive access
|
|
405
|
+
// 2. We're decrementing to_remove_ which is also modified by other threads
|
|
406
|
+
// (though all modifications are already under lock)
|
|
407
|
+
// 3. Other threads read items_ when searching for items to cancel in cancel_item_locked_()
|
|
408
|
+
// 4. We need a consistent view of items_ and to_remove_ throughout the operation
|
|
409
|
+
// Without the lock, we could access items_ while another thread is reading it,
|
|
410
|
+
// leading to race conditions
|
|
411
|
+
LockGuard guard{this->lock_};
|
|
280
412
|
while (!this->items_.empty()) {
|
|
281
413
|
auto &item = this->items_[0];
|
|
282
414
|
if (!item->remove)
|
|
283
415
|
return;
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
{
|
|
288
|
-
LockGuard guard{this->lock_};
|
|
289
|
-
this->pop_raw_();
|
|
290
|
-
}
|
|
416
|
+
this->to_remove_--;
|
|
417
|
+
this->pop_raw_();
|
|
291
418
|
}
|
|
292
419
|
}
|
|
293
420
|
void HOT Scheduler::pop_raw_() {
|
|
294
421
|
std::pop_heap(this->items_.begin(), this->items_.end(), SchedulerItem::cmp);
|
|
295
422
|
this->items_.pop_back();
|
|
296
423
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
424
|
+
|
|
425
|
+
// Helper to execute a scheduler item
|
|
426
|
+
void HOT Scheduler::execute_item_(SchedulerItem *item) {
|
|
427
|
+
App.set_current_component(item->component);
|
|
428
|
+
|
|
429
|
+
uint32_t now_ms = millis();
|
|
430
|
+
WarnIfComponentBlockingGuard guard{item->component, now_ms};
|
|
431
|
+
item->callback();
|
|
432
|
+
guard.finish();
|
|
300
433
|
}
|
|
301
|
-
|
|
434
|
+
|
|
435
|
+
// Common implementation for cancel operations
|
|
436
|
+
bool HOT Scheduler::cancel_item_(Component *component, bool is_static_string, const void *name_ptr,
|
|
437
|
+
SchedulerItem::Type type) {
|
|
438
|
+
// Get the name as const char*
|
|
439
|
+
const char *name_cstr = this->get_name_cstr_(is_static_string, name_ptr);
|
|
440
|
+
|
|
302
441
|
// obtain lock because this function iterates and can be called from non-loop task context
|
|
303
442
|
LockGuard guard{this->lock_};
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
443
|
+
return this->cancel_item_locked_(component, name_cstr, type);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// Helper to cancel items by name - must be called with lock held
|
|
447
|
+
bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_cstr, SchedulerItem::Type type) {
|
|
448
|
+
// Early return if name is invalid - no items to cancel
|
|
449
|
+
if (name_cstr == nullptr || name_cstr[0] == '\0') {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
size_t total_cancelled = 0;
|
|
454
|
+
|
|
455
|
+
// Check all containers for matching items
|
|
456
|
+
#if !defined(USE_ESP8266) && !defined(USE_RP2040)
|
|
457
|
+
// Only check defer queue for timeouts (intervals never go there)
|
|
458
|
+
if (type == SchedulerItem::TIMEOUT) {
|
|
459
|
+
for (auto &item : this->defer_queue_) {
|
|
460
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
461
|
+
item->remove = true;
|
|
462
|
+
total_cancelled++;
|
|
463
|
+
}
|
|
310
464
|
}
|
|
311
465
|
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
466
|
+
#endif
|
|
467
|
+
|
|
468
|
+
// Cancel items in the main heap
|
|
469
|
+
for (auto &item : this->items_) {
|
|
470
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
471
|
+
item->remove = true;
|
|
472
|
+
total_cancelled++;
|
|
473
|
+
this->to_remove_++; // Track removals for heap items
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Cancel items in to_add_
|
|
478
|
+
for (auto &item : this->to_add_) {
|
|
479
|
+
if (this->matches_item_(item, component, name_cstr, type)) {
|
|
480
|
+
item->remove = true;
|
|
481
|
+
total_cancelled++;
|
|
482
|
+
// Don't track removals for to_add_ items
|
|
316
483
|
}
|
|
317
484
|
}
|
|
318
485
|
|
|
319
|
-
return
|
|
486
|
+
return total_cancelled > 0;
|
|
320
487
|
}
|
|
488
|
+
|
|
321
489
|
uint64_t Scheduler::millis_() {
|
|
490
|
+
// Get the current 32-bit millis value
|
|
322
491
|
const uint32_t now = millis();
|
|
492
|
+
// Check for rollover by comparing with last value
|
|
323
493
|
if (now < this->last_millis_) {
|
|
494
|
+
// Detected rollover (happens every ~49.7 days)
|
|
324
495
|
this->millis_major_++;
|
|
325
496
|
ESP_LOGD(TAG, "Incrementing scheduler major at %" PRIu64 "ms",
|
|
326
497
|
now + (static_cast<uint64_t>(this->millis_major_) << 32));
|
|
327
498
|
}
|
|
328
499
|
this->last_millis_ = now;
|
|
500
|
+
// Combine major (high 32 bits) and now (low 32 bits) into 64-bit time
|
|
329
501
|
return now + (static_cast<uint64_t>(this->millis_major_) << 32);
|
|
330
502
|
}
|
|
331
503
|
|