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
@@ -1,4 +1,6 @@
1
+ from esphome import automation
1
2
  import esphome.codegen as cg
3
+ import esphome.config_validation as cv
2
4
  from esphome.const import CONF_ID
3
5
  from esphome.core import ID
4
6
  from esphome.cpp_generator import MockObj
@@ -12,25 +14,54 @@ from .defines import (
12
14
  )
13
15
  from .helpers import add_lv_use
14
16
  from .lvcode import LambdaContext, LocalVariable, lv, lv_assign, lv_variable
15
- from .schemas import ALL_STYLES, STYLE_REMAP
16
- from .types import lv_lambda_t, lv_obj_t, lv_obj_t_ptr
17
- from .widgets import Widget, add_widgets, set_obj_properties, theme_widget_map
17
+ from .schemas import ALL_STYLES, FULL_STYLE_SCHEMA, STYLE_REMAP
18
+ from .types import ObjUpdateAction, lv_lambda_t, lv_obj_t, lv_obj_t_ptr, lv_style_t
19
+ from .widgets import (
20
+ Widget,
21
+ add_widgets,
22
+ set_obj_properties,
23
+ theme_widget_map,
24
+ wait_for_widgets,
25
+ )
18
26
  from .widgets.obj import obj_spec
19
27
 
20
28
 
29
+ async def style_set(svar, style):
30
+ for prop, validator in ALL_STYLES.items():
31
+ if (value := style.get(prop)) is not None:
32
+ if isinstance(validator, LValidator):
33
+ value = await validator.process(value)
34
+ if isinstance(value, list):
35
+ value = "|".join(value)
36
+ remapped_prop = STYLE_REMAP.get(prop, prop)
37
+ lv.call(f"style_set_{remapped_prop}", svar, literal(value))
38
+
39
+
21
40
  async def styles_to_code(config):
22
41
  """Convert styles to C__ code."""
23
42
  for style in config.get(CONF_STYLE_DEFINITIONS, ()):
24
43
  svar = cg.new_Pvariable(style[CONF_ID])
25
44
  lv.style_init(svar)
26
- for prop, validator in ALL_STYLES.items():
27
- if (value := style.get(prop)) is not None:
28
- if isinstance(validator, LValidator):
29
- value = await validator.process(value)
30
- if isinstance(value, list):
31
- value = "|".join(value)
32
- remapped_prop = STYLE_REMAP.get(prop, prop)
33
- lv.call(f"style_set_{remapped_prop}", svar, literal(value))
45
+ await style_set(svar, style)
46
+
47
+
48
+ @automation.register_action(
49
+ "lvgl.style.update",
50
+ ObjUpdateAction,
51
+ FULL_STYLE_SCHEMA.extend(
52
+ {
53
+ cv.Required(CONF_ID): cv.use_id(lv_style_t),
54
+ }
55
+ ),
56
+ )
57
+ async def style_update_to_code(config, action_id, template_arg, args):
58
+ await wait_for_widgets()
59
+ style = await cg.get_variable(config[CONF_ID])
60
+ async with LambdaContext(parameters=args, where=action_id) as context:
61
+ await style_set(style, config)
62
+
63
+ var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
64
+ return var
34
65
 
35
66
 
36
67
  async def theme_to_code(config):
@@ -1,7 +1,9 @@
1
1
  import esphome.codegen as cg
2
- from esphome.components.switch import Switch, new_switch, switch_schema
2
+ from esphome.components.switch import Switch, register_switch, switch_schema
3
3
  import esphome.config_validation as cv
4
+ from esphome.const import CONF_ID
4
5
  from esphome.cpp_generator import MockObj
6
+ from esphome.cpp_types import Component
5
7
 
6
8
  from ..defines import CONF_WIDGET, literal
