esphome 2025.3.2__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 (718) 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/display/display.cpp +2 -2
  143. esphome/components/dps310/sensor.py +3 -3
  144. esphome/components/ds1307/time.py +2 -3
  145. esphome/components/dsmr/__init__.py +3 -7
  146. esphome/components/dsmr/sensor.py +5 -4
  147. esphome/components/dsmr/text_sensor.py +3 -2
  148. esphome/components/duty_cycle/sensor.py +3 -8
  149. esphome/components/duty_time/sensor.py +7 -7
  150. esphome/components/e131/__init__.py +3 -3
  151. esphome/components/ee895/sensor.py +5 -5
  152. esphome/components/ektf2232/touchscreen/__init__.py +2 -3
  153. esphome/components/emc2101/__init__.py +1 -1
  154. esphome/components/emc2101/output/__init__.py +3 -2
  155. esphome/components/emc2101/sensor/__init__.py +4 -3
  156. esphome/components/emmeti/climate.py +1 -1
  157. esphome/components/endstop/cover.py +3 -3
  158. esphome/components/ens160_base/__init__.py +1 -1
  159. esphome/components/ens160_i2c/sensor.py +2 -1
  160. esphome/components/ens160_spi/sensor.py +2 -1
  161. esphome/components/ens210/sensor.py +1 -1
  162. esphome/components/esp32/__init__.py +10 -0
  163. esphome/components/esp32_ble_tracker/__init__.py +135 -51
  164. esphome/components/esp32_camera/__init__.py +7 -8
  165. esphome/components/esp32_camera_web_server/__init__.py +2 -2
  166. esphome/components/esp32_can/canbus.py +21 -0
  167. esphome/components/esp32_can/esp32_can.cpp +1 -1
  168. esphome/components/esp32_can/esp32_can.h +4 -0
  169. esphome/components/esp32_dac/output.py +2 -2
  170. esphome/components/esp32_hall/sensor.py +2 -6
  171. esphome/components/esp32_touch/__init__.py +7 -7
  172. esphome/components/esp32_touch/binary_sensor.py +4 -7
  173. esphome/components/esp8266_pwm/output.py +3 -8
  174. esphome/components/ethernet/__init__.py +1 -0
  175. esphome/components/ethernet/ethernet_component.cpp +1 -1
  176. esphome/components/ethernet_info/ethernet_info_text_sensor.h +1 -0
  177. esphome/components/exposure_notifications/__init__.py +2 -2
  178. esphome/components/external_components/__init__.py +1 -1
  179. esphome/components/ezo/sensor.py +2 -2
  180. esphome/components/ezo_pmp/__init__.py +4 -4
  181. esphome/components/ezo_pmp/binary_sensor.py +4 -4
  182. esphome/components/ezo_pmp/sensor.py +4 -5
  183. esphome/components/ezo_pmp/text_sensor.py +2 -6
  184. esphome/components/factory_reset/button/__init__.py +2 -1
  185. esphome/components/factory_reset/switch/__init__.py +3 -2
  186. esphome/components/fastled_base/__init__.py +3 -3
  187. esphome/components/fastled_clockless/light.py +2 -2
  188. esphome/components/fastled_spi/light.py +2 -2
  189. esphome/components/feedback/cover.py +3 -3
  190. esphome/components/fingerprint_grow/__init__.py +5 -6
  191. esphome/components/fingerprint_grow/binary_sensor.py +2 -1
  192. esphome/components/fingerprint_grow/sensor.py +2 -1
  193. esphome/components/fs3000/sensor.py +2 -6
  194. esphome/components/ft5x06/touchscreen/__init__.py +2 -2
  195. esphome/components/ft63x6/touchscreen.py +2 -3
  196. esphome/components/fujitsu_general/climate.py +1 -1
  197. esphome/components/gcja5/sensor.py +4 -4
  198. esphome/components/gdk101/__init__.py +1 -1
  199. esphome/components/gdk101/binary_sensor.py +2 -1
  200. esphome/components/gdk101/sensor.py +5 -4
  201. esphome/components/globals/__init__.py +1 -2
  202. esphome/components/gp2y1010au0f/sensor.py +3 -3
  203. esphome/components/gp8403/__init__.py +1 -2
  204. esphome/components/gp8403/output/__init__.py +3 -4
  205. esphome/components/gpio/binary_sensor/__init__.py +3 -2
  206. esphome/components/gpio/one_wire/__init__.py +3 -2
  207. esphome/components/gpio/output/__init__.py +3 -2
  208. esphome/components/gpio/switch/__init__.py +3 -2
  209. esphome/components/gps/__init__.py +4 -5
  210. esphome/components/gps/time/__init__.py +3 -2
  211. esphome/components/graph/__init__.py +12 -12
  212. esphome/components/grove_tb6612fng/__init__.py +5 -6
  213. esphome/components/growatt_solar/sensor.py +1 -1
  214. esphome/components/gt911/binary_sensor/__init__.py +2 -2
  215. esphome/components/haier/binary_sensor/__init__.py +4 -10
  216. esphome/components/haier/button/__init__.py +3 -6
  217. esphome/components/haier/sensor/__init__.py +4 -6
  218. esphome/components/haier/switch/__init__.py +4 -7
  219. esphome/components/haier/text_sensor/__init__.py +4 -9
  220. esphome/components/havells_solar/sensor.py +1 -1
  221. esphome/components/hbridge/fan/__init__.py +6 -6
  222. esphome/components/hbridge/light/__init__.py +2 -1
  223. esphome/components/hdc1080/sensor.py +1 -1
  224. esphome/components/he60r/cover.py +2 -6
  225. esphome/components/heatpumpir/climate.py +1 -1
  226. esphome/components/hitachi_ac344/climate.py +1 -1
  227. esphome/components/hitachi_ac424/climate.py +1 -1
  228. esphome/components/hlw8012/sensor.py +6 -6
  229. esphome/components/hm3301/sensor.py +3 -3
  230. esphome/components/hmc5883l/sensor.py +4 -4
  231. esphome/components/homeassistant/time/__init__.py +2 -1
  232. esphome/components/honeywell_hih_i2c/sensor.py +3 -3
  233. esphome/components/honeywellabp/sensor.py +1 -2
  234. esphome/components/honeywellabp2_i2c/sensor.py +1 -2
  235. esphome/components/host/time/__init__.py +2 -2
  236. esphome/components/hrxl_maxsonar_wr/sensor.py +1 -1
  237. esphome/components/hte501/sensor.py +3 -3
  238. esphome/components/http_request/ota/__init__.py +5 -9
  239. esphome/components/http_request/update/__init__.py +3 -7
  240. esphome/components/htu21d/sensor.py +6 -6
  241. esphome/components/htu31d/sensor.py +1 -1
  242. esphome/components/hx711/sensor.py +3 -8
  243. esphome/components/hydreon_rgxx/binary_sensor.py +3 -7
  244. esphome/components/hydreon_rgxx/sensor.py +4 -4
  245. esphome/components/hyt271/sensor.py +1 -1
  246. esphome/components/i2c_device/__init__.py +1 -1
  247. esphome/components/i2s_audio/media_player/__init__.py +6 -8
  248. esphome/components/iaqcore/sensor.py +2 -2
  249. esphome/components/ina219/sensor.py +2 -2
  250. esphome/components/ina226/sensor.py +4 -4
  251. esphome/components/ina260/sensor.py +4 -4
  252. esphome/components/ina2xx_base/__init__.py +2 -2
  253. esphome/components/ina2xx_i2c/sensor.py +1 -1
  254. esphome/components/ina2xx_spi/sensor.py +1 -1
  255. esphome/components/ina3221/sensor.py +3 -3
  256. esphome/components/inkbird_ibsth1_mini/sensor.py +2 -2
  257. esphome/components/inkplate6/display.py +2 -2
  258. esphome/components/integration/sensor.py +4 -4
  259. esphome/components/internal_temperature/sensor.py +5 -7
  260. esphome/components/interval/__init__.py +1 -1
  261. esphome/components/jsn_sr04t/sensor.py +3 -3
  262. esphome/components/kamstrup_kmp/sensor.py +1 -1
  263. esphome/components/key_collector/__init__.py +2 -2
  264. esphome/components/kmeteriso/sensor.py +2 -2
  265. esphome/components/kuntze/sensor.py +5 -5
  266. esphome/components/lcd_base/__init__.py +2 -2
  267. esphome/components/lcd_gpio/display.py +4 -4
  268. esphome/components/lcd_menu/__init__.py +3 -7
  269. esphome/components/lcd_pcf8574/display.py +1 -1
  270. esphome/components/ld2410/__init__.py +4 -4
  271. esphome/components/ld2410/binary_sensor.py +5 -4
  272. esphome/components/ld2410/button/__init__.py +3 -2
  273. esphome/components/ld2410/number/__init__.py +5 -4
  274. esphome/components/ld2410/select/__init__.py +4 -3
  275. esphome/components/ld2410/sensor.py +6 -5
  276. esphome/components/ld2410/switch/__init__.py +2 -1
  277. esphome/components/ld2410/text_sensor.py +3 -2
  278. esphome/components/ld2420/__init__.py +1 -1
  279. esphome/components/ld2420/binary_sensor/__init__.py +4 -3
  280. esphome/components/ld2420/button/__init__.py +3 -2
  281. esphome/components/ld2420/number/__init__.py +3 -2
  282. esphome/components/ld2420/select/__init__.py +1 -0
  283. esphome/components/ld2420/sensor/__init__.py +3 -2
  284. esphome/components/ld2420/text_sensor/__init__.py +2 -6
  285. esphome/components/ld2450/__init__.py +2 -5
  286. esphome/components/ledc/output.py +3 -3
  287. esphome/components/libretiny/text_sensor.py +1 -1
  288. esphome/components/libretiny_pwm/output.py +3 -7
  289. esphome/components/lightwaverf/__init__.py +6 -8
  290. esphome/components/lilygo_t5_47/touchscreen/__init__.py +2 -3
  291. esphome/components/ltr390/sensor.py +1 -1
  292. esphome/components/ltr501/sensor.py +2 -2
  293. esphome/components/ltr_als_ps/sensor.py +2 -2
  294. esphome/components/lvgl/__init__.py +9 -12
  295. esphome/components/lvgl/automation.py +15 -3
  296. esphome/components/lvgl/defines.py +5 -2
  297. esphome/components/lvgl/encoders.py +3 -2
  298. esphome/components/lvgl/lv_validation.py +17 -9
  299. esphome/components/lvgl/lvcode.py +11 -9
  300. esphome/components/lvgl/lvgl_esphome.h +21 -0
  301. esphome/components/lvgl/number/__init__.py +23 -20
  302. esphome/components/lvgl/number/lvgl_number.h +27 -14
  303. esphome/components/lvgl/schemas.py +70 -19
  304. esphome/components/lvgl/select/__init__.py +11 -13
  305. esphome/components/lvgl/select/lvgl_select.h +25 -18
  306. esphome/components/lvgl/styles.py +42 -11
  307. esphome/components/lvgl/switch/__init__.py +13 -8
  308. esphome/components/lvgl/switch/lvgl_switch.h +5 -16
  309. esphome/components/lvgl/trigger.py +10 -1
  310. esphome/components/lvgl/widgets/__init__.py +1 -2
  311. esphome/components/lvgl/widgets/buttonmatrix.py +2 -2
  312. esphome/components/lvgl/widgets/canvas.py +407 -0
  313. esphome/components/lvgl/widgets/line.py +22 -32
  314. esphome/components/lvgl/widgets/meter.py +3 -1
  315. esphome/components/m5stack_8angle/__init__.py +1 -2
  316. esphome/components/m5stack_8angle/binary_sensor/__init__.py +2 -3
  317. esphome/components/m5stack_8angle/light/__init__.py +2 -4
  318. esphome/components/m5stack_8angle/sensor/__init__.py +2 -4
  319. esphome/components/matrix_keypad/binary_sensor/__init__.py +4 -3
  320. esphome/components/max31855/sensor.py +1 -1
  321. esphome/components/max31865/sensor.py +1 -1
  322. esphome/components/max44009/sensor.py +1 -1
  323. esphome/components/max6675/sensor.py +1 -1
  324. esphome/components/max6956/__init__.py +5 -5
  325. esphome/components/max6956/output/__init__.py +4 -3
  326. esphome/components/max7219/display.py +1 -1
  327. esphome/components/max7219digit/display.py +1 -1
  328. esphome/components/max9611/sensor.py +10 -10
  329. esphome/components/mcp23008/__init__.py +1 -1
  330. esphome/components/mcp23016/__init__.py +4 -4
  331. esphome/components/mcp23017/__init__.py +1 -1
  332. esphome/components/mcp23s08/__init__.py +1 -1
  333. esphome/components/mcp23s17/__init__.py +1 -1
  334. esphome/components/mcp23xxx_base/__init__.py +4 -4
  335. esphome/components/mcp2515/canbus.py +2 -2
  336. esphome/components/mcp3008/__init__.py +1 -1
  337. esphome/components/mcp3008/sensor/__init__.py +4 -4
  338. esphome/components/mcp3204/__init__.py +1 -1
  339. esphome/components/mcp3204/sensor/__init__.py +3 -2
  340. esphome/components/mcp4461/__init__.py +42 -0
  341. esphome/components/mcp4461/mcp4461.cpp +618 -0
  342. esphome/components/mcp4461/mcp4461.h +171 -0
  343. esphome/components/mcp4461/output/__init__.py +60 -0
  344. esphome/components/mcp4461/output/mcp4461_output.cpp +73 -0
  345. esphome/components/mcp4461/output/mcp4461_output.h +49 -0
  346. esphome/components/mcp4725/output.py +2 -2
  347. esphome/components/mcp4728/__init__.py +1 -1
  348. esphome/components/mcp4728/output/__init__.py +4 -3
  349. esphome/components/mcp47a1/output.py +2 -2
  350. esphome/components/mcp9808/sensor.py +1 -1
  351. esphome/components/mdns/__init__.py +1 -1
  352. esphome/components/mhz19/sensor.py +4 -4
  353. esphome/components/micronova/__init__.py +3 -5
  354. esphome/components/micronova/button/__init__.py +5 -5
  355. esphome/components/micronova/number/__init__.py +6 -10
  356. esphome/components/micronova/sensor/__init__.py +6 -6
  357. esphome/components/micronova/switch/__init__.py +6 -8
  358. esphome/components/micronova/text_sensor/__init__.py +5 -5
  359. esphome/components/microphone/__init__.py +2 -4
  360. esphome/components/midea/climate.py +6 -10
  361. esphome/components/midea_ir/climate.py +1 -1
  362. esphome/components/mitsubishi/climate.py +1 -1
  363. esphome/components/mlx90614/sensor.py +1 -1
  364. esphome/components/mmc5603/sensor.py +4 -4
  365. esphome/components/mmc5983/sensor.py +1 -1
  366. esphome/components/modbus/__init__.py +5 -9
  367. esphome/components/modbus_controller/__init__.py +1 -1
  368. esphome/components/monochromatic/light.py +2 -2
  369. esphome/components/mopeka_ble/__init__.py +1 -1
  370. esphome/components/mopeka_pro_check/sensor.py +12 -12
  371. esphome/components/mopeka_std_check/sensor.py +8 -8
  372. esphome/components/mpl3115a2/sensor.py +1 -1
  373. esphome/components/mpr121/__init__.py +3 -3
  374. esphome/components/mpr121/binary_sensor/__init__.py +5 -4
  375. esphome/components/mpu6050/sensor.py +4 -4
  376. esphome/components/mpu6886/sensor.py +4 -4
  377. esphome/components/mqtt_subscribe/sensor/__init__.py +3 -5
  378. esphome/components/mqtt_subscribe/text_sensor/__init__.py +1 -1
  379. esphome/components/ms5611/sensor.py +2 -2
  380. esphome/components/ms8607/sensor.py +1 -1
  381. esphome/components/my9231/__init__.py +1 -1
  382. esphome/components/my9231/output.py +2 -1
  383. esphome/components/nau7802/nau7802.cpp +0 -4
  384. esphome/components/nau7802/nau7802.h +0 -2
  385. esphome/components/neopixelbus/_methods.py +11 -9
  386. esphome/components/neopixelbus/light.py +11 -18
  387. esphome/components/nextion/binary_sensor/__init__.py +6 -14
  388. esphome/components/nextion/sensor/__init__.py +7 -10
  389. esphome/components/nextion/switch/__init__.py +3 -5
  390. esphome/components/nextion/text_sensor/__init__.py +3 -7
  391. esphome/components/noblex/climate.py +1 -1
  392. esphome/components/ntc/sensor.py +1 -1
  393. esphome/components/opentherm/__init__.py +6 -6
  394. esphome/components/opentherm/input.py +2 -1
  395. esphome/components/opentherm/number/__init__.py +5 -4
  396. esphome/components/opentherm/output/__init__.py +3 -2
  397. esphome/components/opentherm/schema.py +7 -7
  398. esphome/components/opentherm/switch/__init__.py +3 -2
  399. esphome/components/opentherm/validate.py +1 -1
  400. esphome/components/output/__init__.py +2 -3
  401. esphome/components/output/button/__init__.py +3 -2
  402. esphome/components/output/lock/__init__.py +2 -1
  403. esphome/components/output/switch/__init__.py +2 -1
  404. esphome/components/partition/light.py +4 -4
  405. esphome/components/pca6416a/__init__.py +4 -4
  406. esphome/components/pca9554/__init__.py +4 -4
  407. esphome/components/pca9685/__init__.py +2 -2
  408. esphome/components/pca9685/output.py +2 -1
  409. esphome/components/pcf85063/time.py +2 -3
  410. esphome/components/pcf8563/time.py +2 -2
  411. esphome/components/pcf8574/__init__.py +4 -4
  412. esphome/components/pid/climate.py +2 -2
  413. esphome/components/pid/sensor/__init__.py +4 -8
  414. esphome/components/pipsolar/__init__.py +1 -1
  415. esphome/components/pipsolar/binary_sensor/__init__.py +2 -2
  416. esphome/components/pipsolar/output/__init__.py +4 -3
  417. esphome/components/pipsolar/sensor/__init__.py +5 -4
  418. esphome/components/pipsolar/switch/__init__.py +2 -1
  419. esphome/components/pipsolar/text_sensor/__init__.py +2 -1
  420. esphome/components/pm1006/sensor.py +2 -2
  421. esphome/components/pmsa003i/sensor.py +4 -4
  422. esphome/components/pmsx003/sensor.py +10 -11
  423. esphome/components/pmwcs3/sensor.py +5 -5
  424. esphome/components/pn532/__init__.py +3 -3
  425. esphome/components/pn532_i2c/__init__.py +1 -1
  426. esphome/components/pn532_spi/__init__.py +1 -1
  427. esphome/components/pn7150/__init__.py +2 -2
  428. esphome/components/pn7150_i2c/__init__.py +1 -1
  429. esphome/components/pn7160/__init__.py +2 -2
  430. esphome/components/pn7160_i2c/__init__.py +1 -1
  431. esphome/components/pn7160_spi/__init__.py +1 -1
  432. esphome/components/power_supply/__init__.py +1 -1
  433. esphome/components/prometheus/__init__.py +3 -8
  434. esphome/components/psram/__init__.py +75 -11
  435. esphome/components/psram/psram.cpp +18 -7
  436. esphome/components/pulse_counter/sensor.py +4 -4
  437. esphome/components/pulse_meter/sensor.py +3 -3
  438. esphome/components/pulse_width/sensor.py +3 -8
  439. esphome/components/pvvx_mithermometer/display/__init__.py +1 -1
  440. esphome/components/pvvx_mithermometer/sensor.py +3 -3
  441. esphome/components/pylontech/__init__.py +1 -0
  442. esphome/components/pylontech/sensor/__init__.py +8 -13
  443. esphome/components/pylontech/text_sensor/__init__.py +2 -7
  444. esphome/components/pzem004t/sensor.py +3 -3
  445. esphome/components/pzemac/sensor.py +9 -9
  446. esphome/components/pzemdc/sensor.py +6 -6
  447. esphome/components/qmc5883l/sensor.py +5 -5
  448. esphome/components/qmp6988/sensor.py +3 -3
  449. esphome/components/qr_code/__init__.py +1 -1
  450. esphome/components/qspi_dbi/display.py +1 -1
  451. esphome/components/qspi_dbi/qspi_dbi.cpp +1 -1
  452. esphome/components/qspi_dbi/qspi_dbi.h +1 -1
  453. esphome/components/qwiic_pir/binary_sensor.py +2 -5
  454. esphome/components/radon_eye_ble/__init__.py +1 -1
  455. esphome/components/radon_eye_rd200/sensor.py +3 -4
  456. esphome/components/rc522/__init__.py +3 -3
  457. esphome/components/rc522_i2c/__init__.py +1 -1
  458. esphome/components/rc522_spi/__init__.py +1 -1
  459. esphome/components/rdm6300/__init__.py +2 -2
  460. esphome/components/rdm6300/binary_sensor.py +2 -1
  461. esphome/components/resistance/sensor.py +2 -2
  462. esphome/components/restart/button/__init__.py +1 -1
  463. esphome/components/restart/switch/__init__.py +2 -5
  464. esphome/components/rf_bridge/__init__.py +3 -3
  465. esphome/components/rgb/light.py +2 -2
  466. esphome/components/rgbct/light.py +3 -3
  467. esphome/components/rgbw/light.py +2 -2
  468. esphome/components/rgbww/light.py +4 -4
  469. esphome/components/rotary_encoder/sensor.py +8 -8
  470. esphome/components/rp2040_pio/__init__.py +0 -1
  471. esphome/components/rp2040_pio_led_strip/light.py +2 -4
  472. esphome/components/rp2040_pwm/output.py +3 -7
  473. esphome/components/rtttl/__init__.py +6 -6
  474. esphome/components/ruuvi_ble/__init__.py +1 -1
  475. esphome/components/ruuvitag/sensor.py +15 -15
  476. esphome/components/safe_mode/__init__.py +2 -3
  477. esphome/components/safe_mode/button/__init__.py +3 -2
  478. esphome/components/safe_mode/switch/__init__.py +4 -7
  479. esphome/components/scd30/sensor.py +5 -6
  480. esphome/components/scd4x/sensor.py +6 -8
  481. esphome/components/script/__init__.py +2 -2
  482. esphome/components/sdl/display.py +3 -3
  483. esphome/components/sdl/touchscreen/__init__.py +2 -2
  484. esphome/components/sdm_meter/sensor.py +3 -3
  485. esphome/components/sdp3x/sensor.py +1 -2
  486. esphome/components/sds011/sensor.py +4 -4
  487. esphome/components/seeed_mr24hpc1/__init__.py +1 -1
  488. esphome/components/seeed_mr24hpc1/binary_sensor.py +2 -5
  489. esphome/components/seeed_mr24hpc1/button/__init__.py +1 -0
  490. esphome/components/seeed_mr24hpc1/number/__init__.py +2 -4
  491. esphome/components/seeed_mr24hpc1/select/__init__.py +2 -3
  492. esphome/components/seeed_mr24hpc1/sensor.py +1 -0
  493. esphome/components/seeed_mr24hpc1/switch/__init__.py +2 -4
  494. esphome/components/seeed_mr24hpc1/text_sensor.py +1 -0
  495. esphome/components/seeed_mr60bha2/binary_sensor.py +2 -4
  496. esphome/components/seeed_mr60bha2/sensor.py +1 -1
  497. esphome/components/seeed_mr60fda2/button/__init__.py +1 -1
  498. esphome/components/seeed_mr60fda2/select/__init__.py +0 -1
  499. esphome/components/selec_meter/sensor.py +1 -1
  500. esphome/components/sen0321/sensor.py +2 -2
  501. esphome/components/sen21231/sensor.py +1 -1
  502. esphome/components/senseair/sensor.py +3 -3
  503. esphome/components/sensirion_common/__init__.py +0 -2
  504. esphome/components/servo/__init__.py +3 -3
  505. esphome/components/sfa30/sensor.py +4 -5
  506. esphome/components/sgp4x/sensor.py +2 -2
  507. esphome/components/shelly_dimmer/light.py +16 -16
  508. esphome/components/sht3xd/sensor.py +1 -1
  509. esphome/components/sht4x/sensor.py +6 -6
  510. esphome/components/shtcx/sensor.py +1 -1
  511. esphome/components/shutdown/button/__init__.py +2 -6
  512. esphome/components/shutdown/switch/__init__.py +2 -5
  513. esphome/components/sigma_delta_output/output.py +2 -7
  514. esphome/components/sim800l/__init__.py +3 -7
  515. esphome/components/sim800l/binary_sensor.py +3 -5
  516. esphome/components/sim800l/sensor.py +2 -1
  517. esphome/components/slow_pwm/output.py +4 -5
  518. esphome/components/sm10bit_base/__init__.py +2 -6
  519. esphome/components/sm16716/__init__.py +1 -1
  520. esphome/components/sm16716/output.py +2 -1
  521. esphome/components/sm2135/__init__.py +2 -6
  522. esphome/components/sm2135/output.py +2 -1
  523. esphome/components/sm2235/__init__.py +1 -1
  524. esphome/components/sm2235/output.py +2 -1
  525. esphome/components/sm2335/__init__.py +1 -1
  526. esphome/components/sm2335/output.py +2 -1
  527. esphome/components/sm300d2/sensor.py +13 -13
  528. esphome/components/sml/__init__.py +1 -1
  529. esphome/components/sml/sensor/__init__.py +1 -1
  530. esphome/components/sml/sml.cpp +8 -6
  531. esphome/components/sml/sml.h +1 -1
  532. esphome/components/sml/sml_parser.cpp +16 -18
  533. esphome/components/sml/sml_parser.h +42 -12
  534. esphome/components/sml/text_sensor/__init__.py +1 -1
  535. esphome/components/smt100/sensor.py +5 -6
  536. esphome/components/sn74hc165/__init__.py +5 -5
  537. esphome/components/sn74hc595/__init__.py +5 -5
  538. esphome/components/socket/__init__.py +1 -1
  539. esphome/components/sonoff_d1/light.py +2 -6
  540. esphome/components/speaker/media_player/audio_pipeline.cpp +3 -2
  541. esphome/components/speaker/media_player/speaker_media_player.cpp +47 -12
  542. esphome/components/speed/fan/__init__.py +2 -2
  543. esphome/components/spi/__init__.py +45 -36
  544. esphome/components/spi/spi.h +1 -0
  545. esphome/components/spi/spi_esp_idf.cpp +13 -5
  546. esphome/components/sprinkler/__init__.py +4 -5
  547. esphome/components/sps30/sensor.py +8 -8
  548. esphome/components/ssd1306_i2c/display.py +2 -2
  549. esphome/components/ssd1322_base/__init__.py +2 -2
  550. esphome/components/ssd1325_base/__init__.py +2 -2
  551. esphome/components/ssd1327_base/__init__.py +2 -2
  552. esphome/components/ssd1327_i2c/display.py +1 -1
  553. esphome/components/ssd1331_base/__init__.py +2 -2
  554. esphome/components/ssd1351_base/__init__.py +2 -2
  555. esphome/components/st7567_base/__init__.py +4 -4
  556. esphome/components/st7567_i2c/display.py +1 -1
  557. esphome/components/st7920/display.py +2 -2
  558. esphome/components/statsd/__init__.py +3 -3
  559. esphome/components/status/binary_sensor.py +2 -5
  560. esphome/components/status_led/__init__.py +1 -1
  561. esphome/components/status_led/light/__init__.py +2 -1
  562. esphome/components/stepper/__init__.py +2 -2
  563. esphome/components/sts3x/sensor.py +1 -1
  564. esphome/components/substitutions/__init__.py +2 -2
  565. esphome/components/sun/__init__.py +4 -4
  566. esphome/components/sun/sensor/__init__.py +4 -7
  567. esphome/components/sun/text_sensor/__init__.py +5 -4
  568. esphome/components/sun_gtil2/__init__.py +1 -1
  569. esphome/components/sun_gtil2/sensor.py +7 -6
  570. esphome/components/sun_gtil2/text_sensor.py +3 -2
  571. esphome/components/sx1509/__init__.py +5 -5
  572. esphome/components/sx1509/binary_sensor/__init__.py +3 -3
  573. esphome/components/sx1509/output/__init__.py +4 -3
  574. esphome/components/t6615/sensor.py +1 -1
  575. esphome/components/tca9548a/__init__.py +1 -1
  576. esphome/components/tcl112/climate.py +1 -1
  577. esphome/components/tcs34725/sensor.py +4 -4
  578. esphome/components/tee501/sensor.py +1 -1
  579. esphome/components/teleinfo/__init__.py +1 -1
  580. esphome/components/teleinfo/sensor/__init__.py +1 -7
  581. esphome/components/teleinfo/text_sensor/__init__.py +1 -1
  582. esphome/components/tem3200/sensor.py +1 -2
  583. esphome/components/template/alarm_control_panel/__init__.py +3 -10
  584. esphome/components/template/cover/__init__.py +4 -3
  585. esphome/components/template/datetime/__init__.py +8 -9
  586. esphome/components/template/event/__init__.py +2 -5
  587. esphome/components/template/fan/__init__.py +2 -6
  588. esphome/components/template/lock/__init__.py +3 -2
  589. esphome/components/template/number/__init__.py +3 -2
  590. esphome/components/template/output/__init__.py +4 -3
  591. esphome/components/template/select/__init__.py +3 -2
  592. esphome/components/template/sensor/__init__.py +4 -7
  593. esphome/components/template/switch/__init__.py +3 -2
  594. esphome/components/template/text/__init__.py +4 -3
  595. esphome/components/template/text_sensor/__init__.py +3 -2
  596. esphome/components/template/valve/__init__.py +3 -2
  597. esphome/components/time/real_time_clock.cpp +0 -4
  598. esphome/components/time/real_time_clock.h +4 -3
  599. esphome/components/time_based/cover.py +3 -3
  600. esphome/components/tlc59208f/__init__.py +1 -1
  601. esphome/components/tlc59208f/output.py +2 -1
  602. esphome/components/tlc5947/__init__.py +1 -1
  603. esphome/components/tlc5947/output/__init__.py +2 -1
  604. esphome/components/tlc5971/__init__.py +2 -8
  605. esphome/components/tlc5971/output/__init__.py +2 -1
  606. esphome/components/tm1621/display.py +3 -3
  607. esphome/components/tm1637/binary_sensor.py +1 -1
  608. esphome/components/tm1637/display.py +3 -3
  609. esphome/components/tm1651/__init__.py +4 -4
  610. esphome/components/tmp102/sensor.py +1 -1
  611. esphome/components/tmp1075/sensor.py +2 -2
  612. esphome/components/tmp117/sensor.py +1 -1
  613. esphome/components/tof10120/sensor.py +2 -2
  614. esphome/components/tormatic/cover.py +2 -6
  615. esphome/components/toshiba/climate.py +1 -1
  616. esphome/components/total_daily_energy/sensor.py +4 -4
  617. esphome/components/tsl2561/sensor.py +1 -1
  618. esphome/components/tsl2591/sensor.py +9 -9
  619. esphome/components/tt21100/binary_sensor/__init__.py +2 -2
  620. esphome/components/tt21100/touchscreen/__init__.py +2 -3
  621. esphome/components/ttp229_bsf/__init__.py +2 -2
  622. esphome/components/ttp229_bsf/binary_sensor.py +3 -2
  623. esphome/components/ttp229_lsf/__init__.py +1 -1
  624. esphome/components/ttp229_lsf/binary_sensor.py +3 -2
  625. esphome/components/tuya/__init__.py +3 -5
  626. esphome/components/tuya/binary_sensor/__init__.py +2 -2
  627. esphome/components/tuya/climate/__init__.py +6 -5
  628. esphome/components/tuya/cover/__init__.py +5 -4
  629. esphome/components/tuya/fan/__init__.py +3 -2
  630. esphome/components/tuya/light/__init__.py +9 -8
  631. esphome/components/tuya/number/__init__.py +6 -5
  632. esphome/components/tuya/select/__init__.py +4 -3
  633. esphome/components/tuya/sensor/__init__.py +3 -2
  634. esphome/components/tuya/switch/__init__.py +3 -2
  635. esphome/components/tuya/text_sensor/__init__.py +3 -2
  636. esphome/components/tx20/sensor.py +6 -6
  637. esphome/components/uart/__init__.py +20 -19
  638. esphome/components/uart/button/__init__.py +2 -1
  639. esphome/components/uart/switch/__init__.py +2 -1
  640. esphome/components/ufire_ise/sensor.py +2 -2
  641. esphome/components/uln2003/stepper.py +2 -2
  642. esphome/components/ultrasonic/sensor.py +4 -4
  643. esphome/components/uponor_smatrix/__init__.py +2 -6
  644. esphome/components/uponor_smatrix/climate/__init__.py +3 -3
  645. esphome/components/vbus/__init__.py +1 -1
  646. esphome/components/vbus/binary_sensor/__init__.py +7 -6
  647. esphome/components/vbus/sensor/__init__.py +7 -6
  648. esphome/components/veml3235/sensor.py +1 -1
  649. esphome/components/veml7700/sensor.py +1 -1
  650. esphome/components/version/text_sensor.py +2 -6
  651. esphome/components/vl53l0x/sensor.py +6 -6
  652. esphome/components/web_server_base/__init__.py +2 -2
  653. esphome/components/web_server_idf/__init__.py +1 -1
  654. esphome/components/weikai/__init__.py +1 -1
  655. esphome/components/whirlpool/climate.py +1 -1
  656. esphome/components/whynter/climate.py +1 -1
  657. esphome/components/wireguard/binary_sensor.py +1 -1
  658. esphome/components/wireguard/sensor.py +2 -5
  659. esphome/components/wireguard/text_sensor.py +2 -5
  660. esphome/components/wk2132_i2c/__init__.py +1 -1
  661. esphome/components/wk2132_spi/__init__.py +1 -2
  662. esphome/components/wk2168_i2c/__init__.py +3 -8
  663. esphome/components/wk2168_spi/__init__.py +3 -8
  664. esphome/components/wk2204_i2c/__init__.py +1 -1
  665. esphome/components/wk2204_spi/__init__.py +1 -1
  666. esphome/components/wk2212_i2c/__init__.py +3 -8
  667. esphome/components/wk2212_spi/__init__.py +3 -8
  668. esphome/components/wl_134/text_sensor.py +2 -4
  669. esphome/components/wled/__init__.py +2 -2
  670. esphome/components/x9c/output.py +4 -4
  671. esphome/components/xgzp68xx/sensor.py +5 -5
  672. esphome/components/xiaomi_ble/__init__.py +1 -1
  673. esphome/components/xiaomi_cgd1/sensor.py +3 -3
  674. esphome/components/xiaomi_cgdk2/sensor.py +3 -3
  675. esphome/components/xiaomi_cgg1/sensor.py +2 -2
  676. esphome/components/xiaomi_cgpr1/binary_sensor.py +6 -6
  677. esphome/components/xiaomi_gcls002/sensor.py +7 -7
  678. esphome/components/xiaomi_hhccjcy01/sensor.py +9 -9
  679. esphome/components/xiaomi_hhccjcy10/sensor.py +9 -9
  680. esphome/components/xiaomi_hhccpot002/sensor.py +7 -7
  681. esphome/components/xiaomi_jqjcy01ym/sensor.py +6 -6
  682. esphome/components/xiaomi_lywsd02/sensor.py +4 -4
  683. esphome/components/xiaomi_lywsd02mmc/sensor.py +5 -5
  684. esphome/components/xiaomi_lywsd03mmc/sensor.py +6 -6
  685. esphome/components/xiaomi_lywsdcgq/sensor.py +5 -5
  686. esphome/components/xiaomi_mhoc303/sensor.py +4 -4
  687. esphome/components/xiaomi_mhoc401/sensor.py +6 -6
  688. esphome/components/xiaomi_miscale/sensor.py +6 -6
  689. esphome/components/xiaomi_mjyd02yla/binary_sensor.py +8 -8
  690. esphome/components/xiaomi_mue4094rt/binary_sensor.py +2 -7
  691. esphome/components/xiaomi_rtcgq02lm/__init__.py +2 -3
  692. esphome/components/xiaomi_rtcgq02lm/binary_sensor.py +3 -3
  693. esphome/components/xiaomi_rtcgq02lm/sensor.py +3 -3
  694. esphome/components/xiaomi_wx08zm/binary_sensor.py +2 -3
  695. esphome/components/xl9535/__init__.py +2 -2
  696. esphome/components/yashima/climate.py +1 -1
  697. esphome/components/zhlt01/climate.py +1 -1
  698. esphome/components/zio_ultrasonic/sensor.py +2 -5
  699. esphome/components/zyaura/sensor.py +7 -7
  700. esphome/config_validation.py +0 -42
  701. esphome/const.py +3 -1
  702. esphome/core/__init__.py +0 -1
  703. esphome/core/component.cpp +3 -1
  704. esphome/core/component.h +15 -2
  705. esphome/core/config.py +4 -0
  706. esphome/core/defines.h +21 -0
  707. esphome/core/helpers.cpp +6 -7
  708. esphome/core/scheduler.cpp +34 -67
  709. esphome/core/scheduler.h +7 -17
  710. esphome/dashboard/status/mqtt.py +0 -2
  711. esphome/vscode.py +27 -8
  712. esphome/yaml_util.py +75 -39
  713. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info}/METADATA +45 -44
  714. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info}/RECORD +718 -711
  715. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info}/WHEEL +1 -1
  716. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info}/entry_points.txt +0 -0
  717. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info/licenses}/LICENSE +0 -0
  718. {esphome-2025.3.2.dist-info → esphome-2025.4.0.dist-info}/top_level.txt +0 -0
