esphome 2025.3.3__py3-none-any.whl → 2025.4.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.
Files changed (713) hide show
  1. esphome/__main__.py +34 -10
  2. esphome/components/a01nyub/sensor.py +2 -2
  3. esphome/components/a02yyuw/sensor.py +2 -2
  4. esphome/components/a4988/stepper.py +1 -2
  5. esphome/components/absolute_humidity/sensor.py +3 -3
  6. esphome/components/ac_dimmer/output.py +3 -3
  7. esphome/components/adalight/__init__.py +2 -2
  8. esphome/components/adc128s102/__init__.py +1 -1
  9. esphome/components/adc128s102/sensor/__init__.py +3 -3
  10. esphome/components/addressable_light/display.py +5 -5
  11. esphome/components/ade7880/sensor.py +2 -2
  12. esphome/components/ade7953_base/__init__.py +10 -10
  13. esphome/components/ade7953_i2c/sensor.py +1 -2
  14. esphome/components/ade7953_spi/sensor.py +1 -2
  15. esphome/components/ads1115/__init__.py +1 -1
  16. esphome/components/ads1115/sensor/__init__.py +4 -3
  17. esphome/components/ads1118/__init__.py +1 -1
  18. esphome/components/ads1118/sensor/__init__.py +5 -4
  19. esphome/components/ags10/sensor.py +9 -9
  20. esphome/components/aht10/sensor.py +2 -2
  21. esphome/components/airthings_ble/__init__.py +1 -1
  22. esphome/components/airthings_wave_base/__init__.py +2 -3
  23. esphome/components/airthings_wave_mini/sensor.py +2 -5
  24. esphome/components/airthings_wave_plus/sensor.py +8 -9
  25. esphome/components/alpha3/sensor.py +5 -5
  26. esphome/components/am2315c/am2315c.cpp +4 -4
  27. esphome/components/am2315c/sensor.py +1 -1
  28. esphome/components/am2320/sensor.py +1 -1
  29. esphome/components/am43/cover/__init__.py +1 -1
  30. esphome/components/am43/sensor/__init__.py +3 -3
  31. esphome/components/analog_threshold/binary_sensor.py +2 -5
  32. esphome/components/anova/climate.py +1 -1
  33. esphome/components/apds9306/sensor.py +1 -1
  34. esphome/components/apds9960/__init__.py +1 -1
  35. esphome/components/apds9960/binary_sensor.py +2 -1
  36. esphome/components/apds9960/sensor.py +3 -2
  37. esphome/components/api/api_frame_helper.cpp +25 -1
  38. esphome/components/as3935/__init__.py +3 -3
  39. esphome/components/as3935/binary_sensor.py +2 -1
  40. esphome/components/as3935/sensor.py +4 -3
  41. esphome/components/as3935_i2c/__init__.py +1 -1
  42. esphome/components/as3935_spi/__init__.py +1 -1
  43. esphome/components/as5600/__init__.py +2 -2
  44. esphome/components/as5600/sensor/__init__.py +10 -9
  45. esphome/components/as7341/sensor.py +1 -2
  46. esphome/components/at581x/__init__.py +4 -8
  47. esphome/components/at581x/switch/__init__.py +2 -4
  48. esphome/components/atc_mithermometer/sensor.py +3 -3
  49. esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +7 -3
  50. esphome/components/b_parasite/sensor.py +2 -2
  51. esphome/components/ballu/climate.py +1 -1
  52. esphome/components/bang_bang/climate.py +2 -2
  53. esphome/components/bedjet/__init__.py +2 -6
  54. esphome/components/bedjet/climate/__init__.py +3 -6
  55. esphome/components/bedjet/fan/__init__.py +4 -9
  56. esphome/components/bedjet/sensor/__init__.py +3 -6
  57. esphome/components/beken_spi_led_strip/light.py +2 -2
  58. esphome/components/bh1750/sensor.py +2 -6
  59. esphome/components/binary/fan/__init__.py +2 -1
  60. esphome/components/binary/light/__init__.py +3 -2
  61. esphome/components/binary_sensor_map/sensor.py +5 -6
  62. esphome/components/bl0939/sensor.py +1 -1
  63. esphome/components/bl0940/sensor.py +3 -3
  64. esphome/components/ble_client/__init__.py +3 -2
  65. esphome/components/ble_client/sensor/__init__.py +1 -1
  66. esphome/components/ble_client/text_sensor/__init__.py +1 -1
  67. esphome/components/bluetooth_proxy/__init__.py +35 -23
  68. esphome/components/bme280_base/__init__.py +1 -1
  69. esphome/components/bme280_i2c/sensor.py +3 -2
  70. esphome/components/bme280_spi/sensor.py +3 -2
  71. esphome/components/bme680/sensor.py +4 -4
  72. esphome/components/bme680_bsec/__init__.py +1 -1
  73. esphome/components/bme680_bsec/sensor.py +3 -6
  74. esphome/components/bme680_bsec/text_sensor.py +3 -2
  75. esphome/components/bmi160/sensor.py +6 -6
  76. esphome/components/bmp085/sensor.py +1 -1
  77. esphome/components/bmp280_base/__init__.py +1 -1
  78. esphome/components/bmp280_i2c/sensor.py +3 -2
  79. esphome/components/bmp280_spi/sensor.py +3 -2
  80. esphome/components/bmp3xx_base/__init__.py +1 -1
  81. esphome/components/bmp3xx_i2c/sensor.py +2 -1
  82. esphome/components/bmp3xx_spi/sensor.py +2 -1
  83. esphome/components/bmp581/sensor.py +2 -1
  84. esphome/components/bp1658cj/__init__.py +2 -6
  85. esphome/components/bp1658cj/output.py +2 -1
  86. esphome/components/bp5758d/__init__.py +2 -6
  87. esphome/components/bp5758d/output.py +3 -2
  88. esphome/components/canbus/__init__.py +13 -2
  89. esphome/components/canbus/canbus.cpp +7 -1
  90. esphome/components/cap1188/__init__.py +2 -2
  91. esphome/components/cap1188/binary_sensor.py +3 -2
  92. esphome/components/captive_portal/__init__.py +3 -3
  93. esphome/components/ccs811/sensor.py +10 -10
  94. esphome/components/cd74hc4067/__init__.py +2 -5
  95. esphome/components/cd74hc4067/sensor.py +6 -5
  96. esphome/components/climate_ir/__init__.py +2 -2
  97. esphome/components/climate_ir_lg/climate.py +1 -1
  98. esphome/components/color/__init__.py +1 -2
  99. esphome/components/color_temperature/light.py +2 -2
  100. esphome/components/combination/sensor.py +1 -1
  101. esphome/components/coolix/climate.py +1 -1
  102. esphome/components/copy/binary_sensor/__init__.py +1 -1
  103. esphome/components/copy/button/__init__.py +1 -1
  104. esphome/components/copy/cover/__init__.py +1 -1
  105. esphome/components/copy/fan/__init__.py +2 -7
  106. esphome/components/copy/lock/__init__.py +2 -7
  107. esphome/components/copy/number/__init__.py +1 -1
  108. esphome/components/copy/select/__init__.py +2 -7
  109. esphome/components/copy/sensor/__init__.py +2 -2
  110. esphome/components/copy/switch/__init__.py +1 -1
  111. esphome/components/copy/text/__init__.py +2 -7
  112. esphome/components/copy/text_sensor/__init__.py +2 -6
  113. esphome/components/cs5460a/sensor.py +7 -7
  114. esphome/components/cse7761/sensor.py +2 -2
  115. esphome/components/cse7766/sensor.py +1 -1
  116. esphome/components/cst226/touchscreen/__init__.py +3 -4
  117. esphome/components/ct_clamp/sensor.py +1 -1
  118. esphome/components/current_based/cover.py +3 -4
  119. esphome/components/cwww/light.py +3 -3
  120. esphome/components/dac7678/__init__.py +1 -1
  121. esphome/components/dac7678/output.py +2 -1
  122. esphome/components/daikin/climate.py +1 -1
  123. esphome/components/daikin_arc/climate.py +1 -1
  124. esphome/components/daikin_brc/climate.py +1 -1
  125. esphome/components/dallas_temp/sensor.py +1 -1
  126. esphome/components/daly_bms/__init__.py +2 -2
  127. esphome/components/daly_bms/binary_sensor.py +3 -2
  128. esphome/components/daly_bms/sensor.py +14 -13
  129. esphome/components/daly_bms/text_sensor.py +3 -2
  130. esphome/components/dashboard_import/__init__.py +5 -5
  131. esphome/components/debug/sensor.py +7 -6
  132. esphome/components/debug/text_sensor.py +1 -1
  133. esphome/components/deep_sleep/__init__.py +12 -13
  134. esphome/components/delonghi/climate.py +1 -1
  135. esphome/components/demo/__init__.py +1 -1
  136. esphome/components/dfplayer/__init__.py +3 -3
  137. esphome/components/dfrobot_sen0395/__init__.py +3 -3
  138. esphome/components/dfrobot_sen0395/binary_sensor.py +2 -1
  139. esphome/components/dfrobot_sen0395/switch/__init__.py +2 -3
  140. esphome/components/dht/sensor.py +4 -5
  141. esphome/components/dht12/sensor.py +3 -3
  142. esphome/components/dps310/sensor.py +3 -3
  143. esphome/components/ds1307/time.py +2 -3
  144. esphome/components/dsmr/__init__.py +3 -7
  145. esphome/components/dsmr/sensor.py +5 -4
  146. esphome/components/dsmr/text_sensor.py +3 -2
  147. esphome/components/duty_cycle/sensor.py +3 -8
  148. esphome/components/duty_time/sensor.py +7 -7
  149. esphome/components/e131/__init__.py +3 -3
  150. esphome/components/ee895/sensor.py +5 -5
  151. esphome/components/ektf2232/touchscreen/__init__.py +2 -3
  152. esphome/components/emc2101/__init__.py +1 -1
  153. esphome/components/emc2101/output/__init__.py +3 -2
  154. esphome/components/emc2101/sensor/__init__.py +4 -3
  155. esphome/components/emmeti/climate.py +1 -1
  156. esphome/components/endstop/cover.py +3 -3
  157. esphome/components/ens160_base/__init__.py +1 -1
  158. esphome/components/ens160_i2c/sensor.py +2 -1
  159. esphome/components/ens160_spi/sensor.py +2 -1
  160. esphome/components/ens210/sensor.py +1 -1
  161. esphome/components/esp32/__init__.py +10 -0
  162. esphome/components/esp32_ble_tracker/__init__.py +135 -51
  163. esphome/components/esp32_camera/__init__.py +7 -8
  164. esphome/components/esp32_camera_web_server/__init__.py +2 -2
  165. esphome/components/esp32_can/canbus.py +21 -0
  166. esphome/components/esp32_can/esp32_can.cpp +1 -1
  167. esphome/components/esp32_can/esp32_can.h +4 -0
  168. esphome/components/esp32_dac/output.py +2 -2
  169. esphome/components/esp32_hall/sensor.py +2 -6
  170. esphome/components/esp32_touch/__init__.py +7 -7
  171. esphome/components/esp32_touch/binary_sensor.py +4 -7
  172. esphome/components/esp8266_pwm/output.py +3 -8
  173. esphome/components/ethernet/__init__.py +1 -0
  174. esphome/components/ethernet/ethernet_component.cpp +1 -1
  175. esphome/components/ethernet_info/ethernet_info_text_sensor.h +1 -0
  176. esphome/components/exposure_notifications/__init__.py +2 -2
  177. esphome/components/external_components/__init__.py +1 -1
  178. esphome/components/ezo/sensor.py +2 -2
  179. esphome/components/ezo_pmp/__init__.py +4 -4
  180. esphome/components/ezo_pmp/binary_sensor.py +4 -4
  181. esphome/components/ezo_pmp/sensor.py +4 -5
  182. esphome/components/ezo_pmp/text_sensor.py +2 -6
  183. esphome/components/factory_reset/button/__init__.py +2 -1
  184. esphome/components/factory_reset/switch/__init__.py +3 -2
  185. esphome/components/fastled_base/__init__.py +3 -3
  186. esphome/components/fastled_clockless/light.py +2 -2
  187. esphome/components/fastled_spi/light.py +2 -2
  188. esphome/components/feedback/cover.py +3 -3
  189. esphome/components/fingerprint_grow/__init__.py +5 -6
  190. esphome/components/fingerprint_grow/binary_sensor.py +2 -1
  191. esphome/components/fingerprint_grow/sensor.py +2 -1
  192. esphome/components/fs3000/sensor.py +2 -6
  193. esphome/components/ft5x06/touchscreen/__init__.py +2 -2
  194. esphome/components/ft63x6/touchscreen.py +2 -3
  195. esphome/components/fujitsu_general/climate.py +1 -1
  196. esphome/components/gcja5/sensor.py +4 -4
  197. esphome/components/gdk101/__init__.py +1 -1
  198. esphome/components/gdk101/binary_sensor.py +2 -1
  199. esphome/components/gdk101/sensor.py +5 -4
  200. esphome/components/globals/__init__.py +1 -2
  201. esphome/components/gp2y1010au0f/sensor.py +3 -3
  202. esphome/components/gp8403/__init__.py +1 -2
  203. esphome/components/gp8403/output/__init__.py +3 -4
  204. esphome/components/gpio/binary_sensor/__init__.py +3 -2
  205. esphome/components/gpio/one_wire/__init__.py +3 -2
  206. esphome/components/gpio/output/__init__.py +3 -2
  207. esphome/components/gpio/switch/__init__.py +3 -2
  208. esphome/components/gps/__init__.py +4 -5
  209. esphome/components/gps/time/__init__.py +3 -2
  210. esphome/components/graph/__init__.py +12 -12
  211. esphome/components/grove_tb6612fng/__init__.py +5 -6
  212. esphome/components/growatt_solar/sensor.py +1 -1
  213. esphome/components/gt911/binary_sensor/__init__.py +2 -2
  214. esphome/components/haier/binary_sensor/__init__.py +4 -10
  215. esphome/components/haier/button/__init__.py +3 -6
  216. esphome/components/haier/sensor/__init__.py +4 -6
  217. esphome/components/haier/switch/__init__.py +4 -7
  218. esphome/components/haier/text_sensor/__init__.py +4 -9
  219. esphome/components/havells_solar/sensor.py +1 -1
  220. esphome/components/hbridge/fan/__init__.py +6 -6
  221. esphome/components/hbridge/light/__init__.py +2 -1
  222. esphome/components/hdc1080/sensor.py +1 -1
  223. esphome/components/he60r/cover.py +2 -6
  224. esphome/components/heatpumpir/climate.py +1 -1
  225. esphome/components/hitachi_ac344/climate.py +1 -1
  226. esphome/components/hitachi_ac424/climate.py +1 -1
  227. esphome/components/hlw8012/sensor.py +6 -6
  228. esphome/components/hm3301/sensor.py +3 -3
  229. esphome/components/hmc5883l/sensor.py +4 -4
  230. esphome/components/homeassistant/time/__init__.py +2 -1
  231. esphome/components/honeywell_hih_i2c/sensor.py +3 -3
  232. esphome/components/honeywellabp/sensor.py +1 -2
  233. esphome/components/honeywellabp2_i2c/sensor.py +1 -2
  234. esphome/components/host/time/__init__.py +2 -2
  235. esphome/components/hrxl_maxsonar_wr/sensor.py +1 -1
  236. esphome/components/hte501/sensor.py +3 -3
  237. esphome/components/http_request/ota/__init__.py +5 -9
  238. esphome/components/http_request/update/__init__.py +3 -7
  239. esphome/components/htu21d/sensor.py +6 -6
  240. esphome/components/htu31d/sensor.py +1 -1
  241. esphome/components/hx711/sensor.py +3 -8
  242. esphome/components/hydreon_rgxx/binary_sensor.py +3 -7
  243. esphome/components/hydreon_rgxx/sensor.py +4 -4
  244. esphome/components/hyt271/sensor.py +1 -1
  245. esphome/components/i2c_device/__init__.py +1 -1
  246. esphome/components/i2s_audio/media_player/__init__.py +6 -8
  247. esphome/components/iaqcore/sensor.py +2 -2
  248. esphome/components/ina219/sensor.py +2 -2
  249. esphome/components/ina226/sensor.py +4 -4
  250. esphome/components/ina260/sensor.py +4 -4
  251. esphome/components/ina2xx_base/__init__.py +2 -2
  252. esphome/components/ina2xx_i2c/sensor.py +1 -1
  253. esphome/components/ina2xx_spi/sensor.py +1 -1
  254. esphome/components/ina3221/sensor.py +3 -3
  255. esphome/components/inkbird_ibsth1_mini/sensor.py +2 -2
  256. esphome/components/inkplate6/display.py +2 -2
  257. esphome/components/integration/sensor.py +4 -4
  258. esphome/components/internal_temperature/sensor.py +5 -7
  259. esphome/components/interval/__init__.py +1 -1
  260. esphome/components/jsn_sr04t/sensor.py +3 -3
  261. esphome/components/kamstrup_kmp/sensor.py +1 -1
  262. esphome/components/key_collector/__init__.py +2 -2
  263. esphome/components/kmeteriso/sensor.py +2 -2
  264. esphome/components/kuntze/sensor.py +5 -5
  265. esphome/components/lcd_base/__init__.py +2 -2
  266. esphome/components/lcd_gpio/display.py +4 -4
  267. esphome/components/lcd_menu/__init__.py +3 -7
  268. esphome/components/lcd_pcf8574/display.py +1 -1
  269. esphome/components/ld2410/__init__.py +4 -4
  270. esphome/components/ld2410/binary_sensor.py +5 -4
  271. esphome/components/ld2410/button/__init__.py +3 -2
  272. esphome/components/ld2410/number/__init__.py +5 -4
  273. esphome/components/ld2410/select/__init__.py +4 -3
  274. esphome/components/ld2410/sensor.py +6 -5
  275. esphome/components/ld2410/switch/__init__.py +2 -1
  276. esphome/components/ld2410/text_sensor.py +3 -2
  277. esphome/components/ld2420/__init__.py +1 -1
  278. esphome/components/ld2420/binary_sensor/__init__.py +4 -3
  279. esphome/components/ld2420/button/__init__.py +3 -2
  280. esphome/components/ld2420/number/__init__.py +3 -2
  281. esphome/components/ld2420/select/__init__.py +1 -0
  282. esphome/components/ld2420/sensor/__init__.py +3 -2
  283. esphome/components/ld2420/text_sensor/__init__.py +2 -6
  284. esphome/components/ld2450/__init__.py +2 -5
  285. esphome/components/ledc/output.py +3 -3
  286. esphome/components/libretiny/text_sensor.py +1 -1
  287. esphome/components/libretiny_pwm/output.py +3 -7
  288. esphome/components/lightwaverf/__init__.py +6 -8
  289. esphome/components/lilygo_t5_47/touchscreen/__init__.py +2 -3
  290. esphome/components/ltr390/sensor.py +1 -1
  291. esphome/components/ltr501/sensor.py +2 -2
  292. esphome/components/ltr_als_ps/sensor.py +2 -2
  293. esphome/components/lvgl/__init__.py +9 -12
  294. esphome/components/lvgl/automation.py +15 -3
  295. esphome/components/lvgl/defines.py +5 -2
  296. esphome/components/lvgl/encoders.py +3 -2
  297. esphome/components/lvgl/lv_validation.py +17 -9
  298. esphome/components/lvgl/lvcode.py +11 -9
  299. esphome/components/lvgl/lvgl_esphome.h +21 -0
  300. esphome/components/lvgl/number/__init__.py +23 -20
  301. esphome/components/lvgl/number/lvgl_number.h +27 -14
  302. esphome/components/lvgl/schemas.py +70 -19
  303. esphome/components/lvgl/select/__init__.py +11 -13
  304. esphome/components/lvgl/select/lvgl_select.h +25 -18
  305. esphome/components/lvgl/styles.py +42 -11
  306. esphome/components/lvgl/trigger.py +10 -1
  307. esphome/components/lvgl/widgets/__init__.py +1 -2
  308. esphome/components/lvgl/widgets/buttonmatrix.py +2 -2
  309. esphome/components/lvgl/widgets/canvas.py +407 -0
  310. esphome/components/lvgl/widgets/line.py +22 -32
  311. esphome/components/lvgl/widgets/meter.py +3 -1
  312. esphome/components/m5stack_8angle/__init__.py +1 -2
  313. esphome/components/m5stack_8angle/binary_sensor/__init__.py +2 -3
  314. esphome/components/m5stack_8angle/light/__init__.py +2 -4
  315. esphome/components/m5stack_8angle/sensor/__init__.py +2 -4
  316. esphome/components/matrix_keypad/binary_sensor/__init__.py +4 -3
  317. esphome/components/max31855/sensor.py +1 -1
  318. esphome/components/max31865/sensor.py +1 -1
  319. esphome/components/max44009/sensor.py +1 -1
  320. esphome/components/max6675/sensor.py +1 -1
  321. esphome/components/max6956/__init__.py +5 -5
  322. esphome/components/max6956/output/__init__.py +4 -3
  323. esphome/components/max7219/display.py +1 -1
  324. esphome/components/max7219digit/display.py +1 -1
  325. esphome/components/max9611/sensor.py +10 -10
  326. esphome/components/mcp23008/__init__.py +1 -1
  327. esphome/components/mcp23016/__init__.py +4 -4
  328. esphome/components/mcp23017/__init__.py +1 -1
  329. esphome/components/mcp23s08/__init__.py +1 -1
  330. esphome/components/mcp23s17/__init__.py +1 -1
  331. esphome/components/mcp23xxx_base/__init__.py +4 -4
  332. esphome/components/mcp2515/canbus.py +2 -2
  333. esphome/components/mcp3008/__init__.py +1 -1
  334. esphome/components/mcp3008/sensor/__init__.py +4 -4
  335. esphome/components/mcp3204/__init__.py +1 -1
  336. esphome/components/mcp3204/sensor/__init__.py +3 -2
  337. esphome/components/mcp4461/__init__.py +42 -0
  338. esphome/components/mcp4461/mcp4461.cpp +618 -0
  339. esphome/components/mcp4461/mcp4461.h +171 -0
  340. esphome/components/mcp4461/output/__init__.py +60 -0
  341. esphome/components/mcp4461/output/mcp4461_output.cpp +73 -0
  342. esphome/components/mcp4461/output/mcp4461_output.h +49 -0
  343. esphome/components/mcp4725/output.py +2 -2
  344. esphome/components/mcp4728/__init__.py +1 -1
  345. esphome/components/mcp4728/output/__init__.py +4 -3
  346. esphome/components/mcp47a1/output.py +2 -2
  347. esphome/components/mcp9808/sensor.py +1 -1
  348. esphome/components/mhz19/sensor.py +4 -4
  349. esphome/components/micronova/__init__.py +3 -5
  350. esphome/components/micronova/button/__init__.py +5 -5
  351. esphome/components/micronova/number/__init__.py +6 -10
  352. esphome/components/micronova/sensor/__init__.py +6 -6
  353. esphome/components/micronova/switch/__init__.py +6 -8
  354. esphome/components/micronova/text_sensor/__init__.py +5 -5
  355. esphome/components/microphone/__init__.py +2 -4
  356. esphome/components/midea/climate.py +6 -10
  357. esphome/components/midea_ir/climate.py +1 -1
  358. esphome/components/mitsubishi/climate.py +1 -1
  359. esphome/components/mlx90614/sensor.py +1 -1
  360. esphome/components/mmc5603/sensor.py +4 -4
  361. esphome/components/mmc5983/sensor.py +1 -1
  362. esphome/components/modbus/__init__.py +5 -9
  363. esphome/components/modbus_controller/__init__.py +1 -1
  364. esphome/components/monochromatic/light.py +2 -2
  365. esphome/components/mopeka_ble/__init__.py +1 -1
  366. esphome/components/mopeka_pro_check/sensor.py +12 -12
  367. esphome/components/mopeka_std_check/sensor.py +8 -8
  368. esphome/components/mpl3115a2/sensor.py +1 -1
  369. esphome/components/mpr121/__init__.py +3 -3
  370. esphome/components/mpr121/binary_sensor/__init__.py +5 -4
  371. esphome/components/mpu6050/sensor.py +4 -4
  372. esphome/components/mpu6886/sensor.py +4 -4
  373. esphome/components/mqtt_subscribe/sensor/__init__.py +3 -5
  374. esphome/components/mqtt_subscribe/text_sensor/__init__.py +1 -1
  375. esphome/components/ms5611/sensor.py +2 -2
  376. esphome/components/ms8607/sensor.py +1 -1
  377. esphome/components/my9231/__init__.py +1 -1
  378. esphome/components/my9231/output.py +2 -1
  379. esphome/components/nau7802/nau7802.cpp +0 -4
  380. esphome/components/nau7802/nau7802.h +0 -2
  381. esphome/components/neopixelbus/_methods.py +11 -9
  382. esphome/components/neopixelbus/light.py +11 -18
  383. esphome/components/nextion/binary_sensor/__init__.py +6 -14
  384. esphome/components/nextion/sensor/__init__.py +7 -10
  385. esphome/components/nextion/switch/__init__.py +3 -5
  386. esphome/components/nextion/text_sensor/__init__.py +3 -7
  387. esphome/components/noblex/climate.py +1 -1
  388. esphome/components/ntc/sensor.py +1 -1
  389. esphome/components/opentherm/__init__.py +6 -6
  390. esphome/components/opentherm/input.py +2 -1
  391. esphome/components/opentherm/number/__init__.py +5 -4
  392. esphome/components/opentherm/output/__init__.py +3 -2
  393. esphome/components/opentherm/schema.py +7 -7
  394. esphome/components/opentherm/switch/__init__.py +3 -2
  395. esphome/components/opentherm/validate.py +1 -1
  396. esphome/components/output/__init__.py +2 -3
  397. esphome/components/output/button/__init__.py +3 -2
  398. esphome/components/output/lock/__init__.py +2 -1
  399. esphome/components/output/switch/__init__.py +2 -1
  400. esphome/components/partition/light.py +4 -4
  401. esphome/components/pca6416a/__init__.py +4 -4
  402. esphome/components/pca9554/__init__.py +4 -4
  403. esphome/components/pca9685/__init__.py +2 -2
  404. esphome/components/pca9685/output.py +2 -1
  405. esphome/components/pcf85063/time.py +2 -3
  406. esphome/components/pcf8563/time.py +2 -2
  407. esphome/components/pcf8574/__init__.py +4 -4
  408. esphome/components/pid/climate.py +2 -2
  409. esphome/components/pid/sensor/__init__.py +4 -8
  410. esphome/components/pipsolar/__init__.py +1 -1
  411. esphome/components/pipsolar/binary_sensor/__init__.py +2 -2
  412. esphome/components/pipsolar/output/__init__.py +4 -3
  413. esphome/components/pipsolar/sensor/__init__.py +5 -4
  414. esphome/components/pipsolar/switch/__init__.py +2 -1
  415. esphome/components/pipsolar/text_sensor/__init__.py +2 -1
  416. esphome/components/pm1006/sensor.py +2 -2
  417. esphome/components/pmsa003i/sensor.py +4 -4
  418. esphome/components/pmsx003/sensor.py +10 -11
  419. esphome/components/pmwcs3/sensor.py +5 -5
  420. esphome/components/pn532/__init__.py +3 -3
  421. esphome/components/pn532_i2c/__init__.py +1 -1
  422. esphome/components/pn532_spi/__init__.py +1 -1
  423. esphome/components/pn7150/__init__.py +2 -2
  424. esphome/components/pn7150_i2c/__init__.py +1 -1
  425. esphome/components/pn7160/__init__.py +2 -2
  426. esphome/components/pn7160_i2c/__init__.py +1 -1
  427. esphome/components/pn7160_spi/__init__.py +1 -1
  428. esphome/components/power_supply/__init__.py +1 -1
  429. esphome/components/prometheus/__init__.py +3 -8
  430. esphome/components/psram/__init__.py +75 -11
  431. esphome/components/psram/psram.cpp +18 -7
  432. esphome/components/pulse_counter/sensor.py +4 -4
  433. esphome/components/pulse_meter/sensor.py +3 -3
  434. esphome/components/pulse_width/sensor.py +3 -8
  435. esphome/components/pvvx_mithermometer/display/__init__.py +1 -1
  436. esphome/components/pvvx_mithermometer/sensor.py +3 -3
  437. esphome/components/pylontech/__init__.py +1 -0
  438. esphome/components/pylontech/sensor/__init__.py +8 -13
  439. esphome/components/pylontech/text_sensor/__init__.py +2 -7
  440. esphome/components/pzem004t/sensor.py +3 -3
  441. esphome/components/pzemac/sensor.py +9 -9
  442. esphome/components/pzemdc/sensor.py +6 -6
  443. esphome/components/qmc5883l/sensor.py +5 -5
  444. esphome/components/qmp6988/sensor.py +3 -3
  445. esphome/components/qr_code/__init__.py +1 -1
  446. esphome/components/qspi_dbi/display.py +1 -1
  447. esphome/components/qspi_dbi/qspi_dbi.cpp +1 -1
  448. esphome/components/qspi_dbi/qspi_dbi.h +1 -1
  449. esphome/components/qwiic_pir/binary_sensor.py +2 -5
  450. esphome/components/radon_eye_ble/__init__.py +1 -1
  451. esphome/components/radon_eye_rd200/sensor.py +3 -4
  452. esphome/components/rc522/__init__.py +3 -3
  453. esphome/components/rc522_i2c/__init__.py +1 -1
  454. esphome/components/rc522_spi/__init__.py +1 -1
  455. esphome/components/rdm6300/__init__.py +2 -2
  456. esphome/components/rdm6300/binary_sensor.py +2 -1
  457. esphome/components/resistance/sensor.py +2 -2
  458. esphome/components/restart/button/__init__.py +1 -1
  459. esphome/components/restart/switch/__init__.py +2 -5
  460. esphome/components/rf_bridge/__init__.py +3 -3
  461. esphome/components/rgb/light.py +2 -2
  462. esphome/components/rgbct/light.py +3 -3
  463. esphome/components/rgbw/light.py +2 -2
  464. esphome/components/rgbww/light.py +4 -4
  465. esphome/components/rotary_encoder/sensor.py +8 -8
  466. esphome/components/rp2040_pio/__init__.py +0 -1
  467. esphome/components/rp2040_pio_led_strip/light.py +2 -4
  468. esphome/components/rp2040_pwm/output.py +3 -7
  469. esphome/components/rtttl/__init__.py +6 -6
  470. esphome/components/ruuvi_ble/__init__.py +1 -1
  471. esphome/components/ruuvitag/sensor.py +15 -15
  472. esphome/components/safe_mode/__init__.py +2 -3
  473. esphome/components/safe_mode/button/__init__.py +3 -2
  474. esphome/components/safe_mode/switch/__init__.py +4 -7
  475. esphome/components/scd30/sensor.py +5 -6
  476. esphome/components/scd4x/sensor.py +6 -8
  477. esphome/components/script/__init__.py +2 -2
  478. esphome/components/sdl/display.py +3 -3
  479. esphome/components/sdl/touchscreen/__init__.py +2 -2
  480. esphome/components/sdm_meter/sensor.py +3 -3
  481. esphome/components/sdp3x/sensor.py +1 -2
  482. esphome/components/sds011/sensor.py +4 -4
  483. esphome/components/seeed_mr24hpc1/__init__.py +1 -1
  484. esphome/components/seeed_mr24hpc1/binary_sensor.py +2 -5
  485. esphome/components/seeed_mr24hpc1/button/__init__.py +1 -0
  486. esphome/components/seeed_mr24hpc1/number/__init__.py +2 -4
  487. esphome/components/seeed_mr24hpc1/select/__init__.py +2 -3
  488. esphome/components/seeed_mr24hpc1/sensor.py +1 -0
  489. esphome/components/seeed_mr24hpc1/switch/__init__.py +2 -4
  490. esphome/components/seeed_mr24hpc1/text_sensor.py +1 -0
  491. esphome/components/seeed_mr60bha2/binary_sensor.py +2 -4
  492. esphome/components/seeed_mr60bha2/sensor.py +1 -1
  493. esphome/components/seeed_mr60fda2/button/__init__.py +1 -1
  494. esphome/components/seeed_mr60fda2/select/__init__.py +0 -1
  495. esphome/components/selec_meter/sensor.py +1 -1
  496. esphome/components/sen0321/sensor.py +2 -2
  497. esphome/components/sen21231/sensor.py +1 -1
  498. esphome/components/senseair/sensor.py +3 -3
  499. esphome/components/sensirion_common/__init__.py +0 -2
  500. esphome/components/servo/__init__.py +3 -3
  501. esphome/components/sfa30/sensor.py +4 -5
  502. esphome/components/sgp4x/sensor.py +2 -2
  503. esphome/components/shelly_dimmer/light.py +16 -16
  504. esphome/components/sht3xd/sensor.py +1 -1
  505. esphome/components/sht4x/sensor.py +6 -6
  506. esphome/components/shtcx/sensor.py +1 -1
  507. esphome/components/shutdown/button/__init__.py +2 -6
  508. esphome/components/shutdown/switch/__init__.py +2 -5
  509. esphome/components/sigma_delta_output/output.py +2 -7
  510. esphome/components/sim800l/__init__.py +3 -7
  511. esphome/components/sim800l/binary_sensor.py +3 -5
  512. esphome/components/sim800l/sensor.py +2 -1
  513. esphome/components/slow_pwm/output.py +4 -5
  514. esphome/components/sm10bit_base/__init__.py +2 -6
  515. esphome/components/sm16716/__init__.py +1 -1
  516. esphome/components/sm16716/output.py +2 -1
  517. esphome/components/sm2135/__init__.py +2 -6
  518. esphome/components/sm2135/output.py +2 -1
  519. esphome/components/sm2235/__init__.py +1 -1
  520. esphome/components/sm2235/output.py +2 -1
  521. esphome/components/sm2335/__init__.py +1 -1
  522. esphome/components/sm2335/output.py +2 -1
  523. esphome/components/sm300d2/sensor.py +13 -13
  524. esphome/components/sml/__init__.py +1 -1
  525. esphome/components/sml/sensor/__init__.py +1 -1
  526. esphome/components/sml/sml.cpp +8 -6
  527. esphome/components/sml/sml.h +1 -1
  528. esphome/components/sml/sml_parser.cpp +16 -18
  529. esphome/components/sml/sml_parser.h +42 -12
  530. esphome/components/sml/text_sensor/__init__.py +1 -1
  531. esphome/components/smt100/sensor.py +5 -6
  532. esphome/components/sn74hc165/__init__.py +5 -5
  533. esphome/components/sn74hc595/__init__.py +5 -5
  534. esphome/components/socket/__init__.py +1 -1
  535. esphome/components/sonoff_d1/light.py +2 -6
  536. esphome/components/speaker/media_player/audio_pipeline.cpp +3 -2
  537. esphome/components/speed/fan/__init__.py +2 -2
  538. esphome/components/spi/__init__.py +45 -36
  539. esphome/components/spi/spi.h +1 -0
  540. esphome/components/spi/spi_esp_idf.cpp +13 -5
  541. esphome/components/sprinkler/__init__.py +4 -5
  542. esphome/components/sps30/sensor.py +8 -8
  543. esphome/components/ssd1306_i2c/display.py +2 -2
  544. esphome/components/ssd1322_base/__init__.py +2 -2
  545. esphome/components/ssd1325_base/__init__.py +2 -2
  546. esphome/components/ssd1327_base/__init__.py +2 -2
  547. esphome/components/ssd1327_i2c/display.py +1 -1
  548. esphome/components/ssd1331_base/__init__.py +2 -2
  549. esphome/components/ssd1351_base/__init__.py +2 -2
  550. esphome/components/st7567_base/__init__.py +4 -4
  551. esphome/components/st7567_i2c/display.py +1 -1
  552. esphome/components/st7920/display.py +2 -2
  553. esphome/components/statsd/__init__.py +3 -3
  554. esphome/components/status/binary_sensor.py +2 -5
  555. esphome/components/status_led/__init__.py +1 -1
  556. esphome/components/status_led/light/__init__.py +2 -1
  557. esphome/components/stepper/__init__.py +2 -2
  558. esphome/components/sts3x/sensor.py +1 -1
  559. esphome/components/substitutions/__init__.py +2 -2
  560. esphome/components/sun/__init__.py +4 -4
  561. esphome/components/sun/sensor/__init__.py +4 -7
  562. esphome/components/sun/text_sensor/__init__.py +5 -4
  563. esphome/components/sun_gtil2/__init__.py +1 -1
  564. esphome/components/sun_gtil2/sensor.py +7 -6
  565. esphome/components/sun_gtil2/text_sensor.py +3 -2
  566. esphome/components/sx1509/__init__.py +5 -5
  567. esphome/components/sx1509/binary_sensor/__init__.py +3 -3
  568. esphome/components/sx1509/output/__init__.py +4 -3
  569. esphome/components/t6615/sensor.py +1 -1
  570. esphome/components/tca9548a/__init__.py +1 -1
  571. esphome/components/tcl112/climate.py +1 -1
  572. esphome/components/tcs34725/sensor.py +4 -4
  573. esphome/components/tee501/sensor.py +1 -1
  574. esphome/components/teleinfo/__init__.py +1 -1
  575. esphome/components/teleinfo/sensor/__init__.py +1 -7
  576. esphome/components/teleinfo/text_sensor/__init__.py +1 -1
  577. esphome/components/tem3200/sensor.py +1 -2
  578. esphome/components/template/alarm_control_panel/__init__.py +3 -10
  579. esphome/components/template/cover/__init__.py +4 -3
  580. esphome/components/template/datetime/__init__.py +8 -9
  581. esphome/components/template/event/__init__.py +2 -5
  582. esphome/components/template/fan/__init__.py +2 -6
  583. esphome/components/template/lock/__init__.py +3 -2
  584. esphome/components/template/number/__init__.py +3 -2
  585. esphome/components/template/output/__init__.py +4 -3
  586. esphome/components/template/select/__init__.py +3 -2
  587. esphome/components/template/sensor/__init__.py +4 -7
  588. esphome/components/template/switch/__init__.py +3 -2
  589. esphome/components/template/text/__init__.py +4 -3
  590. esphome/components/template/text_sensor/__init__.py +3 -2
  591. esphome/components/template/valve/__init__.py +3 -2
  592. esphome/components/time/real_time_clock.cpp +0 -4
  593. esphome/components/time/real_time_clock.h +4 -3
  594. esphome/components/time_based/cover.py +3 -3
  595. esphome/components/tlc59208f/__init__.py +1 -1
  596. esphome/components/tlc59208f/output.py +2 -1
  597. esphome/components/tlc5947/__init__.py +1 -1
  598. esphome/components/tlc5947/output/__init__.py +2 -1
  599. esphome/components/tlc5971/__init__.py +2 -8
  600. esphome/components/tlc5971/output/__init__.py +2 -1
  601. esphome/components/tm1621/display.py +3 -3
  602. esphome/components/tm1637/binary_sensor.py +1 -1
  603. esphome/components/tm1637/display.py +3 -3
  604. esphome/components/tm1651/__init__.py +4 -4
  605. esphome/components/tmp102/sensor.py +1 -1
  606. esphome/components/tmp1075/sensor.py +2 -2
  607. esphome/components/tmp117/sensor.py +1 -1
  608. esphome/components/tof10120/sensor.py +2 -2
  609. esphome/components/tormatic/cover.py +2 -6
  610. esphome/components/toshiba/climate.py +1 -1
  611. esphome/components/total_daily_energy/sensor.py +4 -4
  612. esphome/components/tsl2561/sensor.py +1 -1
  613. esphome/components/tsl2591/sensor.py +9 -9
  614. esphome/components/tt21100/binary_sensor/__init__.py +2 -2
  615. esphome/components/tt21100/touchscreen/__init__.py +2 -3
  616. esphome/components/ttp229_bsf/__init__.py +2 -2
  617. esphome/components/ttp229_bsf/binary_sensor.py +3 -2
  618. esphome/components/ttp229_lsf/__init__.py +1 -1
  619. esphome/components/ttp229_lsf/binary_sensor.py +3 -2
  620. esphome/components/tuya/__init__.py +3 -5
  621. esphome/components/tuya/binary_sensor/__init__.py +2 -2
  622. esphome/components/tuya/climate/__init__.py +6 -5
  623. esphome/components/tuya/cover/__init__.py +5 -4
  624. esphome/components/tuya/fan/__init__.py +3 -2
  625. esphome/components/tuya/light/__init__.py +9 -8
  626. esphome/components/tuya/number/__init__.py +6 -5
  627. esphome/components/tuya/select/__init__.py +4 -3
  628. esphome/components/tuya/sensor/__init__.py +3 -2
  629. esphome/components/tuya/switch/__init__.py +3 -2
  630. esphome/components/tuya/text_sensor/__init__.py +3 -2
  631. esphome/components/tx20/sensor.py +6 -6
  632. esphome/components/uart/__init__.py +20 -19
  633. esphome/components/uart/button/__init__.py +2 -1
  634. esphome/components/uart/switch/__init__.py +2 -1
  635. esphome/components/ufire_ise/sensor.py +2 -2
  636. esphome/components/uln2003/stepper.py +2 -2
  637. esphome/components/ultrasonic/sensor.py +4 -4
  638. esphome/components/uponor_smatrix/__init__.py +2 -6
  639. esphome/components/uponor_smatrix/climate/__init__.py +3 -3
  640. esphome/components/vbus/__init__.py +1 -1
  641. esphome/components/vbus/binary_sensor/__init__.py +7 -6
  642. esphome/components/vbus/sensor/__init__.py +7 -6
  643. esphome/components/veml3235/sensor.py +1 -1
  644. esphome/components/veml7700/sensor.py +1 -1
  645. esphome/components/version/text_sensor.py +2 -6
  646. esphome/components/vl53l0x/sensor.py +6 -6
  647. esphome/components/web_server_base/__init__.py +2 -2
  648. esphome/components/web_server_idf/__init__.py +1 -1
  649. esphome/components/weikai/__init__.py +1 -1
  650. esphome/components/whirlpool/climate.py +1 -1
  651. esphome/components/whynter/climate.py +1 -1
  652. esphome/components/wireguard/binary_sensor.py +1 -1
  653. esphome/components/wireguard/sensor.py +2 -5
  654. esphome/components/wireguard/text_sensor.py +2 -5
  655. esphome/components/wk2132_i2c/__init__.py +1 -1
  656. esphome/components/wk2132_spi/__init__.py +1 -2
  657. esphome/components/wk2168_i2c/__init__.py +3 -8
  658. esphome/components/wk2168_spi/__init__.py +3 -8
  659. esphome/components/wk2204_i2c/__init__.py +1 -1
  660. esphome/components/wk2204_spi/__init__.py +1 -1
  661. esphome/components/wk2212_i2c/__init__.py +3 -8
  662. esphome/components/wk2212_spi/__init__.py +3 -8
  663. esphome/components/wl_134/text_sensor.py +2 -4
  664. esphome/components/wled/__init__.py +2 -2
  665. esphome/components/x9c/output.py +4 -4
  666. esphome/components/xgzp68xx/sensor.py +5 -5
  667. esphome/components/xiaomi_ble/__init__.py +1 -1
  668. esphome/components/xiaomi_cgd1/sensor.py +3 -3
  669. esphome/components/xiaomi_cgdk2/sensor.py +3 -3
  670. esphome/components/xiaomi_cgg1/sensor.py +2 -2
  671. esphome/components/xiaomi_cgpr1/binary_sensor.py +6 -6
  672. esphome/components/xiaomi_gcls002/sensor.py +7 -7
  673. esphome/components/xiaomi_hhccjcy01/sensor.py +9 -9
  674. esphome/components/xiaomi_hhccjcy10/sensor.py +9 -9
  675. esphome/components/xiaomi_hhccpot002/sensor.py +7 -7
  676. esphome/components/xiaomi_jqjcy01ym/sensor.py +6 -6
  677. esphome/components/xiaomi_lywsd02/sensor.py +4 -4
  678. esphome/components/xiaomi_lywsd02mmc/sensor.py +5 -5
  679. esphome/components/xiaomi_lywsd03mmc/sensor.py +6 -6
  680. esphome/components/xiaomi_lywsdcgq/sensor.py +5 -5
  681. esphome/components/xiaomi_mhoc303/sensor.py +4 -4
  682. esphome/components/xiaomi_mhoc401/sensor.py +6 -6
  683. esphome/components/xiaomi_miscale/sensor.py +6 -6
  684. esphome/components/xiaomi_mjyd02yla/binary_sensor.py +8 -8
  685. esphome/components/xiaomi_mue4094rt/binary_sensor.py +2 -7
  686. esphome/components/xiaomi_rtcgq02lm/__init__.py +2 -3
  687. esphome/components/xiaomi_rtcgq02lm/binary_sensor.py +3 -3
  688. esphome/components/xiaomi_rtcgq02lm/sensor.py +3 -3
  689. esphome/components/xiaomi_wx08zm/binary_sensor.py +2 -3
  690. esphome/components/xl9535/__init__.py +2 -2
  691. esphome/components/yashima/climate.py +1 -1
  692. esphome/components/zhlt01/climate.py +1 -1
  693. esphome/components/zio_ultrasonic/sensor.py +2 -5
  694. esphome/components/zyaura/sensor.py +7 -7
  695. esphome/config_validation.py +0 -42
  696. esphome/const.py +3 -1
  697. esphome/core/__init__.py +0 -1
  698. esphome/core/component.cpp +3 -1
  699. esphome/core/component.h +15 -2
  700. esphome/core/config.py +4 -0
  701. esphome/core/defines.h +21 -0
  702. esphome/core/helpers.cpp +6 -7
  703. esphome/core/scheduler.cpp +34 -67
  704. esphome/core/scheduler.h +7 -17
  705. esphome/dashboard/status/mqtt.py +0 -2
  706. esphome/vscode.py +27 -8
  707. esphome/yaml_util.py +75 -39
  708. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/METADATA +45 -44
  709. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/RECORD +713 -706
  710. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/WHEEL +1 -1
  711. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/entry_points.txt +0 -0
  712. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info/licenses}/LICENSE +0 -0
  713. {esphome-2025.3.3.dist-info → esphome-2025.4.0.dist-info}/top_level.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  #include "scheduler.h"