7
9
  from ..lvcode import (
@@ -18,7 +20,7 @@ from ..lvcode import (
18
20
  from ..types import LV_EVENT, LV_STATE, lv_pseudo_button_t, lvgl_ns
19
21
  from ..widgets import get_widgets, wait_for_widgets
20
22
 
21
- LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch)
23
+ LVGLSwitch = lvgl_ns.class_("LVGLSwitch", Switch, Component)
22
24
  CONFIG_SCHEMA = switch_schema(LVGLSwitch).extend(
23
25
  {
24
26
  cv.Required(CONF_WIDGET): cv.use_id(lv_pseudo_button_t),
@@ -27,21 +29,24 @@ CONFIG_SCHEMA = switch_schema(LVGLSwitch).extend(
27
29
 
28
30
 
29
31
  async def to_code(config):
30
- switch = await new_switch(config)
31
32
  widget = await get_widgets(config, CONF_WIDGET)
32
33
  widget = widget[0]
33
34
  await wait_for_widgets()
34
- async with LambdaContext(EVENT_ARG) as checked_ctx:
35
- checked_ctx.add(switch.publish_state(widget.get_value()))
35
+ switch_id = MockObj(config[CONF_ID], "->")
36
+ v = literal("v")
36
37
  async with LambdaContext([(cg.bool_, "v")]) as control:
37
- with LvConditional(MockObj("v")) as cond:
38
+ with LvConditional(v) as cond:
38
39
  widget.add_state(LV_STATE.CHECKED)
39
40
  cond.else_()
40
41
  widget.clear_state(LV_STATE.CHECKED)
41
42
  lv.event_send(widget.obj, API_EVENT, cg.nullptr)
42
- control.add(switch.publish_state(literal("v")))
43
+ control.add(switch_id.publish_state(v))
44
+ switch = cg.new_Pvariable(config[CONF_ID], await control.get_lambda())
45
+ await cg.register_component(switch, config)
46
+ await register_switch(switch, config)
47
+ async with LambdaContext(EVENT_ARG) as checked_ctx:
48
+ checked_ctx.add(switch.publish_state(widget.get_value()))
43
49
  async with LvContext() as ctx:
44
- lv_add(switch.set_control_lambda(await control.get_lambda()))
45
50
  ctx.add(
46
51
  lvgl_static.add_event_cb(
47
52
  widget.obj,
@@ -10,26 +10,15 @@
10
10
  namespace esphome {
11
11
  namespace lvgl {
12
12
 
13
- class LVGLSwitch : public switch_::Switch {
13
+ class LVGLSwitch : public switch_::Switch, public Component {
14
14
  public:
15
- void set_control_lambda(std::function<void(bool)> state_lambda) {
16
- this->state_lambda_ = std::move(state_lambda);
17
- if (this->initial_state_.has_value()) {
18
- this->state_lambda_(this->initial_state_.value());
19
- this->initial_state_.reset();
20
- }
21
- }
15
+ LVGLSwitch(std::function<void(bool)> state_lambda) : state_lambda_(std::move(state_lambda)) {}
16
+
17
+ void setup() override { this->write_state(this->get_initial_state_with_restore_mode().value_or(false)); }
22
18
 
23
19
  protected:
24
- void write_state(bool value) override {
25
- if (this->state_lambda_ != nullptr) {
26
- this->state_lambda_(value);
27
- } else {
28
- this->initial_state_ = value;
29
- }
30
- }
20
+ void write_state(bool value) override { this->state_lambda_(value); }
31
21
  std::function<void(bool)> state_lambda_{};
32
- optional<bool> initial_state_{};
33
22
  };
34
23
 
35
24
  } // namespace lvgl
@@ -1,6 +1,6 @@
1
1
  from esphome import automation
2
2
  import esphome.codegen as cg
3
- from esphome.const import CONF_ID, CONF_ON_VALUE, CONF_TRIGGER_ID
3
+ from esphome.const import CONF_ID, CONF_ON_BOOT, CONF_ON_VALUE, CONF_TRIGGER_ID
4
4
 
5
5
  from .defines import (
6
6
  CONF_ALIGN,
@@ -28,6 +28,13 @@ from .types import LV_EVENT
28
28
  from .widgets import LvScrActType, get_scr_act, widget_map
29
29
 
30
30
 
31
+ async def add_on_boot_triggers(triggers):
32
+ for conf in triggers:
33
+ trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], 390)
34
+ await cg.register_component(trigger, conf)
35
+ await automation.build_automation(trigger, [], conf)
36
+
37
+
31
38
  async def generate_triggers():
32
39
  """
33
40
  Generate LVGL triggers for all defined widgets
@@ -75,6 +82,8 @@ async def generate_triggers():
75
82
  UPDATE_EVENT,
76
83
  )
77
84
 
85
+ await add_on_boot_triggers(w.config.get(CONF_ON_BOOT, ()))
86
+
78
87
  # Generate align to directives while we're here
79
88
  if align_to := w.config.get(CONF_ALIGN_TO):
80
89
  target = widget_map[align_to[CONF_ID]].obj
@@ -3,13 +3,12 @@ from typing import Any, Union
3
3
 
4
4
  from esphome import codegen as cg, config_validation as cv
5
5
  from esphome.config_validation import Invalid
6
- from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE
6
+ from esphome.const import CONF_DEFAULT, CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE
7
7
  from esphome.core import ID, TimePeriod
8
8
  from esphome.coroutine import FakeAwaitable
9
9
  from esphome.cpp_generator import CallExpression, MockObj
10
10
 
11
11
  from ..defines import (
12
- CONF_DEFAULT,
13
12
  CONF_FLEX_ALIGN_CROSS,
14
13
  CONF_FLEX_ALIGN_MAIN,
15
14
  CONF_FLEX_ALIGN_TRACK,
@@ -250,7 +250,7 @@ async def button_update_to_code(config, action_id, template_arg, args):
250
250
  widgets = await get_widgets(config[CONF_ID])
251
251
  assert all(isinstance(w, MatrixButton) for w in widgets)
252
252
 
253
- async def do_button_update(w: MatrixButton):
253
+ async def do_button_update(w):
254
254
  if (width := config.get(CONF_WIDTH)) is not None:
255
255
  lv.btnmatrix_set_btn_width(w.obj, w.index, width)
256
256
  if config.get(CONF_SELECTED):
@@ -275,5 +275,5 @@ async def button_update_to_code(config, action_id, template_arg, args):
275
275
  )
276
276
 
277
277
  return await action_to_code(
278
- widgets, do_button_update, action_id, template_arg, args
278
+ widgets, do_button_update, action_id, template_arg, args, config
279
279
  )
@@ -0,0 +1,407 @@
1
+ from esphome import automation, codegen as cg, config_validation as cv
2
+ from esphome.components.display_menu_base import CONF_LABEL
3
+ from esphome.const import CONF_COLOR, CONF_HEIGHT, CONF_ID, CONF_TEXT, CONF_WIDTH
4
+ from esphome.cpp_generator import Literal, MockObj
5
+
6
+ from ..automation import action_to_code
7
+ from ..defines import (
8
+ CONF_END_ANGLE,
9
+ CONF_MAIN,
10
+ CONF_OPA,
11
+ CONF_PIVOT_X,
12
+ CONF_PIVOT_Y,
13
+ CONF_POINTS,
14
+ CONF_SRC,
15
+ CONF_START_ANGLE,
16
+ CONF_X,
17
+ CONF_Y,
18
+ literal,
19
+ )
20
+ from ..lv_validation import (
21
+ lv_angle,
22
+ lv_bool,
23
+ lv_color,
24
+ lv_image,
25
+ lv_text,
26
+ opacity,
27
+ pixels,
28
+ size,
29
+ )
30
+ from ..lvcode import LocalVariable, lv, lv_assign
31
+ from ..schemas import STYLE_PROPS, STYLE_REMAP, TEXT_SCHEMA, point_schema
32
+ from ..types import LvType, ObjUpdateAction, WidgetType
33
+ from . import Widget, get_widgets
34
+ from .line import lv_point_t, process_coord
35
+
36
+ CONF_CANVAS = "canvas"
37
+ CONF_BUFFER_ID = "buffer_id"
38
+ CONF_MAX_WIDTH = "max_width"
39
+ CONF_TRANSPARENT = "transparent"
40
+ CONF_RADIUS = "radius"
41
+
42
+ lv_canvas_t = LvType("lv_canvas_t")
43
+
44
+
45
+ class CanvasType(WidgetType):
46
+ def __init__(self):
47
+ super().__init__(
48
+ CONF_CANVAS,
49
+ lv_canvas_t,
50
+ (CONF_MAIN,),
51
+ cv.Schema(
52
+ {
53
+ cv.Required(CONF_WIDTH): size,
54
+ cv.Required(CONF_HEIGHT): size,
55
+ cv.Optional(CONF_TRANSPARENT, default=False): cv.boolean,
56
+ }
57
+ ),
58
+ )
59
+
60
+ def get_uses(self):
61
+ return "img", CONF_LABEL
62
+
63
+ async def to_code(self, w: Widget, config):
64
+ width = config[CONF_WIDTH]
65
+ height = config[CONF_HEIGHT]
66
+ use_alpha = "_ALPHA" if config[CONF_TRANSPARENT] else ""
67
+ lv.canvas_set_buffer(
68
+ w.obj,
69
+ lv.custom_mem_alloc(
70
+ literal(f"LV_CANVAS_BUF_SIZE_TRUE_COLOR{use_alpha}({width}, {height})")
71
+ ),
72
+ width,
73
+ height,
74
+ literal(f"LV_IMG_CF_TRUE_COLOR{use_alpha}"),
75
+ )
76
+
77
+
78
+ canvas_spec = CanvasType()
79
+
80
+
81
+ @automation.register_action(
82
+ "lvgl.canvas.fill",
83
+ ObjUpdateAction,
84
+ cv.Schema(
85
+ {
86
+ cv.GenerateID(CONF_ID): cv.use_id(lv_canvas_t),
87
+ cv.Required(CONF_COLOR): lv_color,
88
+ cv.Optional(CONF_OPA, default="COVER"): opacity,
89
+ },
90
+ ),
91
+ )
92
+ async def canvas_fill(config, action_id, template_arg, args):
93
+ widget = await get_widgets(config)
94
+ color = await lv_color.process(config[CONF_COLOR])
95
+ opa = await opacity.process(config[CONF_OPA])
96
+
97
+ async def do_fill(w: Widget):
98
+ lv.canvas_fill_bg(w.obj, color, opa)
99
+
100
+ return await action_to_code(widget, do_fill, action_id, template_arg, args, config)
101
+
102
+
103
+ @automation.register_action(
104
+ "lvgl.canvas.set_pixels",
105
+ ObjUpdateAction,
106
+ cv.Schema(
107
+ {
108
+ cv.GenerateID(CONF_ID): cv.use_id(lv_canvas_t),
109
+ cv.Required(CONF_COLOR): lv_color,
110
+ cv.Optional(CONF_OPA): opacity,
111
+ cv.Required(CONF_POINTS): cv.ensure_list(point_schema),
112
+ },
113
+ ),
114
+ )
115
+ async def canvas_set_pixel(config, action_id, template_arg, args):
116
+ widget = await get_widgets(config)
117
+ color = await lv_color.process(config[CONF_COLOR])
118
+ opa = await opacity.process(config.get(CONF_OPA))
119
+ points = [
120
+ (
121
+ await pixels.process(p[CONF_X]),
122
+ await pixels.process(p[CONF_Y]),
123
+ )
124
+ for p in config[CONF_POINTS]
125
+ ]
126
+
127
+ async def do_set_pixels(w: Widget):
128
+ if isinstance(color, MockObj):
129
+ for point in points:
130
+ x, y = point
131
+ lv.canvas_set_px_color(w.obj, x, y, color)
132
+ else:
133
+ with LocalVariable("color", "lv_color_t", color, modifier="") as color_var:
134
+ for point in points:
135
+ x, y = point
136
+ lv.canvas_set_px_color(w.obj, x, y, color_var)
137
+ if opa:
138
+ if isinstance(opa, Literal):
139
+ for point in points:
140
+ x, y = point
141
+ lv.canvas_set_px_opa(w.obj, x, y, opa)
142
+ else:
143
+ with LocalVariable("opa", "lv_opa_t", opa, modifier="") as opa_var:
144
+ for point in points:
145
+ x, y = point
146
+ lv.canvas_set_px_opa(w.obj, x, y, opa_var)
147
+
148
+ return await action_to_code(
149
+ widget, do_set_pixels, action_id, template_arg, args, config
150
+ )
151
+
152
+
153
+ DRAW_SCHEMA = cv.Schema(
154
+ {
155
+ cv.GenerateID(CONF_ID): cv.use_id(lv_canvas_t),
156
+ cv.Required(CONF_X): pixels,
157
+ cv.Required(CONF_Y): pixels,
158
+ }
159
+ )
160
+ DRAW_OPA_SCHEMA = DRAW_SCHEMA.extend(
161
+ {
162
+ cv.Optional(CONF_OPA): opacity,
163
+ }
164
+ )
165
+
166
+
167
+ async def draw_to_code(config, dsc_type, props, do_draw, action_id, template_arg, args):
168
+ widget = await get_widgets(config)
169
+ x = await pixels.process(config.get(CONF_X))
170
+ y = await pixels.process(config.get(CONF_Y))
171
+
172
+ async def action_func(w: Widget):
173
+ with LocalVariable("dsc", f"lv_draw_{dsc_type}_dsc_t", modifier="") as dsc:
174
+ dsc_addr = literal(f"&{dsc}")
175
+ lv.call(f"draw_{dsc_type}_dsc_init", dsc_addr)
176
+ if CONF_OPA in config:
177
+ opa = await opacity.process(config[CONF_OPA])
178
+ lv_assign(dsc.opa, opa)
179
+ for prop, validator in props.items():
180
+ if prop in config:
181
+ value = await validator.process(config[prop])
182
+ mapped_prop = STYLE_REMAP.get(prop, prop)
183
+ lv_assign(getattr(dsc, mapped_prop), value)
184
+ await do_draw(w, x, y, dsc_addr)
185
+
186
+ return await action_to_code(
187
+ widget, action_func, action_id, template_arg, args, config
188
+ )
189
+
190
+
191
+ RECT_PROPS = {
192
+ p: STYLE_PROPS[p]
193
+ for p in (
194
+ "radius",
195
+ "bg_opa",
196
+ "bg_color",
197
+ "bg_grad",
198
+ "border_color",
199
+ "border_width",
200
+ "border_opa",
201
+ "outline_color",
202
+ "outline_width",
203
+ "outline_pad",
204
+ "outline_opa",
205
+ "shadow_color",
206
+ "shadow_width",
207
+ "shadow_ofs_x",
208
+ "shadow_ofs_y",
209
+ "shadow_spread",
210
+ "shadow_opa",
211
+ )
212
+ }
213
+
214
+
215
+ @automation.register_action(
216
+ "lvgl.canvas.draw_rectangle",
217
+ ObjUpdateAction,
218
+ DRAW_SCHEMA.extend(
219
+ {
220
+ cv.Required(CONF_WIDTH): cv.templatable(cv.int_),
221
+ cv.Required(CONF_HEIGHT): cv.templatable(cv.int_),
222
+ },
223
+ ).extend({cv.Optional(prop): STYLE_PROPS[prop] for prop in RECT_PROPS}),
224
+ )
225
+ async def canvas_draw_rect(config, action_id, template_arg, args):
226
+ width = await pixels.process(config[CONF_WIDTH])
227
+ height = await pixels.process(config[CONF_HEIGHT])
228
+
229
+ async def do_draw_rect(w: Widget, x, y, dsc_addr):
230
+ lv.canvas_draw_rect(w.obj, x, y, width, height, dsc_addr)
231
+
232
+ return await draw_to_code(
233
+ config, "rect", RECT_PROPS, do_draw_rect, action_id, template_arg, args
234
+ )
235
+
236
+
237
+ TEXT_PROPS = {
238
+ p: STYLE_PROPS[f"text_{p}"]
239
+ for p in (
240
+ "font",
241
+ "color",
242
+ # "sel_color",
243
+ # "sel_bg_color",
244
+ "line_space",
245
+ "letter_space",
246
+ "align",
247
+ "decor",
248
+ )
249
+ }
250
+
251
+
252
+ @automation.register_action(
253
+ "lvgl.canvas.draw_text",
254
+ ObjUpdateAction,
255
+ TEXT_SCHEMA.extend(DRAW_OPA_SCHEMA)
256
+ .extend(
257
+ {
258
+ cv.Required(CONF_MAX_WIDTH): cv.templatable(cv.int_),
259
+ },
260
+ )
261
+ .extend({cv.Optional(prop): STYLE_PROPS[f"text_{prop}"] for prop in TEXT_PROPS}),
262
+ )
263
+ async def canvas_draw_text(config, action_id, template_arg, args):
264
+ text = await lv_text.process(config[CONF_TEXT])
265
+ max_width = await pixels.process(config[CONF_MAX_WIDTH])
266
+
267
+ async def do_draw_text(w: Widget, x, y, dsc_addr):
268
+ lv.canvas_draw_text(w.obj, x, y, max_width, dsc_addr, text)
269
+
270
+ return await draw_to_code(
271
+ config, "label", TEXT_PROPS, do_draw_text, action_id, template_arg, args
272
+ )
273
+
274
+
275
+ IMG_PROPS = {
276
+ "angle": STYLE_PROPS["transform_angle"],
277
+ "zoom": STYLE_PROPS["transform_zoom"],
278
+ "recolor": STYLE_PROPS["image_recolor"],
279
+ "recolor_opa": STYLE_PROPS["image_recolor_opa"],
280
+ "opa": STYLE_PROPS["opa"],
281
+ }
282
+
283
+
284
+ @automation.register_action(
285
+ "lvgl.canvas.draw_image",
286
+ ObjUpdateAction,
287
+ DRAW_OPA_SCHEMA.extend(
288
+ {
289
+ cv.Required(CONF_SRC): lv_image,
290
+ cv.Optional(CONF_PIVOT_X, default=0): pixels,
291
+ cv.Optional(CONF_PIVOT_Y, default=0): pixels,
292
+ },
293
+ ).extend({cv.Optional(prop): validator for prop, validator in IMG_PROPS.items()}),
294
+ )
295
+ async def canvas_draw_image(config, action_id, template_arg, args):
296
+ src = await lv_image.process(config[CONF_SRC])
297
+ pivot_x = await pixels.process(config[CONF_PIVOT_X])
298
+ pivot_y = await pixels.process(config[CONF_PIVOT_Y])
299
+
300
+ async def do_draw_image(w: Widget, x, y, dsc_addr):
301
+ dsc = MockObj(f"(*{dsc_addr})")
302
+ if pivot_x or pivot_y:
303
+ # pylint :disable=no-member
304
+ lv_assign(dsc.pivot, literal(f"{{{pivot_x}, {pivot_y}}}"))
305
+ lv.canvas_draw_img(w.obj, x, y, src, dsc_addr)
306
+
307
+ return await draw_to_code(
308
+ config, "img", IMG_PROPS, do_draw_image, action_id, template_arg, args
309
+ )
310
+
311
+
312
+ LINE_PROPS = {
313
+ "width": STYLE_PROPS["line_width"],
314
+ "color": STYLE_PROPS["line_color"],
315
+ "dash-width": STYLE_PROPS["line_dash_width"],
316
+ "dash-gap": STYLE_PROPS["line_dash_gap"],
317
+ "round_start": lv_bool,
318
+ "round_end": lv_bool,
319
+ }
320
+
321
+
322
+ @automation.register_action(
323
+ "lvgl.canvas.draw_line",
324
+ ObjUpdateAction,
325
+ cv.Schema(
326
+ {
327
+ cv.GenerateID(CONF_ID): cv.use_id(lv_canvas_t),
328
+ cv.Optional(CONF_OPA): opacity,
329
+ cv.Required(CONF_POINTS): cv.ensure_list(point_schema),
330
+ },
331
+ ).extend({cv.Optional(prop): validator for prop, validator in LINE_PROPS.items()}),
332
+ )
333
+ async def canvas_draw_line(config, action_id, template_arg, args):
334
+ points = [
335
+ [await process_coord(p[CONF_X]), await process_coord(p[CONF_Y])]
336
+ for p in config[CONF_POINTS]
337
+ ]
338
+
339
+ async def do_draw_line(w: Widget, x, y, dsc_addr):
340
+ with LocalVariable(
341
+ "points", cg.std_vector.template(lv_point_t), points, modifier=""
342
+ ) as points_var:
343
+ lv.canvas_draw_line(w.obj, points_var.data(), points_var.size(), dsc_addr)
344
+
345
+ return await draw_to_code(
346
+ config, "line", LINE_PROPS, do_draw_line, action_id, template_arg, args
347
+ )
348
+
349
+
350
+ @automation.register_action(
351
+ "lvgl.canvas.draw_polygon",
352
+ ObjUpdateAction,
353
+ cv.Schema(
354
+ {
355
+ cv.GenerateID(CONF_ID): cv.use_id(lv_canvas_t),
356
+ cv.Required(CONF_POINTS): cv.ensure_list(point_schema),
357
+ },
358
+ ).extend({cv.Optional(prop): STYLE_PROPS[prop] for prop in RECT_PROPS}),
359
+ )
360
+ async def canvas_draw_polygon(config, action_id, template_arg, args):
361
+ points = [
362
+ [await process_coord(p[CONF_X]), await process_coord(p[CONF_Y])]
363
+ for p in config[CONF_POINTS]
364
+ ]
365
+
366
+ async def do_draw_polygon(w: Widget, x, y, dsc_addr):
367
+ with LocalVariable(
368
+ "points", cg.std_vector.template(lv_point_t), points, modifier=""
369
+ ) as points_var:
370
+ lv.canvas_draw_polygon(
371
+ w.obj, points_var.data(), points_var.size(), dsc_addr
372
+ )
373
+
374
+ return await draw_to_code(
375
+ config, "rect", RECT_PROPS, do_draw_polygon, action_id, template_arg, args
376
+ )
377
+
378
+
379
+ ARC_PROPS = {
380
+ "width": STYLE_PROPS["arc_width"],
381
+ "color": STYLE_PROPS["arc_color"],
382
+ "rounded": STYLE_PROPS["arc_rounded"],
383
+ }
384
+
385
+
386
+ @automation.register_action(
387
+ "lvgl.canvas.draw_arc",
388
+ ObjUpdateAction,
389
+ DRAW_OPA_SCHEMA.extend(
390
+ {
391
+ cv.Required(CONF_RADIUS): pixels,
392
+ cv.Required(CONF_START_ANGLE): lv_angle,
393
+ cv.Required(CONF_END_ANGLE): lv_angle,
394
+ }
395
+ ).extend({cv.Optional(prop): validator for prop, validator in ARC_PROPS.items()}),
396
+ )
397
+ async def canvas_draw_arc(config, action_id, template_arg, args):
398
+ radius = await size.process(config[CONF_RADIUS])
399
+ start_angle = await lv_angle.process(config[CONF_START_ANGLE])
400
+ end_angle = await lv_angle.process(config[CONF_END_ANGLE])
401
+
402
+ async def do_draw_arc(w: Widget, x, y, dsc_addr):
403
+ lv.canvas_draw_arc(w.obj, x, y, radius, start_angle, end_angle, dsc_addr)
404
+
405
+ return await draw_to_code(
406
+ config, "arc", ARC_PROPS, do_draw_arc, action_id, template_arg, args
407
+ )