@@ -4,6 +4,7 @@ from esphome import automation
4
4
  import esphome.codegen as cg
5
5
  import esphome.config_validation as cv
6
6
  from esphome.const import CONF_ACTION, CONF_GROUP, CONF_ID, CONF_TIMEOUT
7
+ from esphome.core import Lambda
7
8
  from esphome.cpp_generator import TemplateArguments, get_variable
8
9
  from esphome.cpp_types import nullptr
9
10
 
@@ -17,6 +18,7 @@ from .defines import (
17
18
  CONF_SHOW_SNOW,
18
19
  PARTS,
19
20
  literal,
21
+ static_cast,
20
22
  )
21
23
  from .lv_validation import lv_bool, lv_color, lv_image, opacity
22
24
  from .lvcode import (
@@ -32,7 +34,6 @@ from .lvcode import (
32
34
  lv_expr,
33
35
  lv_obj,
34
36
  lvgl_comp,
35
- static_cast,
36
37
  )
37
38
  from .schemas import DISP_BG_SCHEMA, LIST_ACTION_SCHEMA, LVGL_SCHEMA, base_update_schema
38
39
  from .types import (
@@ -64,7 +65,14 @@ async def action_to_code(
64
65
  action_id,
65
66
  template_arg,
66
67
  args,
68
+ config=None,
67
69
  ):
70
+ # Ensure all required ids have been processed, so our LambdaContext doesn't get context-switched.
71
+ if config:
72
+ for lamb in config.values():
73
+ if isinstance(lamb, Lambda):
74
+ for id_ in lamb.requires_ids:
75
+ await get_variable(id_)
68
76
  await wait_for_widgets()
69
77
  async with LambdaContext(parameters=args, where=action_id) as context:
70
78
  for widget in widgets:
@@ -84,7 +92,9 @@ async def update_to_code(config, action_id, template_arg, args):
84
92
  lv.event_send(widget.obj, UPDATE_EVENT, nullptr)
85
93
 
86
94
  widgets = await get_widgets(config[CONF_ID])
87
- return await action_to_code(widgets, do_update, action_id, template_arg, args)
95
+ return await action_to_code(
96
+ widgets, do_update, action_id, template_arg, args, config
97
+ )
88
98
 
89
99
 
90
100
  @automation.register_condition(
@@ -348,4 +358,6 @@ async def obj_update_to_code(config, action_id, template_arg, args):
348
358
  await set_obj_properties(widget, config)
349
359
 
350
360
  widgets = await get_widgets(config[CONF_ID])
351
- return await action_to_code(widgets, do_update, action_id, template_arg, args)
361
+ return await action_to_code(
362
+ widgets, do_update, action_id, template_arg, args, config
363
+ )
@@ -29,12 +29,16 @@ def add_define(macro, value="1"):
29
29
  lv_defines[macro] = value
30
30
 
31
31
 
32
- def literal(arg):
32
+ def literal(arg) -> MockObj:
33
33
  if isinstance(arg, str):
34
34
  return MockObj(arg)
35
35
  return arg
36
36
 
37
37
 
38
+ def static_cast(type, value):
39
+ return literal(f"static_cast<{type}>({value})")
40
+
41
+
38
42
  def call_lambda(lamb: LambdaExpression):
39
43
  expr = lamb.content.strip()
40
44
  if expr.startswith("return") and expr.endswith(";"):
@@ -416,7 +420,6 @@ CONF_CHANGE_RATE = "change_rate"
416
420
  CONF_CLOSE_BUTTON = "close_button"
417
421
  CONF_COLOR_DEPTH = "color_depth"
418
422
  CONF_CONTROL = "control"
419
- CONF_DEFAULT = "default"
420
423
  CONF_DEFAULT_FONT = "default_font"
421
424
  CONF_DEFAULT_GROUP = "default_group"
422
425
  CONF_DIR = "dir"
@@ -18,6 +18,7 @@ from .helpers import lvgl_components_required, requires_component
18
18
  from .lvcode import lv, lv_add, lv_assign, lv_expr, lv_Pvariable
19
19
  from .schemas import ENCODER_SCHEMA
20
20
  from .types import lv_group_t, lv_indev_type_t, lv_key_t
21
+ from .widgets import get_widgets
21
22
 
22
23
  ENCODERS_CONFIG = cv.ensure_list(
23
24
  ENCODER_SCHEMA.extend(
@@ -76,5 +77,5 @@ async def encoders_to_code(var, config, default_group):
76
77
  async def initial_focus_to_code(config):
77
78
  for enc_conf in config[CONF_ENCODERS]:
78
79
  if default_focus := enc_conf.get(CONF_INITIAL_FOCUS):
79
- obj = await cg.get_variable(default_focus)
80
- lv.group_focus_obj(obj)
80
+ widget = await get_widgets(default_focus)
81
+ lv.group_focus_obj(widget[0].obj)
@@ -254,11 +254,27 @@ def pixels_or_percent_validator(value):
254
254
  pixels_or_percent = LValidator(pixels_or_percent_validator, uint32, retmapper=literal)
255
255
 
256
256
 
257
- def zoom(value):
257
+ def pixels_validator(value):
258
+ if isinstance(value, str) and value.lower().endswith("px"):
259
+ value = value[:-2]
260
+ return cv.positive_int(value)
261
+
262
+
263
+ pixels = LValidator(pixels_validator, uint32, retmapper=literal)
264
+
265
+
266
+ def zoom_validator(value):
258
267
  value = cv.float_range(0.1, 10.0)(value)
268
+ return value
269
+
270
+
271
+ def zoom_retmapper(value):
259
272
  return int(value * 256)
260
273
 
261
274
 
275
+ zoom = LValidator(zoom_validator, uint32, retmapper=zoom_retmapper)
276
+
277
+
262
278
  def angle(value):
263
279
  """
264
280
  Validation for an angle in degrees, converted to an integer representing 0.1deg units
@@ -286,14 +302,6 @@ def size_validator(value):
286
302
  size = LValidator(size_validator, uint32, retmapper=literal)
287
303
 
288
304
 
289
- def pixels_validator(value):
290
- if isinstance(value, str) and value.lower().endswith("px"):
291
- return cv.int_(value[:-2])
292
- return cv.int_(value)
293
-
294
-
295
- pixels = LValidator(pixels_validator, uint32, retmapper=literal)
296
-
297
305
  radius_consts = LvConstant("LV_RADIUS_", "CIRCLE")
298
306
 
299
307
 
@@ -173,7 +173,8 @@ class LambdaContext(CodeContext):
173
173
 
174
174
  class LvContext(LambdaContext):
175
175
  """
176
- Code generation into the LVGL initialisation code (called in `setup()`)
176
+ Code generation into the LVGL initialisation code, called before setup() and loop()
177
+ Basically just does cg.add, so now fairly redundant.
177
178
  """
178
179
 
179
180
  added_lambda_count = 0
@@ -206,11 +207,16 @@ class LocalVariable(MockObj):
206
207
 
207
208
  def __enter__(self):
208
209
  CodeContext.start_block()
209
- CodeContext.append(
210
- VariableDeclarationExpression(self.base.type, self.modifier, self.base.id)
211
- )
212
210
  if self.rhs is not None:
213
- CodeContext.append(AssignmentExpression(None, "", self.base, self.rhs))
211
+ CodeContext.append(
212
+ AssignmentExpression(self.base.type, self.modifier, self.base, self.rhs)
213
+ )
214
+ else:
215
+ CodeContext.append(
216
+ VariableDeclarationExpression(
217
+ self.base.type, self.modifier, self.base.id
218
+ )
219
+ )
214
220
  return MockObj(self.base)
215
221
 
216
222
  def __exit__(self, *args):
@@ -285,10 +291,6 @@ class LvExpr(MockLv):
285
291
  pass
286
292
 
287
293
 
288
- def static_cast(type, value):
289
- return literal(f"static_cast<{type}>({value})")
290
-
291
-
292
294
  # Top level mock for generic lv_ calls to be recorded
293
295
  lv = MockLv("lv_")
294
296
  # Just generate an expression
@@ -63,6 +63,13 @@ inline void lv_disp_set_bg_image(lv_disp_t *disp, esphome::image::Image *image)
63
63
  inline void lv_obj_set_style_bg_img_src(lv_obj_t *obj, esphome::image::Image *image, lv_style_selector_t selector) {
64
64
  lv_obj_set_style_bg_img_src(obj, image->get_lv_img_dsc(), selector);
65
65
  }
66
+ #ifdef USE_LVGL_CANVAS
67
+ inline void lv_canvas_draw_img(lv_obj_t *canvas, lv_coord_t x, lv_coord_t y, image::Image *image,
68
+ lv_draw_img_dsc_t *dsc) {
69
+ lv_canvas_draw_img(canvas, x, y, image->get_lv_img_dsc(), dsc);
70
+ }
71
+ #endif
72
+
66
73
  #ifdef USE_LVGL_METER
67
74
  inline lv_meter_indicator_t *lv_meter_add_needle_img(lv_obj_t *obj, lv_meter_scale_t *scale, esphome::image::Image *src,
68
75
  lv_coord_t pivot_x, lv_coord_t pivot_y) {
@@ -90,6 +97,7 @@ inline void lv_animimg_set_src(lv_obj_t *img, std::vector<image::Image *> images
90
97
  // Parent class for things that wrap an LVGL object
91
98
  class LvCompound {
92
99
  public:
100
+ virtual ~LvCompound() = default;
93
101
  virtual void set_obj(lv_obj_t *lv_obj) { this->obj = lv_obj; }
94
102
  lv_obj_t *obj{};
95
103
  };
@@ -330,6 +338,19 @@ class LVEncoderListener : public Parented<LvglComponent> {
330
338
  };
331
339
  #endif // USE_LVGL_KEY_LISTENER
332
340
 
341
+ #ifdef USE_LVGL_LINE
342
+ class LvLineType : public LvCompound {
343
+ public:
344
+ std::vector<lv_point_t> get_points() { return this->points_; }
345
+ void set_points(std::vector<lv_point_t> points) {
346
+ this->points_ = std::move(points);
347
+ lv_line_set_points(this->obj, this->points_.data(), this->points_.size());
348
+ }
349
+
350
+ protected:
351
+ std::vector<lv_point_t> points_{};
352
+ };
353
+ #endif
333
354
  #if defined(USE_LVGL_DROPDOWN) || defined(LV_USE_ROLLER)
334
355
  class LvSelectable : public LvCompound {
335
356
  public:
@@ -1,6 +1,7 @@
1
1
  import esphome.codegen as cg
2
2
  from esphome.components import number
3
3
  import esphome.config_validation as cv
4
+ from esphome.const import CONF_RESTORE_VALUE
4
5
  from esphome.cpp_generator import MockObj
5
6
 
6
7
  from ..defines import CONF_ANIMATED, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
@@ -10,21 +11,21 @@ from ..lvcode import (
10
11
  EVENT_ARG,
11
12
  UPDATE_EVENT,
12
13
  LambdaContext,
13
- LvContext,
14
+ ReturnStatement,
14
15
  lv,
15
- lv_add,
16
16
  lvgl_static,
17
17
  )
18
18
  from ..types import LV_EVENT, LvNumber, lvgl_ns
19
19
  from ..widgets import get_widgets, wait_for_widgets
20
20
 
21
- LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
21
+ LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number, cg.Component)
22
22
 
23
23
  CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
24
24
  {
25
25
  cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
26
26
  cv.Optional(CONF_ANIMATED, default=True): animated,
27
27
  cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
28
+ cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
28
29
  }
29
30
  )
30
31
 
@@ -32,32 +33,34 @@ CONFIG_SCHEMA = number.number_schema(LVGLNumber).extend(
32
33
  async def to_code(config):
33
34
  widget = await get_widgets(config, CONF_WIDGET)
34
35
  widget = widget[0]
35
- var = await number.new_number(
36
- config,
37
- max_value=widget.get_max(),
38
- min_value=widget.get_min(),
39
- step=widget.get_step(),
40
- )
41
-
42
36
  await wait_for_widgets()
37
+ async with LambdaContext([], return_type=cg.float_) as value:
38
+ value.add(ReturnStatement(widget.get_value()))
43
39
  async with LambdaContext([(cg.float_, "v")]) as control:
44
40
  await widget.set_property(
45
41
  "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
46
42
  )
47
43
  lv.event_send(widget.obj, API_EVENT, cg.nullptr)
48
- control.add(var.publish_state(widget.get_value()))
49
- async with LambdaContext(EVENT_ARG) as event:
50
- event.add(var.publish_state(widget.get_value()))
51
44
  event_code = (
52
45
  LV_EVENT.VALUE_CHANGED
53
46
  if not config[CONF_UPDATE_ON_RELEASE]
54
47
  else LV_EVENT.RELEASED
55
48
  )
56
- async with LvContext():
57
- lv_add(var.set_control_lambda(await control.get_lambda()))
58
- lv_add(
59
- lvgl_static.add_event_cb(
60
- widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
61
- )
49
+ var = await number.new_number(
50
+ config,
51
+ await control.get_lambda(),
52
+ await value.get_lambda(),
53
+ event_code,
54
+ config[CONF_RESTORE_VALUE],
55
+ max_value=widget.get_max(),
56
+ min_value=widget.get_min(),
57
+ step=widget.get_step(),
58
+ )
59
+ async with LambdaContext(EVENT_ARG) as event:
60
+ event.add(var.on_value())
61
+ await cg.register_component(var, config)
62
+ cg.add(
63
+ lvgl_static.add_event_cb(
64
+ widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
62
65
  )
63
- lv_add(var.publish_state(widget.get_value()))
66
+ )
@@ -3,33 +3,46 @@
3
3
  #include <utility>
4
4
 
5
5
  #include "esphome/components/number/number.h"
6
- #include "esphome/core/automation.h"
7
6
  #include "esphome/core/component.h"
8
7
  #include "esphome/core/preferences.h"
9
8
 
10
9
  namespace esphome {
11
10
  namespace lvgl {
12
11
 
13
- class LVGLNumber : public number::Number {
12
+ class LVGLNumber : public number::Number, public Component {
14
13
  public:
15
- void set_control_lambda(std::function<void(float)> control_lambda) {
16
- this->control_lambda_ = std::move(control_lambda);
17
- if (this->initial_state_.has_value()) {
18
- this->control_lambda_(this->initial_state_.value());
19
- this->initial_state_.reset();
14
+ LVGLNumber(std::function<void(float)> control_lambda, std::function<float()> value_lambda, lv_event_code_t event,
15
+ bool restore)
16
+ : control_lambda_(std::move(control_lambda)),
17
+ value_lambda_(std::move(value_lambda)),
18
+ event_(event),
19
+ restore_(restore) {}
20
+
21
+ void setup() override {
22
+ float value = this->value_lambda_();
23
+ if (this->restore_) {
24
+ this->pref_ = global_preferences->make_preference<float>(this->get_object_id_hash());
25
+ if (this->pref_.load(&value)) {
26
+ this->control_lambda_(value);
27
+ }
20
28
  }
29
+ this->publish_state(value);
21
30
  }
22
31
 
32
+ void on_value() { this->publish_state(this->value_lambda_()); }
33
+
23
34
  protected:
24
35
  void control(float value) override {
25
- if (this->control_lambda_ != nullptr) {
26
- this->control_lambda_(value);
27
- } else {
28
- this->initial_state_ = value;
29
- }
36
+ this->control_lambda_(value);
37
+ this->publish_state(value);
38
+ if (this->restore_)
39
+ this->pref_.save(&value);
30
40
  }
31
- std::function<void(float)> control_lambda_{};
32
- optional<float> initial_state_{};
41
+ std::function<void(float)> control_lambda_;
42
+ std::function<float()> value_lambda_;
43
+ lv_event_code_t event_;
44
+ bool restore_;
45
+ ESPPreferenceObject pref_{};
33
46
  };
34
47
 
35
48
  } // namespace lvgl
@@ -6,6 +6,7 @@ from esphome.const import (
6
6
  CONF_FORMAT,
7
7
  CONF_GROUP,
8
8
  CONF_ID,
9
+ CONF_ON_BOOT,
9
10
  CONF_ON_VALUE,
10
11
  CONF_STATE,
11
12
  CONF_TEXT,
@@ -14,10 +15,11 @@ from esphome.const import (
14
15
  CONF_TYPE,
15
16
  )
16
17
  from esphome.core import TimePeriod
18
+ from esphome.core.config import StartupTrigger
17
19
  from esphome.schema_extractors import SCHEMA_EXTRACT
18
20
 
19
21
  from . import defines as df, lv_validation as lvalid
20
- from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
22
+ from .defines import CONF_TIME_FORMAT, CONF_X, CONF_Y, LV_GRAD_DIR
21
23
  from .helpers import add_lv_use, requires_component, validate_printf
22
24
  from .lv_validation import lv_color, lv_font, lv_gradient, lv_image, opacity
23
25
  from .lvcode import LvglComponent, lv_event_t_ptr
@@ -79,12 +81,39 @@ ENCODER_SCHEMA = cv.Schema(
79
81
  cv.declare_id(LVEncoderListener), requires_component("binary_sensor")
80
82
  ),
81
83
  cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t),
82
- cv.Optional(df.CONF_INITIAL_FOCUS): cv.use_id(lv_obj_t),
84
+ cv.Optional(df.CONF_INITIAL_FOCUS): cv.All(
85
+ LIST_ACTION_SCHEMA, cv.Length(min=1, max=1)
86
+ ),
83
87
  cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME,
84
88
  cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME,
85
89
  }
86
90
  )
87
91
 
92
+ POINT_SCHEMA = cv.Schema(
93
+ {
94
+ cv.Required(CONF_X): cv.templatable(cv.int_),
95
+ cv.Required(CONF_Y): cv.templatable(cv.int_),
96
+ }
97
+ )
98
+
99
+
100
+ def point_schema(value):
101
+ """
102
+ A shorthand for a point in the form of x,y
103
+ :param value: The value to check
104
+ :return: The value as a tuple of x,y
105
+ """
106
+ if isinstance(value, dict):
107
+ return POINT_SCHEMA(value)
108
+ try:
109
+ x, y = map(int, value.split(","))
110
+ return {CONF_X: x, CONF_Y: y}
111
+ except ValueError:
112
+ pass
113
+ # not raising this in the catch block because pylint doesn't like it
114
+ raise cv.Invalid("Invalid point format, should be <x_int>, <y_int>")
115
+
116
+
88
117
  # All LVGL styles and their validators
89
118
  STYLE_PROPS = {
90
119
  "align": df.CHILD_ALIGNMENTS.one_of,
@@ -103,6 +132,7 @@ STYLE_PROPS = {
103
132
  "bg_image_recolor": lvalid.lv_color,
104
133
  "bg_image_recolor_opa": lvalid.opacity,
105
134
  "bg_image_src": lvalid.lv_image,
135
+ "bg_image_tiled": lvalid.lv_bool,
106
136
  "bg_main_stop": lvalid.stop_value,
107
137
  "bg_opa": lvalid.opacity,
108
138
  "border_color": lvalid.lv_color,
@@ -117,9 +147,9 @@ STYLE_PROPS = {
117
147
  "height": lvalid.size,
118
148
  "image_recolor": lvalid.lv_color,
119
149
  "image_recolor_opa": lvalid.opacity,
120
- "line_width": cv.positive_int,
121
- "line_dash_width": cv.positive_int,
122
- "line_dash_gap": cv.positive_int,
150
+ "line_width": lvalid.lv_positive_int,
151
+ "line_dash_width": lvalid.lv_positive_int,
152
+ "line_dash_gap": lvalid.lv_positive_int,
123
153
  "line_rounded": lvalid.lv_bool,
124
154
  "line_color": lvalid.lv_color,
125
155
  "opa": lvalid.opacity,
@@ -147,8 +177,8 @@ STYLE_PROPS = {
147
177
  "LV_TEXT_DECOR_", "NONE", "UNDERLINE", "STRIKETHROUGH"
148
178
  ).several_of,
149
179
  "text_font": lv_font,
150
- "text_letter_space": cv.positive_int,
151
- "text_line_space": cv.positive_int,
180
+ "text_letter_space": lvalid.lv_positive_int,
181
+ "text_line_space": lvalid.lv_positive_int,
152
182
  "text_opa": lvalid.opacity,
153
183
  "transform_angle": lvalid.lv_angle,
154
184
  "transform_height": lvalid.pixels_or_percent,
@@ -172,10 +202,15 @@ STYLE_REMAP = {
172
202
  "bg_image_recolor": "bg_img_recolor",
173
203
  "bg_image_recolor_opa": "bg_img_recolor_opa",
174
204
  "bg_image_src": "bg_img_src",
205
+ "bg_image_tiled": "bg_img_tiled",
175
206
  "image_recolor": "img_recolor",
176
207
  "image_recolor_opa": "img_recolor_opa",
177
208
  }
178
209
 
210
+ cell_alignments = df.LV_CELL_ALIGNMENTS.one_of
211
+ grid_alignments = df.LV_GRID_ALIGNMENTS.one_of
212
+ flex_alignments = df.LV_FLEX_ALIGNMENTS.one_of
213
+
179
214
  # Complete object style schema
180
215
  STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend(
181
216
  {
@@ -186,6 +221,16 @@ STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).ex
186
221
  }
187
222
  )
188
223
 
224
+ # Also allow widget specific properties for use in style definitions
225
+ FULL_STYLE_SCHEMA = STYLE_SCHEMA.extend(
226
+ {
227
+ cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments,
228
+ cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments,
229
+ cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
230
+ cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
231
+ }
232
+ )
233
+
189
234
  # Object states. Top level properties apply to MAIN
190
235
  STATE_SCHEMA = cv.Schema(
191
236
  {cv.Optional(state): STYLE_SCHEMA for state in df.STATES}
@@ -216,14 +261,24 @@ def automation_schema(typ: LvType):
216
261
  events = events + (CONF_ON_VALUE,)
217
262
  args = typ.get_arg_type() if isinstance(typ, LvType) else []
218
263
  args.append(lv_event_t_ptr)
219
- return {
220
- cv.Optional(event): validate_automation(
221
- {
222
- cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template(*args)),
223
- }
224
- )
225
- for event in events
226
- }
264
+ return cv.Schema(
265
+ {
266
+ cv.Optional(event): validate_automation(
267
+ {
268
+ cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
269
+ Trigger.template(*args)
270
+ ),
271
+ }
272
+ )
273
+ for event in events
274
+ }
275
+ ).extend(
276
+ {
277
+ cv.Optional(CONF_ON_BOOT): validate_automation(
278
+ {cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StartupTrigger)}
279
+ )
280
+ }
281
+ )
227
282
 
228
283
 
229
284
  def base_update_schema(widget_type, parts):
@@ -307,10 +362,6 @@ grid_spec = cv.Any(
307
362
  lvalid.size, df.LvConstant("LV_GRID_", "CONTENT").one_of, grid_free_space
308
363
  )
309
364
 
310
- cell_alignments = df.LV_CELL_ALIGNMENTS.one_of
311
- grid_alignments = df.LV_GRID_ALIGNMENTS.one_of
312
- flex_alignments = df.LV_FLEX_ALIGNMENTS.one_of
313
-
314
365
  LAYOUT_SCHEMA = {
315
366
  cv.Optional(df.CONF_LAYOUT): cv.typed_schema(
316
367
  {
@@ -1,18 +1,19 @@
1
+ import esphome.codegen as cg
1
2
  from esphome.components import select
2
3
  import esphome.config_validation as cv
3
- from esphome.const import CONF_OPTIONS
4
+ from esphome.const import CONF_ID, CONF_OPTIONS, CONF_RESTORE_VALUE
4
5
 
5
6
  from ..defines import CONF_ANIMATED, CONF_WIDGET, literal
6
- from ..lvcode import LvContext
7
7
  from ..types import LvSelect, lvgl_ns
8
- from ..widgets import get_widgets, wait_for_widgets
8
+ from ..widgets import get_widgets
9
9
 
10
- LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
10
+ LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select, cg.Component)
11
11
 
12
12
  CONFIG_SCHEMA = select.select_schema(LVGLSelect).extend(
13
13
  {
14
14
  cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
15
15
  cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
16
+ cv.Optional(CONF_RESTORE_VALUE, default=False): cv.boolean,
16
17
  }
17
18
  )
18
19
 
@@ -21,12 +22,9 @@ async def to_code(config):
21
22
  widget = await get_widgets(config, CONF_WIDGET)
22
23
  widget = widget[0]
23
24
  options = widget.config.get(CONF_OPTIONS, [])
24
- selector = await select.new_select(config, options=options)
25
- await wait_for_widgets()
26
- async with LvContext() as ctx:
27
- ctx.add(
28
- selector.set_widget(
29
- widget.var,
30
- literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF"),
31
- )
32
- )
25
+ animated = literal("LV_ANIM_ON" if config[CONF_ANIMATED] else "LV_ANIM_OFF")
26
+ selector = cg.new_Pvariable(
27
+ config[CONF_ID], widget.var, animated, config[CONF_RESTORE_VALUE]
28
+ )
29
+ await select.register_select(selector, config, options=options)
30
+ await cg.register_component(selector, config)
@@ -11,12 +11,20 @@
11
11
  namespace esphome {
12
12
  namespace lvgl {
13
13
 
14
- class LVGLSelect : public select::Select {
14
+ class LVGLSelect : public select::Select, public Component {
15
15
  public:
16
- void set_widget(LvSelectable *widget, lv_anim_enable_t anim = LV_ANIM_OFF) {
17
- this->widget_ = widget;
18
- this->anim_ = anim;
16
+ LVGLSelect(LvSelectable *widget, lv_anim_enable_t anim, bool restore)
17
+ : widget_(widget), anim_(anim), restore_(restore) {}
18
+
19
+ void setup() override {
19
20
  this->set_options_();
21
+ if (this->restore_) {
22
+ size_t index;
23
+ this->pref_ = global_preferences->make_preference<size_t>(this->get_object_id_hash());
24
+ if (this->pref_.load(&index))
25
+ this->widget_->set_selected_index(index, LV_ANIM_OFF);
26
+ }
27
+ this->publish();
20
28
  lv_obj_add_event_cb(
21
29
  this->widget_->obj,
22
30
  [](lv_event_t *e) {
@@ -24,11 +32,6 @@ class LVGLSelect : public select::Select {
24
32
  it->set_options_();
25
33
  },
26
34
  LV_EVENT_REFRESH, this);
27
- if (this->initial_state_.has_value()) {
28
- this->control(this->initial_state_.value());
29
- this->initial_state_.reset();
30
- }
31
- this->publish();
32
35
  auto lamb = [](lv_event_t *e) {
33
36
  auto *self = static_cast<LVGLSelect *>(e->user_data);
34
37
  self->publish();
@@ -37,21 +40,25 @@ class LVGLSelect : public select::Select {
37
40
  lv_obj_add_event_cb(this->widget_->obj, lamb, lv_update_event, this);
38
41
  }
39
42
 
40
- void publish() { this->publish_state(this->widget_->get_selected_text()); }
43
+ void publish() {
44
+ this->publish_state(this->widget_->get_selected_text());
45
+ if (this->restore_) {
46
+ auto index = this->widget_->get_selected_index();
47
+ this->pref_.save(&index);
48
+ }
49
+ }
41
50
 
42
51
  protected:
43
52
  void control(const std::string &value) override {
44
- if (this->widget_ != nullptr) {
45
- this->widget_->set_selected_text(value, this->anim_);
46
- } else {
47
- this->initial_state_ = value;
48
- }
53
+ this->widget_->set_selected_text(value, this->anim_);
54
+ this->publish();
49
55
  }
50
56
  void set_options_() { this->traits.set_options(this->widget_->get_options()); }
51
57
 
52
- LvSelectable *widget_{};
53
- optional<std::string> initial_state_{};
54
- lv_anim_enable_t anim_{LV_ANIM_OFF};
58
+ LvSelectable *widget_;
59
+ lv_anim_enable_t anim_;
60
+ bool restore_;
61
+ ESPPreferenceObject pref_{};
55
62
  };
56
63
 
57
64
  } // namespace lvgl