2
+ #include "esphome/core/defines.h"
2
3
  #include "esphome/core/log.h"
3
4
  #include "esphome/core/helpers.h"
4
5
  #include "esphome/core/hal.h"
@@ -21,7 +22,7 @@ static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10;
21
22
 
22
23
  void HOT Scheduler::set_timeout(Component *component, const std::string &name, uint32_t timeout,
23
24
  std::function<void()> func) {
24
- const uint32_t now = this->millis_();
25
+ const auto now = this->millis_();
25
26
 
26
27
  if (!name.empty())
27
28
  this->cancel_timeout(component, name);
@@ -29,17 +30,16 @@ void HOT Scheduler::set_timeout(Component *component, const std::string &name, u
29
30
  if (timeout == SCHEDULER_DONT_RUN)
30
31
  return;
31
32
 
32
- ESP_LOGVV(TAG, "set_timeout(name='%s', timeout=%" PRIu32 ")", name.c_str(), timeout);
33
-
34
33
  auto item = make_unique<SchedulerItem>();
35
34
  item->component = component;
36
35
  item->name = name;
37
36
  item->type = SchedulerItem::TIMEOUT;
38
- item->timeout = timeout;
39
- item->last_execution = now;
40
- item->last_execution_major = this->millis_major_;
37
+ item->next_execution_ = now + timeout;
41
38
  item->callback = std::move(func);
42
39
  item->remove = false;
40
+ #ifdef ESPHOME_DEBUG_SCHEDULER
41
+ ESP_LOGD(TAG, "set_timeout(name='%s/%s', timeout=%" PRIu32 ")", item->get_source(), name.c_str(), timeout);
42
+ #endif
43
43
  this->push_(std::move(item));
44
44
  }
45
45
  bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name) {
@@ -47,7 +47,7 @@ bool HOT Scheduler::cancel_timeout(Component *component, const std::string &name
47
47
  }
48
48
  void HOT Scheduler::set_interval(Component *component, const std::string &name, uint32_t interval,
49
49
  std::function<void()> func) {
50
- const uint32_t now = this->millis_();
50
+ const auto now = this->millis_();
51
51
 
52
52
  if (!name.empty())
53
53
  this->cancel_interval(component, name);
@@ -60,19 +60,18 @@ void HOT Scheduler::set_interval(Component *component, const std::string &name,
60
60
  if (interval != 0)
61
61
  offset = (random_uint32() % interval) / 2;
62
62
 
63
- ESP_LOGVV(TAG, "set_interval(name='%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", name.c_str(), interval, offset);
64
-
65
63
  auto item = make_unique<SchedulerItem>();
66
64
  item->component = component;
67
65
  item->name = name;
68
66
  item->type = SchedulerItem::INTERVAL;
69
67
  item->interval = interval;
70
- item->last_execution = now - offset - interval;
71
- item->last_execution_major = this->millis_major_;
72
- if (item->last_execution > now)
73
- item->last_execution_major--;
68
+ item->next_execution_ = now + offset;
74
69
  item->callback = std::move(func);
75
70
  item->remove = false;
71
+ #ifdef ESPHOME_DEBUG_SCHEDULER
72
+ ESP_LOGD(TAG, "set_interval(name='%s/%s', interval=%" PRIu32 ", offset=%" PRIu32 ")", item->get_source(),
73
+ name.c_str(), interval, offset);
74
+ #endif
76
75
  this->push_(std::move(item));
77
76
  }
78
77
  bool HOT Scheduler::cancel_interval(Component *component, const std::string &name) {
@@ -138,36 +137,36 @@ optional<uint32_t> HOT Scheduler::next_schedule_in() {
138
137
  if (this->empty_())
139
138
  return {};
140
139
  auto &item = this->items_[0];
141
- const uint32_t now = this->millis_();
142
- uint32_t next_time = item->last_execution + item->interval;
143
- if (next_time < now)
140
+ const auto now = this->millis_();
141
+ if (item->next_execution_ < now)
144
142
  return 0;
145
- return next_time - now;
143
+ return item->next_execution_ - now;
146
144
  }
147
145
  void HOT Scheduler::call() {
148
- const uint32_t now = this->millis_();
146
+ const auto now = this->millis_();
149
147
  this->process_to_add();
150
148
 
151
149
  #ifdef ESPHOME_DEBUG_SCHEDULER
152
- static uint32_t last_print = 0;
150
+ static uint64_t last_print = 0;
153
151
 
154
152
  if (now - last_print > 2000) {
155
153
  last_print = now;
156
154
  std::vector<std::unique_ptr<SchedulerItem>> old_items;
157
- ESP_LOGVV(TAG, "Items: count=%u, now=%" PRIu32, this->items_.size(), now);
155
+ ESP_LOGD(TAG, "Items: count=%u, now=%" PRIu64 " (%u, %" PRIu32 ")", this->items_.size(), now, this->millis_major_,
156
+ this->last_millis_);
158
157
  while (!this->empty_()) {
159
158
  this->lock_.lock();
160
159
  auto item = std::move(this->items_[0]);
161
160
  this->pop_raw_();
162
161
  this->lock_.unlock();
163
162
 
164
- ESP_LOGVV(TAG, " %s '%s' interval=%" PRIu32 " last_execution=%" PRIu32 " (%u) next=%" PRIu32 " (%u)",
165
- item->get_type_str(), item->name.c_str(), item->interval, item->last_execution,
166
- item->last_execution_major, item->next_execution(), item->next_execution_major());
163
+ ESP_LOGD(TAG, " %s '%s/%s' interval=%" PRIu32 " next_execution in %" PRIu64 "ms at %" PRIu64,
164
+ item->get_type_str(), item->get_source(), item->name.c_str(), item->interval,
165
+ item->next_execution_ - now, item->next_execution_);
167
166
 
168
167
  old_items.push_back(std::move(item));
169
168
  }
170
- ESP_LOGVV(TAG, "\n");
169
+ ESP_LOGD(TAG, "\n");
171
170
 
172
171
  {
173
172
  LockGuard guard{this->lock_};
@@ -206,14 +205,10 @@ void HOT Scheduler::call() {
206
205
  {
207
206
  // Don't copy-by value yet
208
207
  auto &item = this->items_[0];
209
- if ((now - item->last_execution) < item->interval) {
208
+ if (item->next_execution_ > now) {
210
209
  // Not reached timeout yet, done for this call
211
210
  break;
212
211
  }
213
- uint8_t major = item->next_execution_major();
214
- if (this->millis_major_ - major > 1)
215
- break;
216
-
217
212
  // Don't run on failed components
218
213
  if (item->component != nullptr && item->component->is_failed()) {
219
214
  LockGuard guard{this->lock_};
@@ -221,9 +216,10 @@ void HOT Scheduler::call() {
221
216
  continue;
222
217
  }
223
218
 
224
- #ifdef ESPHOME_LOG_HAS_VERY_VERBOSE
225
- ESP_LOGVV(TAG, "Running %s '%s' with interval=%" PRIu32 " last_execution=%" PRIu32 " (now=%" PRIu32 ")",
226
- item->get_type_str(), item->name.c_str(), item->interval, item->last_execution, now);
219
+ #ifdef ESPHOME_DEBUG_SCHEDULER
220
+ ESP_LOGV(TAG, "Running %s '%s/%s' with interval=%" PRIu32 " next_execution=%" PRIu64 " (now=%" PRIu64 ")",
221
+ item->get_type_str(), item->get_source(), item->name.c_str(), item->interval, item->next_execution_,
222
+ now);
227
223
  #endif
228
224
 
229
225
  // Warning: During callback(), a lot of stuff can happen, including:
@@ -254,13 +250,7 @@ void HOT Scheduler::call() {
254
250
  }
255
251
 
256
252
  if (item->type == SchedulerItem::INTERVAL) {
257
- if (item->interval != 0) {
258
- const uint32_t before = item->last_execution;
259
- const uint32_t amount = (now - item->last_execution) / item->interval;
260
- item->last_execution += amount * item->interval;
261
- if (item->last_execution < before)
262
- item->last_execution_major++;
263
- }
253
+ item->next_execution_ = now + item->interval;
264
254
  this->push_(std::move(item));
265
255
  }
266
256
  }
@@ -322,43 +312,20 @@ bool HOT Scheduler::cancel_item_(Component *component, const std::string &name,
322
312
 
323
313
  return ret;
324
314
  }
325
- uint32_t Scheduler::millis_() {
315
+ uint64_t Scheduler::millis_() {
326
316
  const uint32_t now = millis();
327
317
  if (now < this->last_millis_) {
328
- ESP_LOGD(TAG, "Incrementing scheduler major");
329
318
  this->millis_major_++;
319
+ ESP_LOGD(TAG, "Incrementing scheduler major at %" PRIu64 "ms",
320
+ now + (static_cast<uint64_t>(this->millis_major_) << 32));
330
321
  }
331
322
  this->last_millis_ = now;
332
- return now;
323
+ return now + (static_cast<uint64_t>(this->millis_major_) << 32);
333
324
  }
334
325
 
335
326
  bool HOT Scheduler::SchedulerItem::cmp(const std::unique_ptr<SchedulerItem> &a,
336
327
  const std::unique_ptr<SchedulerItem> &b) {
337
- // min-heap
338
- // return true if *a* will happen after *b*
339
- uint32_t a_next_exec = a->next_execution();
340
- uint8_t a_next_exec_major = a->next_execution_major();
341
- uint32_t b_next_exec = b->next_execution();
342
- uint8_t b_next_exec_major = b->next_execution_major();
343
-
344
- if (a_next_exec_major != b_next_exec_major) {
345
- // The "major" calculation is quite complicated.
346
- // Basically, we need to check if the major value lies in the future or
347
- //
348
-
349
- // Here are some cases to think about:
350
- // Format: a_major,b_major -> expected result (a-b, b-a)
351
- // a=255,b=0 -> false (255, 1)
352
- // a=0,b=1 -> false (255, 1)
353
- // a=1,b=0 -> true (1, 255)
354
- // a=0,b=255 -> true (1, 255)
355
-
356
- uint8_t diff1 = a_next_exec_major - b_next_exec_major;
357
- uint8_t diff2 = b_next_exec_major - a_next_exec_major;
358
- return diff1 < diff2;
359
- }
360
-
361
- return a_next_exec > b_next_exec;
328
+ return a->next_execution_ > b->next_execution_;
362
329
  }
363
330
 
364
331
  } // namespace esphome
esphome/core/scheduler.h CHANGED
@@ -32,23 +32,10 @@ class Scheduler {
32
32
  Component *component;
33
33
  std::string name;
34
34
  enum Type { TIMEOUT, INTERVAL } type;
35
- union {
36
- uint32_t interval;
37
- uint32_t timeout;
38
- };
39
- uint32_t last_execution;
35
+ uint32_t interval;
36
+ uint64_t next_execution_;
40
37
  std::function<void()> callback;
41
38
  bool remove;
42
- uint8_t last_execution_major;
43
-
44
- inline uint32_t next_execution() { return this->last_execution + this->timeout; }
45
- inline uint8_t next_execution_major() {
46
- uint32_t next_exec = this->next_execution();
47
- uint8_t next_exec_major = this->last_execution_major;
48
- if (next_exec < this->last_execution)
49
- next_exec_major++;
50
- return next_exec_major;
51
- }
52
39
 
53
40
  static bool cmp(const std::unique_ptr<SchedulerItem> &a, const std::unique_ptr<SchedulerItem> &b);
54
41
  const char *get_type_str() {
@@ -61,9 +48,12 @@ class Scheduler {
61
48
  return "";
62
49
  }
63
50
  }
51
+ const char *get_source() {
52
+ return this->component != nullptr ? this->component->get_component_source() : "unknown";
53
+ }
64
54
  };
65
55
 
66
- uint32_t millis_();
56
+ uint64_t millis_();
67
57
  void cleanup_();
68
58
  void pop_raw_();
69
59
  void push_(std::unique_ptr<SchedulerItem> item);
@@ -77,7 +67,7 @@ class Scheduler {
77
67
  std::vector<std::unique_ptr<SchedulerItem>> items_;
78
68
  std::vector<std::unique_ptr<SchedulerItem>> to_add_;
79
69
  uint32_t last_millis_{0};
80
- uint8_t millis_major_{0};
70
+ uint16_t millis_major_{0};
81
71
  uint32_t to_remove_{0};
82
72
  };
83
73
 
@@ -32,8 +32,6 @@ class MqttStatusThread(threading.Thread):
32
32
  topic = "esphome/discover/#"
33
33
 
34
34
  def on_message(client, userdata, msg):
35
- nonlocal current_entries
36
-
37
35
  payload = msg.payload.decode(errors="backslashreplace")
38
36
  if len(payload) > 0:
39
37
  data = json.loads(payload)
esphome/vscode.py CHANGED
@@ -78,28 +78,47 @@ def _print_file_read_event(path: str) -> None:
78
78
  )
79
79
 
80
80
 
81
+ def _request_and_get_stream_on_stdin(fname: str) -> StringIO:
82
+ _print_file_read_event(fname)
83
+ raw_yaml_stream = StringIO(_read_file_content_from_json_on_stdin())
84
+ return raw_yaml_stream
85
+
86
+
87
+ def _vscode_loader(fname: str) -> dict[str, Any]:
88
+ raw_yaml_stream = _request_and_get_stream_on_stdin(fname)
89
+ # it is required to set the name on StringIO so document on start_mark
90
+ # is set properly. Otherwise it is initialized with "<file>"
91
+ raw_yaml_stream.name = fname
92
+ return parse_yaml(fname, raw_yaml_stream, _vscode_loader)
93
+
94
+
95
+ def _ace_loader(fname: str) -> dict[str, Any]:
96
+ raw_yaml_stream = _request_and_get_stream_on_stdin(fname)
97
+ return parse_yaml(fname, raw_yaml_stream)
98
+
99
+
81
100
  def read_config(args):
82
101
  while True:
83
102
  CORE.reset()
84
103
  data = json.loads(input())
85
- assert data["type"] == "validate"
104
+ assert data["type"] == "validate" or data["type"] == "exit"
105
+ if data["type"] == "exit":
106
+ return
86
107
  CORE.vscode = True
87
- CORE.ace = args.ace
88
- f = data["file"]
89
- if CORE.ace:
90
- CORE.config_path = os.path.join(args.configuration, f)
108
+ if args.ace: # Running from ESPHome Compiler dashboard, not vscode
109
+ CORE.config_path = os.path.join(args.configuration, data["file"])
110
+ loader = _ace_loader
91
111
  else:
92
112
  CORE.config_path = data["file"]
113
+ loader = _vscode_loader
93
114
 
94
115
  file_name = CORE.config_path
95
- _print_file_read_event(file_name)
96
- raw_yaml = _read_file_content_from_json_on_stdin()
97
116
  command_line_substitutions: dict[str, Any] = (
98
117
  dict(args.substitution) if args.substitution else {}
99
118
  )
100
119
  vs = VSCodeResult()
101
120
  try:
102
- config = parse_yaml(file_name, StringIO(raw_yaml))
121
+ config = loader(file_name)
103
122
  res = validate_config(config, command_line_substitutions)
104
123
  except Exception as err: # pylint: disable=broad-except
105
124
  vs.add_yaml_error(str(err))
esphome/yaml_util.py CHANGED
@@ -3,12 +3,12 @@ from __future__ import annotations
3
3
  import fnmatch
4
4
  import functools
5
5
  import inspect
6
- from io import TextIOWrapper
6
+ from io import BytesIO, TextIOBase, TextIOWrapper
7
7
  from ipaddress import _BaseAddress
8
8
  import logging
9
9
  import math
10
10
  import os
11
- from typing import Any
11
+ from typing import Any, Callable
12
12
  import uuid
13
13
 
14
14
  import yaml
@@ -69,7 +69,10 @@ class ESPForceValue:
69
69
  pass
70
70
 
71
71
 
72
- def make_data_base(value, from_database: ESPHomeDataBase = None):
72
+ def make_data_base(
73
+ value, from_database: ESPHomeDataBase = None
74
+ ) -> ESPHomeDataBase | Any:
75
+ """Wrap a value in a ESPHomeDataBase object."""
73
76
  try:
74
77
  value = add_class_to_obj(value, ESPHomeDataBase)
75
78
  if from_database is not None:
@@ -102,6 +105,11 @@ def _add_data_ref(fn):
102
105
  class ESPHomeLoaderMixin:
103
106
  """Loader class that keeps track of line numbers."""
104
107
 
108
+ def __init__(self, name: str, yaml_loader: Callable[[str], dict[str, Any]]) -> None:
109
+ """Initialize the loader."""
110
+ self.name = name
111
+ self.yaml_loader = yaml_loader
112
+
105
113
  @_add_data_ref
106
114
  def construct_yaml_int(self, node):
107
115
  return super().construct_yaml_int(node)
@@ -127,7 +135,7 @@ class ESPHomeLoaderMixin:
127
135
  return super().construct_yaml_seq(node)
128
136
 
129
137
  @_add_data_ref
130
- def construct_yaml_map(self, node):
138
+ def construct_yaml_map(self, node: yaml.MappingNode) -> OrderedDict[str, Any]:
131
139
  """Traverses the given mapping node and returns a list of constructed key-value pairs."""
132
140
  assert isinstance(node, yaml.MappingNode)
133
141
  # A list of key-value pairs we find in the current mapping
@@ -231,7 +239,7 @@ class ESPHomeLoaderMixin:
231
239
  return OrderedDict(pairs)
232
240
 
233
241
  @_add_data_ref
234
- def construct_env_var(self, node):
242
+ def construct_env_var(self, node: yaml.Node) -> str:
235
243
  args = node.value.split()
236
244
  # Check for a default value
237
245
  if len(args) > 1:
@@ -243,23 +251,23 @@ class ESPHomeLoaderMixin:
243
251
  )
244
252
 
245
253
  @property
246
- def _directory(self):
254
+ def _directory(self) -> str:
247
255
  return os.path.dirname(self.name)
248
256
 
249
- def _rel_path(self, *args):
257
+ def _rel_path(self, *args: str) -> str:
250
258
  return os.path.join(self._directory, *args)
251
259
 
252
260
  @_add_data_ref
253
- def construct_secret(self, node):
261
+ def construct_secret(self, node: yaml.Node) -> str:
254
262
  try:
255
- secrets = _load_yaml_internal(self._rel_path(SECRET_YAML))
263
+ secrets = self.yaml_loader(self._rel_path(SECRET_YAML))
256
264
  except EsphomeError as e:
257
265
  if self.name == CORE.config_path:
258
266
  raise e
259
267
  try:
260
268
  main_config_dir = os.path.dirname(CORE.config_path)
261
269
  main_secret_yml = os.path.join(main_config_dir, SECRET_YAML)
262
- secrets = _load_yaml_internal(main_secret_yml)
270
+ secrets = self.yaml_loader(main_secret_yml)
263
271
  except EsphomeError as er:
264
272
  raise EsphomeError(f"{e}\n{er}") from er
265
273
 
@@ -272,7 +280,9 @@ class ESPHomeLoaderMixin:
272
280
  return val
273
281
 
274
282
  @_add_data_ref
275
- def construct_include(self, node):
283
+ def construct_include(
284
+ self, node: yaml.Node
285
+ ) -> dict[str, Any] | OrderedDict[str, Any]:
276
286
  from esphome.const import CONF_VARS
277
287
 
278
288
  def extract_file_vars(node):
@@ -290,71 +300,93 @@ class ESPHomeLoaderMixin:
290
300
  else:
291
301
  file, vars = node.value, None
292
302
 
293
- result = _load_yaml_internal(self._rel_path(file))
303
+ result = self.yaml_loader(self._rel_path(file))
294
304
  if not vars:
295
305
  vars = {}
296
306
  result = substitute_vars(result, vars)
297
307
  return result
298
308
 
299
309
  @_add_data_ref
300
- def construct_include_dir_list(self, node):
310
+ def construct_include_dir_list(self, node: yaml.Node) -> list[dict[str, Any]]:
301
311
  files = filter_yaml_files(_find_files(self._rel_path(node.value), "*.yaml"))
302
- return [_load_yaml_internal(f) for f in files]
312
+ return [self.yaml_loader(f) for f in files]
303
313
 
304
314
  @_add_data_ref
305
- def construct_include_dir_merge_list(self, node):
315
+ def construct_include_dir_merge_list(self, node: yaml.Node) -> list[dict[str, Any]]:
306
316
  files = filter_yaml_files(_find_files(self._rel_path(node.value), "*.yaml"))
307
317
  merged_list = []
308
318
  for fname in files:
309
- loaded_yaml = _load_yaml_internal(fname)
319
+ loaded_yaml = self.yaml_loader(fname)
310
320
  if isinstance(loaded_yaml, list):
311
321
  merged_list.extend(loaded_yaml)
312
322
  return merged_list
313
323
 
314
324
  @_add_data_ref
315
- def construct_include_dir_named(self, node):
325
+ def construct_include_dir_named(
326
+ self, node: yaml.Node
327
+ ) -> OrderedDict[str, dict[str, Any]]:
316
328
  files = filter_yaml_files(_find_files(self._rel_path(node.value), "*.yaml"))
317
329
  mapping = OrderedDict()
318
330
  for fname in files:
319
331
  filename = os.path.splitext(os.path.basename(fname))[0]
320
- mapping[filename] = _load_yaml_internal(fname)
332
+ mapping[filename] = self.yaml_loader(fname)
321
333
  return mapping
322
334
 
323
335
  @_add_data_ref
324
- def construct_include_dir_merge_named(self, node):
336
+ def construct_include_dir_merge_named(
337
+ self, node: yaml.Node
338
+ ) -> OrderedDict[str, dict[str, Any]]:
325
339
  files = filter_yaml_files(_find_files(self._rel_path(node.value), "*.yaml"))
326
340
  mapping = OrderedDict()
327
341
  for fname in files:
328
- loaded_yaml = _load_yaml_internal(fname)
342
+ loaded_yaml = self.yaml_loader(fname)
329
343
  if isinstance(loaded_yaml, dict):
330
344
  mapping.update(loaded_yaml)
331
345
  return mapping
332
346
 
333
347
  @_add_data_ref
334
- def construct_lambda(self, node):
348
+ def construct_lambda(self, node: yaml.Node) -> Lambda:
335
349
  return Lambda(str(node.value))
336
350
 
337
351
  @_add_data_ref
338
- def construct_force(self, node):
352
+ def construct_force(self, node: yaml.Node) -> ESPForceValue:
339
353
  obj = self.construct_scalar(node)
340
354
  return add_class_to_obj(obj, ESPForceValue)
341
355
 
342
356
  @_add_data_ref
343
- def construct_extend(self, node):
357
+ def construct_extend(self, node: yaml.Node) -> Extend:
344
358
  return Extend(str(node.value))
345
359
 
346
360
  @_add_data_ref
347
- def construct_remove(self, node):
361
+ def construct_remove(self, node: yaml.Node) -> Remove:
348
362
  return Remove(str(node.value))
349
363
 
350
364
 
351
365
  class ESPHomeLoader(ESPHomeLoaderMixin, FastestAvailableSafeLoader):
352
366
  """Loader class that keeps track of line numbers."""
353
367
 
368
+ def __init__(
369
+ self,
370
+ stream: TextIOBase | BytesIO,
371
+ name: str,
372
+ yaml_loader: Callable[[str], dict[str, Any]],
373
+ ) -> None:
374
+ FastestAvailableSafeLoader.__init__(self, stream)
375
+ ESPHomeLoaderMixin.__init__(self, name, yaml_loader)
376
+
354
377
 
355
378
  class ESPHomePurePythonLoader(ESPHomeLoaderMixin, PurePythonLoader):
356
379
  """Loader class that keeps track of line numbers."""
357
380
 
381
+ def __init__(
382
+ self,
383
+ stream: TextIOBase | BytesIO,
384
+ name: str,
385
+ yaml_loader: Callable[[str], dict[str, Any]],
386
+ ) -> None:
387
+ PurePythonLoader.__init__(self, stream)
388
+ ESPHomeLoaderMixin.__init__(self, name, yaml_loader)
389
+
358
390
 
359
391
  for _loader in (ESPHomeLoader, ESPHomePurePythonLoader):
360
392
  _loader.add_constructor("tag:yaml.org,2002:int", _loader.construct_yaml_int)
@@ -388,17 +420,30 @@ def load_yaml(fname: str, clear_secrets: bool = True) -> Any:
388
420
  return _load_yaml_internal(fname)
389
421
 
390
422
 
391
- def parse_yaml(file_name: str, file_handle: TextIOWrapper) -> Any:
423
+ def _load_yaml_internal(fname: str) -> Any:
424
+ """Load a YAML file."""
425
+ try:
426
+ with open(fname, encoding="utf-8") as f_handle:
427
+ return parse_yaml(fname, f_handle)
428
+ except (UnicodeDecodeError, OSError) as err:
429
+ raise EsphomeError(f"Error reading file {fname}: {err}") from err
430
+
431
+
432
+ def parse_yaml(
433
+ file_name: str, file_handle: TextIOWrapper, yaml_loader=_load_yaml_internal
434
+ ) -> Any:
392
435
  """Parse a YAML file."""
393
436
  try:
394
- return _load_yaml_internal_with_type(ESPHomeLoader, file_name, file_handle)
437
+ return _load_yaml_internal_with_type(
438
+ ESPHomeLoader, file_name, file_handle, yaml_loader
439
+ )
395
440
  except EsphomeError:
396
441
  # Loading failed, so we now load with the Python loader which has more
397
442
  # readable exceptions
398
443
  # Rewind the stream so we can try again
399
444
  file_handle.seek(0, 0)
400
445
  return _load_yaml_internal_with_type(
401
- ESPHomePurePythonLoader, file_name, file_handle
446
+ ESPHomePurePythonLoader, file_name, file_handle, yaml_loader
402
447
  )
403
448
 
404
449
 
@@ -435,23 +480,14 @@ def substitute_vars(config, vars):
435
480
  return result
436
481
 
437
482
 
438
- def _load_yaml_internal(fname: str) -> Any:
439
- """Load a YAML file."""
440
- try:
441
- with open(fname, encoding="utf-8") as f_handle:
442
- return parse_yaml(fname, f_handle)
443
- except (UnicodeDecodeError, OSError) as err:
444
- raise EsphomeError(f"Error reading file {fname}: {err}") from err
445
-
446
-
447
483
  def _load_yaml_internal_with_type(
448
484
  loader_type: type[ESPHomeLoader] | type[ESPHomePurePythonLoader],
449
485
  fname: str,
450
486
  content: TextIOWrapper,
487
+ yaml_loader: Any,
451
488
  ) -> Any:
452
489
  """Load a YAML file."""
453
- loader = loader_type(content)
454
- loader.name = fname
490
+ loader = loader_type(content, fname, yaml_loader)
455
491
  try:
456
492
  return loader.get_single_data() or OrderedDict()
457
493
  except yaml.YAMLError as exc:
@@ -470,7 +506,7 @@ def dump(dict_, show_secrets=False):
470
506
  )
471
507
 
472
508
 
473
- def _is_file_valid(name):
509
+ def _is_file_valid(name: str) -> bool:
474
510
  """Decide if a file is valid."""
475
511
  return not name.startswith(".")
476
512