esphome 2024.7.2__py3-none-any.whl → 2024.8.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 (353) hide show
  1. esphome/__main__.py +15 -81
  2. esphome/automation.py +1 -1
  3. esphome/codegen.py +53 -53
  4. esphome/components/ade7953/sensor.py +1 -1
  5. esphome/components/ade7953_spi/ade7953_spi.cpp +1 -1
  6. esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +5 -2
  7. esphome/components/airthings_wave_plus/airthings_wave_plus.h +2 -0
  8. esphome/components/airthings_wave_plus/sensor.py +12 -0
  9. esphome/components/alarm_control_panel/__init__.py +75 -66
  10. esphome/components/apds9306/__init__.py +4 -0
  11. esphome/components/apds9306/apds9306.cpp +151 -0
  12. esphome/components/apds9306/apds9306.h +66 -0
  13. esphome/components/apds9306/sensor.py +95 -0
  14. esphome/components/api/__init__.py +80 -52
  15. esphome/components/api/api_connection.cpp +14 -1
  16. esphome/components/api/api_pb2.cpp +33 -4
  17. esphome/components/api/api_pb2.h +8 -1
  18. esphome/components/api/api_server.cpp +10 -0
  19. esphome/components/api/api_server.h +3 -0
  20. esphome/components/atm90e32/__init__.py +7 -0
  21. esphome/components/atm90e32/atm90e32.cpp +68 -16
  22. esphome/components/atm90e32/atm90e32.h +20 -7
  23. esphome/components/atm90e32/atm90e32_reg.h +2 -0
  24. esphome/components/atm90e32/button/__init__.py +43 -0
  25. esphome/components/atm90e32/button/atm90e32_button.cpp +20 -0
  26. esphome/components/atm90e32/button/atm90e32_button.h +27 -0
  27. esphome/components/atm90e32/sensor.py +15 -11
  28. esphome/components/bedjet/bedjet_codec.h +1 -1
  29. esphome/components/binary/light/binary_light_output.h +3 -2
  30. esphome/components/binary_sensor/__init__.py +5 -5
  31. esphome/components/ble_client/__init__.py +3 -3
  32. esphome/components/ble_client/output/__init__.py +1 -1
  33. esphome/components/ble_client/sensor/__init__.py +4 -3
  34. esphome/components/ble_client/switch/__init__.py +2 -1
  35. esphome/components/ble_client/text_sensor/__init__.py +4 -3
  36. esphome/components/ble_presence/binary_sensor.py +3 -3
  37. esphome/components/ble_rssi/sensor.py +2 -2
  38. esphome/components/ble_scanner/text_sensor.py +1 -1
  39. esphome/components/bluetooth_proxy/__init__.py +3 -3
  40. esphome/components/bme68x_bsec2/__init__.py +196 -0
  41. esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +523 -0
  42. esphome/components/bme68x_bsec2/bme68x_bsec2.h +163 -0
  43. esphome/components/bme68x_bsec2/sensor.py +130 -0
  44. esphome/components/bme68x_bsec2/text_sensor.py +33 -0
  45. esphome/components/bme68x_bsec2_i2c/__init__.py +28 -0
  46. esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp +53 -0
  47. esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h +28 -0
  48. esphome/components/bmp3xx/sensor.py +1 -1
  49. esphome/components/button/__init__.py +4 -4
  50. esphome/components/climate/__init__.py +5 -5
  51. esphome/components/climate/climate.h +1 -1
  52. esphome/components/cover/__init__.py +8 -8
  53. esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +11 -7
  54. esphome/components/cst226/touchscreen/cst226_touchscreen.h +1 -1
  55. esphome/components/datetime/__init__.py +11 -13
  56. esphome/components/demo/demo_sensor.h +3 -2
  57. esphome/components/display/display.cpp +31 -0
  58. esphome/components/display/display.h +3 -0
  59. esphome/components/display_menu_base/__init__.py +14 -13
  60. esphome/components/ens160/sensor.py +1 -1
  61. esphome/components/esp32/__init__.py +22 -10
  62. esphome/components/esp32/boards.py +1 -1
  63. esphome/components/esp32/gpio.py +12 -13
  64. esphome/components/esp32/gpio_esp32.py +1 -2
  65. esphome/components/esp32/gpio_esp32_c2.py +1 -2
  66. esphome/components/esp32/gpio_esp32_c3.py +1 -5
  67. esphome/components/esp32/gpio_esp32_c6.py +1 -2
  68. esphome/components/esp32/gpio_esp32_h2.py +1 -2
  69. esphome/components/esp32/gpio_esp32_s2.py +1 -2
  70. esphome/components/esp32/gpio_esp32_s3.py +1 -6
  71. esphome/components/esp32_ble/__init__.py +20 -3
  72. esphome/components/esp32_ble/ble.cpp +9 -1
  73. esphome/components/esp32_ble/ble.h +9 -0
  74. esphome/components/esp32_ble/ble_advertising.cpp +42 -9
  75. esphome/components/esp32_ble/ble_advertising.h +21 -1
  76. esphome/components/esp32_ble_beacon/__init__.py +17 -7
  77. esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +45 -113
  78. esphome/components/esp32_ble_beacon/esp32_ble_beacon.h +17 -19
  79. esphome/components/esp32_ble_client/__init__.py +0 -1
  80. esphome/components/esp32_ble_server/__init__.py +2 -3
  81. esphome/components/esp32_ble_tracker/__init__.py +2 -2
  82. esphome/components/esp32_improv/__init__.py +2 -4
  83. esphome/components/ethernet/__init__.py +17 -17
  84. esphome/components/ethernet_info/text_sensor.py +2 -2
  85. esphome/components/event/__init__.py +5 -5
  86. esphome/components/fan/__init__.py +14 -14
  87. esphome/components/fan/fan.cpp +2 -2
  88. esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
  89. esphome/components/fingerprint_grow/fingerprint_grow.h +1 -1
  90. esphome/components/graphical_display_menu/__init__.py +11 -8
  91. esphome/components/haier/haier_base.h +2 -2
  92. esphome/components/homeassistant/__init__.py +8 -1
  93. esphome/components/homeassistant/number/__init__.py +33 -0
  94. esphome/components/homeassistant/number/homeassistant_number.cpp +100 -0
  95. esphome/components/homeassistant/number/homeassistant_number.h +31 -0
  96. esphome/components/homeassistant/switch/__init__.py +30 -0
  97. esphome/components/homeassistant/switch/homeassistant_switch.cpp +59 -0
  98. esphome/components/homeassistant/switch/homeassistant_switch.h +22 -0
  99. esphome/components/host/__init__.py +3 -7
  100. esphome/components/http_request/__init__.py +12 -1
  101. esphome/components/http_request/http_request_arduino.cpp +2 -2
  102. esphome/components/http_request/http_request_idf.cpp +11 -2
  103. esphome/components/http_request/http_request_idf.h +10 -0
  104. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  105. esphome/components/http_request/update/http_request_update.cpp +2 -2
  106. esphome/components/http_request/update/http_request_update.h +2 -1
  107. esphome/components/hx711/hx711.cpp +10 -1
  108. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +1 -1
  109. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +11 -2
  110. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  111. esphome/components/ili9xxx/ili9xxx_defines.h +3 -1
  112. esphome/components/ili9xxx/ili9xxx_display.cpp +9 -22
  113. esphome/components/ili9xxx/ili9xxx_display.h +5 -7
  114. esphome/components/ili9xxx/ili9xxx_init.h +4 -4
  115. esphome/components/improv_base/__init__.py +2 -3
  116. esphome/components/improv_serial/__init__.py +4 -10
  117. esphome/components/improv_serial/improv_serial_component.cpp +4 -0
  118. esphome/components/jsn_sr04t/jsn_sr04t.cpp +18 -1
  119. esphome/components/jsn_sr04t/jsn_sr04t.h +7 -1
  120. esphome/components/jsn_sr04t/sensor.py +13 -0
  121. esphome/components/kalman_combinator/sensor.py +1 -1
  122. esphome/components/light/__init__.py +16 -15
  123. esphome/components/light/addressable_light_effect.h +12 -8
  124. esphome/components/light/automation.h +16 -1
  125. esphome/components/light/automation.py +21 -0
  126. esphome/components/light/base_light_effects.h +5 -5
  127. esphome/components/light/esp_color_correction.h +8 -8
  128. esphome/components/light/types.py +7 -0
  129. esphome/components/lock/__init__.py +3 -3
  130. esphome/components/logger/__init__.py +15 -18
  131. esphome/components/lvgl/__init__.py +346 -0
  132. esphome/components/lvgl/automation.py +226 -0
  133. esphome/components/lvgl/binary_sensor/__init__.py +43 -0
  134. esphome/components/lvgl/defines.py +508 -0
  135. esphome/components/lvgl/encoders.py +77 -0
  136. esphome/components/lvgl/font.cpp +76 -0
  137. esphome/components/lvgl/helpers.py +49 -0
  138. esphome/components/lvgl/light/__init__.py +32 -0
  139. esphome/components/lvgl/light/lvgl_light.h +48 -0
  140. esphome/components/lvgl/lv_validation.py +303 -0
  141. esphome/components/lvgl/lvcode.py +349 -0
  142. esphome/components/lvgl/lvgl_esphome.cpp +407 -0
  143. esphome/components/lvgl/lvgl_esphome.h +274 -0
  144. esphome/components/lvgl/lvgl_hal.h +21 -0
  145. esphome/components/lvgl/number/__init__.py +66 -0
  146. esphome/components/lvgl/number/lvgl_number.h +34 -0
  147. esphome/components/lvgl/schemas.py +436 -0
  148. esphome/components/lvgl/select/__init__.py +55 -0
  149. esphome/components/lvgl/select/lvgl_select.h +62 -0
  150. esphome/components/lvgl/sensor/__init__.py +47 -0
  151. esphome/components/lvgl/styles.py +58 -0
  152. esphome/components/lvgl/switch/__init__.py +56 -0
  153. esphome/components/lvgl/switch/lvgl_switch.h +34 -0
  154. esphome/components/lvgl/text/__init__.py +50 -0
  155. esphome/components/lvgl/text/lvgl_text.h +34 -0
  156. esphome/components/lvgl/text_sensor/__init__.py +42 -0
  157. esphome/components/lvgl/touchscreens.py +45 -0
  158. esphome/components/lvgl/trigger.py +74 -0
  159. esphome/components/lvgl/types.py +191 -0
  160. esphome/components/lvgl/widgets/__init__.py +419 -0
  161. esphome/components/lvgl/widgets/animimg.py +117 -0
  162. esphome/components/lvgl/widgets/arc.py +78 -0
  163. esphome/components/lvgl/widgets/button.py +20 -0
  164. esphome/components/lvgl/widgets/buttonmatrix.py +275 -0
  165. esphome/components/lvgl/widgets/checkbox.py +27 -0
  166. esphome/components/lvgl/widgets/dropdown.py +76 -0
  167. esphome/components/lvgl/widgets/img.py +85 -0
  168. esphome/components/lvgl/widgets/keyboard.py +49 -0
  169. esphome/components/lvgl/widgets/label.py +42 -0
  170. esphome/components/lvgl/widgets/led.py +29 -0
  171. esphome/components/lvgl/widgets/line.py +50 -0
  172. esphome/components/lvgl/widgets/lv_bar.py +55 -0
  173. esphome/components/lvgl/widgets/meter.py +302 -0
  174. esphome/components/lvgl/widgets/msgbox.py +134 -0
  175. esphome/components/lvgl/widgets/obj.py +28 -0
  176. esphome/components/lvgl/widgets/page.py +113 -0
  177. esphome/components/lvgl/widgets/roller.py +77 -0
  178. esphome/components/lvgl/widgets/slider.py +63 -0
  179. esphome/components/lvgl/widgets/spinbox.py +178 -0
  180. esphome/components/lvgl/widgets/spinner.py +43 -0
  181. esphome/components/lvgl/widgets/switch.py +20 -0
  182. esphome/components/lvgl/widgets/tabview.py +114 -0
  183. esphome/components/lvgl/widgets/textarea.py +66 -0
  184. esphome/components/lvgl/widgets/tileview.py +128 -0
  185. esphome/components/m5stack_8angle/__init__.py +33 -0
  186. esphome/components/m5stack_8angle/binary_sensor/__init__.py +30 -0
  187. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +17 -0
  188. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h +19 -0
  189. esphome/components/m5stack_8angle/light/__init__.py +31 -0
  190. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +45 -0
  191. esphome/components/m5stack_8angle/light/m5stack_8angle_light.h +37 -0
  192. esphome/components/m5stack_8angle/m5stack_8angle.cpp +74 -0
  193. esphome/components/m5stack_8angle/m5stack_8angle.h +34 -0
  194. esphome/components/m5stack_8angle/sensor/__init__.py +66 -0
  195. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +24 -0
  196. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h +27 -0
  197. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -0
  198. esphome/components/max31856/sensor.py +5 -5
  199. esphome/components/media_player/__init__.py +3 -5
  200. esphome/components/media_player/automation.h +31 -27
  201. esphome/components/micro_wake_word/__init__.py +20 -25
  202. esphome/components/micro_wake_word/streaming_model.cpp +6 -4
  203. esphome/components/microphone/microphone.h +4 -1
  204. esphome/components/mitsubishi/mitsubishi.cpp +7 -1
  205. esphome/components/modbus_controller/__init__.py +26 -2
  206. esphome/components/modbus_controller/automation.h +19 -0
  207. esphome/components/modbus_controller/const.py +1 -0
  208. esphome/components/modbus_controller/modbus_controller.cpp +8 -0
  209. esphome/components/modbus_controller/modbus_controller.h +3 -0
  210. esphome/components/mqtt/__init__.py +20 -9
  211. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +128 -0
  212. esphome/components/mqtt/mqtt_alarm_control_panel.h +39 -0
  213. esphome/components/mqtt/mqtt_backend.h +3 -1
  214. esphome/components/mqtt/mqtt_backend_esp32.cpp +4 -1
  215. esphome/components/mqtt/mqtt_backend_esp32.h +3 -1
  216. esphome/components/mqtt/mqtt_backend_esp8266.h +3 -1
  217. esphome/components/mqtt/mqtt_backend_libretiny.h +3 -1
  218. esphome/components/mqtt/mqtt_client.cpp +16 -3
  219. esphome/components/mqtt/mqtt_client.h +5 -1
  220. esphome/components/mqtt/mqtt_component.cpp +32 -4
  221. esphome/components/mqtt/mqtt_const.h +2 -0
  222. esphome/components/network/__init__.py +15 -12
  223. esphome/components/network/ip_address.h +3 -0
  224. esphome/components/network/util.cpp +2 -1
  225. esphome/components/network/util.h +3 -1
  226. esphome/components/nextion/base_component.py +5 -8
  227. esphome/components/number/__init__.py +7 -8
  228. esphome/components/online_image/__init__.py +167 -0
  229. esphome/components/online_image/image_decoder.cpp +44 -0
  230. esphome/components/online_image/image_decoder.h +112 -0
  231. esphome/components/online_image/online_image.cpp +283 -0
  232. esphome/components/online_image/online_image.h +195 -0
  233. esphome/components/online_image/png_image.cpp +68 -0
  234. esphome/components/online_image/png_image.h +33 -0
  235. esphome/components/ota/__init__.py +8 -4
  236. esphome/components/pid/pid_climate.h +2 -0
  237. esphome/components/pmwcs3/pmwcs3.cpp +31 -30
  238. esphome/components/remote_base/pronto_protocol.cpp +0 -3
  239. esphome/components/remote_transmitter/remote_transmitter.h +1 -1
  240. esphome/components/rgbct/rgbct_light_output.h +3 -2
  241. esphome/components/rgbw/rgbw_light_output.h +3 -2
  242. esphome/components/rgbww/rgbww_light_output.h +3 -2
  243. esphome/components/rp2040_pio_led_strip/led_strip.cpp +31 -5
  244. esphome/components/rp2040_pio_led_strip/led_strip.h +5 -0
  245. esphome/components/rtttl/rtttl.cpp +108 -21
  246. esphome/components/rtttl/rtttl.h +15 -6
  247. esphome/components/select/__init__.py +7 -7
  248. esphome/components/sensor/__init__.py +29 -10
  249. esphome/components/sensor/filter.cpp +8 -0
  250. esphome/components/sensor/filter.h +9 -0
  251. esphome/components/sml/sml_parser.cpp +48 -22
  252. esphome/components/socket/socket.cpp +11 -14
  253. esphome/components/speaker/__init__.py +14 -5
  254. esphome/components/speaker/automation.h +10 -0
  255. esphome/components/speaker/speaker.h +9 -0
  256. esphome/components/spi/spi.cpp +0 -6
  257. esphome/components/spi/spi.h +2 -19
  258. esphome/components/spi_led_strip/spi_led_strip.h +5 -4
  259. esphome/components/sprinkler/sprinkler.cpp +2 -2
  260. esphome/components/sprinkler/sprinkler.h +1 -1
  261. esphome/components/switch/__init__.py +3 -3
  262. esphome/components/text/__init__.py +5 -5
  263. esphome/components/text_sensor/__init__.py +7 -7
  264. esphome/components/time/__init__.py +8 -8
  265. esphome/components/touchscreen/binary_sensor/__init__.py +24 -10
  266. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +3 -2
  267. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +4 -2
  268. esphome/components/uart/uart_component_host.cpp +6 -2
  269. esphome/components/update/__init__.py +33 -15
  270. esphome/components/update/automation.h +23 -0
  271. esphome/components/update/update_entity.h +3 -1
  272. esphome/components/valve/__init__.py +3 -3
  273. esphome/components/voice_assistant/__init__.py +7 -8
  274. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -0
  275. esphome/components/wake_on_lan/wake_on_lan.h +3 -1
  276. esphome/components/watchdog/__init__.py +1 -0
  277. esphome/components/{http_request → watchdog}/watchdog.cpp +0 -2
  278. esphome/components/{http_request → watchdog}/watchdog.h +0 -2
  279. esphome/components/waveshare_epaper/waveshare_epaper.cpp +5 -5
  280. esphome/components/web_server/server_index_v3.h +3615 -3603
  281. esphome/components/web_server/web_server.cpp +0 -209
  282. esphome/components/web_server/web_server.h +1 -1
  283. esphome/components/web_server/web_server_v1.cpp +217 -0
  284. esphome/components/web_server_base/web_server_base.h +1 -0
  285. esphome/components/wifi/__init__.py +15 -14
  286. esphome/components/wifi/wifi_component.cpp +2 -0
  287. esphome/components/wifi/wifi_component.h +7 -1
  288. esphome/components/wifi/wifi_component_esp32_arduino.cpp +5 -2
  289. esphome/components/wifi/wifi_component_esp8266.cpp +2 -0
  290. esphome/components/wifi/wifi_component_esp_idf.cpp +43 -7
  291. esphome/components/wifi/wifi_component_libretiny.cpp +2 -0
  292. esphome/components/wifi/wifi_component_pico_w.cpp +2 -0
  293. esphome/components/wifi/wpa2_eap.py +6 -7
  294. esphome/components/wifi_info/text_sensor.py +3 -3
  295. esphome/components/wifi_info/wifi_info_text_sensor.cpp +2 -0
  296. esphome/components/wifi_info/wifi_info_text_sensor.h +2 -0
  297. esphome/components/wifi_signal/sensor.py +1 -1
  298. esphome/components/wifi_signal/wifi_signal_sensor.cpp +2 -0
  299. esphome/components/wifi_signal/wifi_signal_sensor.h +2 -1
  300. esphome/components/xiaomi_ble/xiaomi_ble.cpp +20 -3
  301. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  302. esphome/components/xiaomi_lywsd02mmc/__init__.py +0 -0
  303. esphome/components/xiaomi_lywsd02mmc/sensor.py +77 -0
  304. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp +73 -0
  305. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +37 -0
  306. esphome/config.py +17 -19
  307. esphome/config_validation.py +55 -23
  308. esphome/const.py +25 -9
  309. esphome/core/__init__.py +17 -14
  310. esphome/core/application.h +42 -21
  311. esphome/core/automation.h +5 -3
  312. esphome/core/base_automation.h +3 -2
  313. esphome/core/bytebuffer.cpp +134 -0
  314. esphome/core/bytebuffer.h +96 -0
  315. esphome/core/color.h +24 -16
  316. esphome/core/config.py +3 -3
  317. esphome/core/defines.h +14 -1
  318. esphome/core/entity_base.h +2 -2
  319. esphome/core/entity_helpers.py +1 -2
  320. esphome/core/gpio.h +0 -18
  321. esphome/core/helpers.h +1 -1
  322. esphome/core/optional.h +15 -16
  323. esphome/coroutine.py +1 -1
  324. esphome/cpp_generator.py +1 -1
  325. esphome/cpp_helpers.py +3 -5
  326. esphome/dashboard/core.py +3 -3
  327. esphome/dashboard/dashboard.py +3 -3
  328. esphome/dashboard/entries.py +1 -1
  329. esphome/dashboard/util/file.py +1 -1
  330. esphome/dashboard/web_server.py +3 -3
  331. esphome/external_files.py +5 -3
  332. esphome/final_validate.py +2 -2
  333. esphome/git.py +4 -4
  334. esphome/helpers.py +5 -5
  335. esphome/loader.py +15 -10
  336. esphome/mqtt.py +4 -8
  337. esphome/pins.py +6 -6
  338. esphome/platformio_api.py +5 -5
  339. esphome/storage_json.py +2 -1
  340. esphome/types.py +1 -1
  341. esphome/util.py +2 -3
  342. esphome/voluptuous_schema.py +1 -0
  343. esphome/vscode.py +5 -4
  344. esphome/wizard.py +1 -1
  345. esphome/writer.py +7 -7
  346. esphome/yaml_util.py +3 -3
  347. esphome/zeroconf.py +1 -1
  348. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/METADATA +3 -3
  349. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/RECORD +353 -247
  350. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/LICENSE +0 -0
  351. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/WHEEL +0 -0
  352. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/entry_points.txt +0 -0
  353. {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,302 @@
1
+ from esphome import automation
2
+ import esphome.codegen as cg
3
+ import esphome.config_validation as cv
4
+ from esphome.const import (
5
+ CONF_COLOR,
6
+ CONF_COUNT,
7
+ CONF_ID,
8
+ CONF_LENGTH,
9
+ CONF_LOCAL,
10
+ CONF_RANGE_FROM,
11
+ CONF_RANGE_TO,
12
+ CONF_ROTATION,
13
+ CONF_VALUE,
14
+ CONF_WIDTH,
15
+ )
16
+
17
+ from ..automation import action_to_code
18
+ from ..defines import (
19
+ CONF_END_VALUE,
20
+ CONF_MAIN,
21
+ CONF_PIVOT_X,
22
+ CONF_PIVOT_Y,
23
+ CONF_SRC,
24
+ CONF_START_VALUE,
25
+ CONF_TICKS,
26
+ )
27
+ from ..helpers import add_lv_use
28
+ from ..lv_validation import (
29
+ angle,
30
+ get_end_value,
31
+ get_start_value,
32
+ lv_bool,
33
+ lv_color,
34
+ lv_float,
35
+ lv_image,
36
+ requires_component,
37
+ size,
38
+ )
39
+ from ..lvcode import LocalVariable, lv, lv_assign, lv_expr
40
+ from ..types import LvType, ObjUpdateAction
41
+ from . import Widget, WidgetType, get_widgets
42
+ from .arc import CONF_ARC
43
+ from .img import CONF_IMAGE
44
+ from .line import CONF_LINE
45
+ from .obj import obj_spec
46
+
47
+ CONF_ANGLE_RANGE = "angle_range"
48
+ CONF_COLOR_END = "color_end"
49
+ CONF_COLOR_START = "color_start"
50
+ CONF_INDICATORS = "indicators"
51
+ CONF_LABEL_GAP = "label_gap"
52
+ CONF_MAJOR = "major"
53
+ CONF_METER = "meter"
54
+ CONF_R_MOD = "r_mod"
55
+ CONF_SCALES = "scales"
56
+ CONF_STRIDE = "stride"
57
+ CONF_TICK_STYLE = "tick_style"
58
+
59
+ lv_meter_t = LvType("lv_meter_t")
60
+ lv_meter_indicator_t = cg.global_ns.struct("lv_meter_indicator_t")
61
+ lv_meter_indicator_t_ptr = lv_meter_indicator_t.operator("ptr")
62
+
63
+
64
+ def pixels(value):
65
+ """A size in one axis in pixels"""
66
+ if isinstance(value, str) and value.lower().endswith("px"):
67
+ return cv.int_(value[:-2])
68
+ return cv.int_(value)
69
+
70
+
71
+ INDICATOR_LINE_SCHEMA = cv.Schema(
72
+ {
73
+ cv.Optional(CONF_WIDTH, default=4): size,
74
+ cv.Optional(CONF_COLOR, default=0): lv_color,
75
+ cv.Optional(CONF_R_MOD, default=0): size,
76
+ cv.Optional(CONF_VALUE): lv_float,
77
+ }
78
+ )
79
+ INDICATOR_IMG_SCHEMA = cv.Schema(
80
+ {
81
+ cv.Required(CONF_SRC): lv_image,
82
+ cv.Required(CONF_PIVOT_X): pixels,
83
+ cv.Required(CONF_PIVOT_Y): pixels,
84
+ cv.Optional(CONF_VALUE): lv_float,
85
+ }
86
+ )
87
+ INDICATOR_ARC_SCHEMA = cv.Schema(
88
+ {
89
+ cv.Optional(CONF_WIDTH, default=4): size,
90
+ cv.Optional(CONF_COLOR, default=0): lv_color,
91
+ cv.Optional(CONF_R_MOD, default=0): size,
92
+ cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float,
93
+ cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float,
94
+ cv.Optional(CONF_END_VALUE): lv_float,
95
+ }
96
+ )
97
+ INDICATOR_TICKS_SCHEMA = cv.Schema(
98
+ {
99
+ cv.Optional(CONF_WIDTH, default=4): size,
100
+ cv.Optional(CONF_COLOR_START, default=0): lv_color,
101
+ cv.Optional(CONF_COLOR_END): lv_color,
102
+ cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float,
103
+ cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float,
104
+ cv.Optional(CONF_END_VALUE): lv_float,
105
+ cv.Optional(CONF_LOCAL, default=False): lv_bool,
106
+ }
107
+ )
108
+ INDICATOR_SCHEMA = cv.Schema(
109
+ {
110
+ cv.Exclusive(CONF_LINE, CONF_INDICATORS): INDICATOR_LINE_SCHEMA.extend(
111
+ {
112
+ cv.GenerateID(): cv.declare_id(lv_meter_indicator_t),
113
+ }
114
+ ),
115
+ cv.Exclusive(CONF_IMAGE, CONF_INDICATORS): cv.All(
116
+ INDICATOR_IMG_SCHEMA.extend(
117
+ {
118
+ cv.GenerateID(): cv.declare_id(lv_meter_indicator_t),
119
+ }
120
+ ),
121
+ requires_component("image"),
122
+ ),
123
+ cv.Exclusive(CONF_ARC, CONF_INDICATORS): INDICATOR_ARC_SCHEMA.extend(
124
+ {
125
+ cv.GenerateID(): cv.declare_id(lv_meter_indicator_t),
126
+ }
127
+ ),
128
+ cv.Exclusive(CONF_TICK_STYLE, CONF_INDICATORS): INDICATOR_TICKS_SCHEMA.extend(
129
+ {
130
+ cv.GenerateID(): cv.declare_id(lv_meter_indicator_t),
131
+ }
132
+ ),
133
+ }
134
+ )
135
+
136
+ SCALE_SCHEMA = cv.Schema(
137
+ {
138
+ cv.Optional(CONF_TICKS): cv.Schema(
139
+ {
140
+ cv.Optional(CONF_COUNT, default=12): cv.positive_int,
141
+ cv.Optional(CONF_WIDTH, default=2): size,
142
+ cv.Optional(CONF_LENGTH, default=10): size,
143
+ cv.Optional(CONF_COLOR, default=0x808080): lv_color,
144
+ cv.Optional(CONF_MAJOR): cv.Schema(
145
+ {
146
+ cv.Optional(CONF_STRIDE, default=3): cv.positive_int,
147
+ cv.Optional(CONF_WIDTH, default=5): size,
148
+ cv.Optional(CONF_LENGTH, default="15%"): size,
149
+ cv.Optional(CONF_COLOR, default=0): lv_color,
150
+ cv.Optional(CONF_LABEL_GAP, default=4): size,
151
+ }
152
+ ),
153
+ }
154
+ ),
155
+ cv.Optional(CONF_RANGE_FROM, default=0.0): cv.float_,
156
+ cv.Optional(CONF_RANGE_TO, default=100.0): cv.float_,
157
+ cv.Optional(CONF_ANGLE_RANGE, default=270): cv.int_range(0, 360),
158
+ cv.Optional(CONF_ROTATION): angle,
159
+ cv.Optional(CONF_INDICATORS): cv.ensure_list(INDICATOR_SCHEMA),
160
+ }
161
+ )
162
+
163
+ METER_SCHEMA = {cv.Optional(CONF_SCALES): cv.ensure_list(SCALE_SCHEMA)}
164
+
165
+
166
+ class MeterType(WidgetType):
167
+ def __init__(self):
168
+ super().__init__(CONF_METER, lv_meter_t, (CONF_MAIN,), METER_SCHEMA)
169
+
170
+ async def to_code(self, w: Widget, config):
171
+ """For a meter object, create and set parameters"""
172
+
173
+ var = w.obj
174
+ for scale_conf in config.get(CONF_SCALES, ()):
175
+ rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2
176
+ if CONF_ROTATION in scale_conf:
177
+ rotation = scale_conf[CONF_ROTATION] // 10
178
+ with LocalVariable(
179
+ "meter_var", "lv_meter_scale_t", lv_expr.meter_add_scale(var)
180
+ ) as meter_var:
181
+ lv.meter_set_scale_range(
182
+ var,
183
+ meter_var,
184
+ scale_conf[CONF_RANGE_FROM],
185
+ scale_conf[CONF_RANGE_TO],
186
+ scale_conf[CONF_ANGLE_RANGE],
187
+ rotation,
188
+ )
189
+ if ticks := scale_conf.get(CONF_TICKS):
190
+ color = await lv_color.process(ticks[CONF_COLOR])
191
+ lv.meter_set_scale_ticks(
192
+ var,
193
+ meter_var,
194
+ ticks[CONF_COUNT],
195
+ ticks[CONF_WIDTH],
196
+ ticks[CONF_LENGTH],
197
+ color,
198
+ )
199
+ if CONF_MAJOR in ticks:
200
+ major = ticks[CONF_MAJOR]
201
+ color = await lv_color.process(major[CONF_COLOR])
202
+ lv.meter_set_scale_major_ticks(
203
+ var,
204
+ meter_var,
205
+ major[CONF_STRIDE],
206
+ major[CONF_WIDTH],
207
+ major[CONF_LENGTH],
208
+ color,
209
+ major[CONF_LABEL_GAP],
210
+ )
211
+ for indicator in scale_conf.get(CONF_INDICATORS, ()):
212
+ (t, v) = next(iter(indicator.items()))
213
+ iid = v[CONF_ID]
214
+ ivar = cg.new_variable(
215
+ iid, cg.nullptr, type_=lv_meter_indicator_t_ptr
216
+ )
217
+ # Enable getting the meter to which this belongs.
218
+ wid = Widget.create(iid, var, obj_spec, v)
219
+ wid.obj = ivar
220
+ if t == CONF_LINE:
221
+ color = await lv_color.process(v[CONF_COLOR])
222
+ lv_assign(
223
+ ivar,
224
+ lv_expr.meter_add_needle_line(
225
+ var, meter_var, v[CONF_WIDTH], color, v[CONF_R_MOD]
226
+ ),
227
+ )
228
+ if t == CONF_ARC:
229
+ color = await lv_color.process(v[CONF_COLOR])
230
+ lv_assign(
231
+ ivar,
232
+ lv_expr.meter_add_arc(
233
+ var, meter_var, v[CONF_WIDTH], color, v[CONF_R_MOD]
234
+ ),
235
+ )
236
+ if t == CONF_TICK_STYLE:
237
+ color_start = await lv_color.process(v[CONF_COLOR_START])
238
+ color_end = await lv_color.process(
239
+ v.get(CONF_COLOR_END) or color_start
240
+ )
241
+ lv_assign(
242
+ ivar,
243
+ lv_expr.meter_add_scale_lines(
244
+ var,
245
+ meter_var,
246
+ color_start,
247
+ color_end,
248
+ v[CONF_LOCAL],
249
+ v[CONF_WIDTH],
250
+ ),
251
+ )
252
+ if t == CONF_IMAGE:
253
+ add_lv_use("img")
254
+ lv_assign(
255
+ ivar,
256
+ lv_expr.meter_add_needle_img(
257
+ var,
258
+ meter_var,
259
+ await lv_image.process(v[CONF_SRC]),
260
+ v[CONF_PIVOT_X],
261
+ v[CONF_PIVOT_Y],
262
+ ),
263
+ )
264
+ start_value = await get_start_value(v)
265
+ end_value = await get_end_value(v)
266
+ set_indicator_values(var, ivar, start_value, end_value)
267
+
268
+
269
+ meter_spec = MeterType()
270
+
271
+
272
+ @automation.register_action(
273
+ "lvgl.indicator.update",
274
+ ObjUpdateAction,
275
+ cv.Schema(
276
+ {
277
+ cv.Required(CONF_ID): cv.use_id(lv_meter_indicator_t),
278
+ cv.Exclusive(CONF_VALUE, CONF_VALUE): lv_float,
279
+ cv.Exclusive(CONF_START_VALUE, CONF_VALUE): lv_float,
280
+ cv.Optional(CONF_END_VALUE): lv_float,
281
+ }
282
+ ),
283
+ )
284
+ async def indicator_update_to_code(config, action_id, template_arg, args):
285
+ widget = await get_widgets(config)
286
+ start_value = await get_start_value(config)
287
+ end_value = await get_end_value(config)
288
+
289
+ async def set_value(w: Widget):
290
+ set_indicator_values(w.var, w.obj, start_value, end_value)
291
+
292
+ return await action_to_code(widget, set_value, action_id, template_arg, args)
293
+
294
+
295
+ def set_indicator_values(meter, indicator, start_value, end_value):
296
+ if start_value is not None:
297
+ if end_value is None:
298
+ lv.meter_set_indicator_value(meter, indicator, start_value)
299
+ else:
300
+ lv.meter_set_indicator_start_value(meter, indicator, start_value)
301
+ if end_value is not None:
302
+ lv.meter_set_indicator_end_value(meter, indicator, end_value)
@@ -0,0 +1,134 @@
1
+ from esphome import config_validation as cv
2
+ from esphome.const import CONF_BUTTON, CONF_ID, CONF_TEXT
3
+ from esphome.core import ID
4
+ from esphome.cpp_generator import new_Pvariable, static_const_array
5
+ from esphome.cpp_types import nullptr
6
+
7
+ from ..defines import (
8
+ CONF_BODY,
9
+ CONF_BUTTONS,
10
+ CONF_CLOSE_BUTTON,
11
+ CONF_MSGBOXES,
12
+ CONF_TITLE,
13
+ TYPE_FLEX,
14
+ literal,
15
+ )
16
+ from ..helpers import add_lv_use
17
+ from ..lv_validation import lv_bool, lv_pct, lv_text
18
+ from ..lvcode import (
19
+ EVENT_ARG,
20
+ LambdaContext,
21
+ LocalVariable,
22
+ lv_add,
23
+ lv_assign,
24
+ lv_expr,
25
+ lv_obj,
26
+ lv_Pvariable,
27
+ )
28
+ from ..schemas import STYLE_SCHEMA, STYLED_TEXT_SCHEMA, container_schema
29
+ from ..styles import TOP_LAYER
30
+ from ..types import LV_EVENT, char_ptr, lv_obj_t
31
+ from . import Widget, set_obj_properties
32
+ from .button import button_spec
33
+ from .buttonmatrix import (
34
+ BUTTONMATRIX_BUTTON_SCHEMA,
35
+ CONF_BUTTON_TEXT_LIST_ID,
36
+ buttonmatrix_spec,
37
+ get_button_data,
38
+ lv_buttonmatrix_t,
39
+ set_btn_data,
40
+ )
41
+ from .label import CONF_LABEL
42
+ from .obj import obj_spec
43
+
44
+ CONF_MSGBOX = "msgbox"
45
+ MSGBOX_SCHEMA = container_schema(
46
+ obj_spec,
47
+ STYLE_SCHEMA.extend(
48
+ {
49
+ cv.GenerateID(CONF_ID): cv.declare_id(lv_obj_t),
50
+ cv.Required(CONF_TITLE): STYLED_TEXT_SCHEMA,
51
+ cv.Optional(CONF_BODY): STYLED_TEXT_SCHEMA,
52
+ cv.Optional(CONF_BUTTONS): cv.ensure_list(BUTTONMATRIX_BUTTON_SCHEMA),
53
+ cv.Optional(CONF_CLOSE_BUTTON): lv_bool,
54
+ cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr),
55
+ }
56
+ ),
57
+ )
58
+
59
+
60
+ async def msgbox_to_code(conf):
61
+ """
62
+ Construct a message box. This consists of a full-screen translucent background enclosing a centered container
63
+ with an optional title, body, close button and a button matrix. And any other widgets the user cares to add
64
+ :param conf: The config data
65
+ :return: code to add to the init lambda
66
+ """
67
+ add_lv_use(
68
+ TYPE_FLEX,
69
+ CONF_BUTTON,
70
+ CONF_LABEL,
71
+ CONF_MSGBOX,
72
+ *buttonmatrix_spec.get_uses(),
73
+ *button_spec.get_uses(),
74
+ )
75
+ messagebox_id = conf[CONF_ID]
76
+ outer = lv_Pvariable(lv_obj_t, messagebox_id.id)
77
+ buttonmatrix = new_Pvariable(
78
+ ID(
79
+ f"{messagebox_id.id}_buttonmatrix_",
80
+ is_declaration=True,
81
+ type=lv_buttonmatrix_t,
82
+ )
83
+ )
84
+ msgbox = lv_Pvariable(lv_obj_t, f"{messagebox_id.id}_msgbox")
85
+ outer_widget = Widget.create(messagebox_id, outer, obj_spec, conf)
86
+ buttonmatrix_widget = Widget.create(
87
+ str(buttonmatrix), buttonmatrix, buttonmatrix_spec, conf
88
+ )
89
+ text_list, ctrl_list, width_list, _ = await get_button_data(
90
+ (conf,), buttonmatrix_widget
91
+ )
92
+ text_id = conf[CONF_BUTTON_TEXT_LIST_ID]
93
+ text_list = static_const_array(text_id, text_list)
94
+ if (text := conf.get(CONF_BODY)) is not None:
95
+ text = await lv_text.process(text.get(CONF_TEXT))
96
+ if (title := conf.get(CONF_TITLE)) is not None:
97
+ title = await lv_text.process(title.get(CONF_TEXT))
98
+ close_button = conf[CONF_CLOSE_BUTTON]
99
+ lv_assign(outer, lv_expr.obj_create(TOP_LAYER))
100
+ lv_obj.set_width(outer, lv_pct(100))
101
+ lv_obj.set_height(outer, lv_pct(100))
102
+ lv_obj.set_style_bg_opa(outer, 128, 0)
103
+ lv_obj.set_style_bg_color(outer, literal("lv_color_black()"), 0)
104
+ lv_obj.set_style_border_width(outer, 0, 0)
105
+ lv_obj.set_style_pad_all(outer, 0, 0)
106
+ lv_obj.set_style_radius(outer, 0, 0)
107
+ outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
108
+ lv_assign(
109
+ msgbox, lv_expr.msgbox_create(outer, title, text, text_list, close_button)
110
+ )
111
+ lv_obj.set_style_align(msgbox, literal("LV_ALIGN_CENTER"), 0)
112
+ lv_add(buttonmatrix.set_obj(lv_expr.msgbox_get_btns(msgbox)))
113
+ await set_obj_properties(outer_widget, conf)
114
+ if close_button:
115
+ async with LambdaContext(EVENT_ARG, where=messagebox_id) as context:
116
+ outer_widget.add_flag("LV_OBJ_FLAG_HIDDEN")
117
+ with LocalVariable(
118
+ "close_btn_", lv_obj_t, lv_expr.msgbox_get_close_btn(msgbox)
119
+ ) as close_btn:
120
+ lv_obj.remove_event_cb(close_btn, nullptr)
121
+ lv_obj.add_event_cb(
122
+ close_btn,
123
+ await context.get_lambda(),
124
+ LV_EVENT.CLICKED,
125
+ nullptr,
126
+ )
127
+
128
+ if len(ctrl_list) != 0 or len(width_list) != 0:
129
+ set_btn_data(buttonmatrix.obj, ctrl_list, width_list)
130
+
131
+
132
+ async def msgboxes_to_code(config):
133
+ for conf in config.get(CONF_MSGBOXES, ()):
134
+ await msgbox_to_code(conf)
@@ -0,0 +1,28 @@
1
+ from esphome import automation
2
+
3
+ from ..automation import update_to_code
4
+ from ..defines import CONF_MAIN, CONF_OBJ
5
+ from ..schemas import create_modify_schema
6
+ from ..types import ObjUpdateAction, WidgetType, lv_obj_t
7
+
8
+
9
+ class ObjType(WidgetType):
10
+ """
11
+ The base LVGL object. All other widgets inherit from this.
12
+ """
13
+
14
+ def __init__(self):
15
+ super().__init__(CONF_OBJ, lv_obj_t, (CONF_MAIN,), schema={}, modify_schema={})
16
+
17
+ async def to_code(self, w, config):
18
+ return []
19
+
20
+
21
+ obj_spec = ObjType()
22
+
23
+
24
+ @automation.register_action(
25
+ "lvgl.widget.update", ObjUpdateAction, create_modify_schema(obj_spec)
26
+ )
27
+ async def obj_update_to_code(config, action_id, template_arg, args):
28
+ return await update_to_code(config, action_id, template_arg, args)
@@ -0,0 +1,113 @@
1
+ from esphome import automation, codegen as cg
2
+ import esphome.config_validation as cv
3
+ from esphome.const import CONF_ID, CONF_PAGES, CONF_TIME
4
+
5
+ from ..defines import (
6
+ CONF_ANIMATION,
7
+ CONF_LVGL_ID,
8
+ CONF_PAGE,
9
+ CONF_PAGE_WRAP,
10
+ CONF_SKIP,
11
+ LV_ANIM,
12
+ )
13
+ from ..lv_validation import lv_bool, lv_milliseconds
14
+ from ..lvcode import LVGL_COMP_ARG, LambdaContext, add_line_marks, lv_add, lvgl_comp
15
+ from ..schemas import LVGL_SCHEMA
16
+ from ..types import LvglAction, lv_page_t
17
+ from . import Widget, WidgetType, add_widgets, set_obj_properties
18
+
19
+
20
+ class PageType(WidgetType):
21
+ def __init__(self):
22
+ super().__init__(
23
+ CONF_PAGE,
24
+ lv_page_t,
25
+ (),
26
+ {
27
+ cv.Optional(CONF_SKIP, default=False): lv_bool,
28
+ },
29
+ )
30
+
31
+ async def to_code(self, w: Widget, config: dict):
32
+ return []
33
+
34
+
35
+ SHOW_SCHEMA = LVGL_SCHEMA.extend(
36
+ {
37
+ cv.Optional(CONF_ANIMATION, default="NONE"): LV_ANIM.one_of,
38
+ cv.Optional(CONF_TIME, default="50ms"): lv_milliseconds,
39
+ }
40
+ )
41
+
42
+
43
+ page_spec = PageType()
44
+
45
+
46
+ @automation.register_action(
47
+ "lvgl.page.next",
48
+ LvglAction,
49
+ SHOW_SCHEMA,
50
+ )
51
+ async def page_next_to_code(config, action_id, template_arg, args):
52
+ animation = await LV_ANIM.process(config[CONF_ANIMATION])
53
+ time = await lv_milliseconds.process(config[CONF_TIME])
54
+ async with LambdaContext(LVGL_COMP_ARG) as context:
55
+ add_line_marks(action_id)
56
+ lv_add(lvgl_comp.show_next_page(animation, time))
57
+ var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
58
+ await cg.register_parented(var, config[CONF_LVGL_ID])
59
+ return var
60
+
61
+
62
+ @automation.register_action(
63
+ "lvgl.page.previous",
64
+ LvglAction,
65
+ SHOW_SCHEMA,
66
+ )
67
+ async def page_previous_to_code(config, action_id, template_arg, args):
68
+ animation = await LV_ANIM.process(config[CONF_ANIMATION])
69
+ time = await lv_milliseconds.process(config[CONF_TIME])
70
+ async with LambdaContext(LVGL_COMP_ARG) as context:
71
+ add_line_marks(action_id)
72
+ lv_add(lvgl_comp.show_prev_page(animation, time))
73
+ var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
74
+ await cg.register_parented(var, config[CONF_LVGL_ID])
75
+ return var
76
+
77
+
78
+ @automation.register_action(
79
+ "lvgl.page.show",
80
+ LvglAction,
81
+ cv.maybe_simple_value(
82
+ SHOW_SCHEMA.extend(
83
+ {
84
+ cv.Required(CONF_ID): cv.use_id(lv_page_t),
85
+ }
86
+ ),
87
+ key=CONF_ID,
88
+ ),
89
+ )
90
+ async def page_show_to_code(config, action_id, template_arg, args):
91
+ widget = await cg.get_variable(config[CONF_ID])
92
+ animation = await LV_ANIM.process(config[CONF_ANIMATION])
93
+ time = await lv_milliseconds.process(config[CONF_TIME])
94
+ async with LambdaContext(LVGL_COMP_ARG) as context:
95
+ add_line_marks(action_id)
96
+ lv_add(lvgl_comp.show_page(widget.index, animation, time))
97
+ var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda())
98
+ await cg.register_parented(var, config[CONF_LVGL_ID])
99
+ return var
100
+
101
+
102
+ async def add_pages(lv_component, config):
103
+ lv_add(lv_component.set_page_wrap(config[CONF_PAGE_WRAP]))
104
+ for pconf in config.get(CONF_PAGES, ()):
105
+ id = pconf[CONF_ID]
106
+ skip = pconf[CONF_SKIP]
107
+ var = cg.new_Pvariable(id, skip)
108
+ page = Widget.create(id, var, page_spec, pconf)
109
+ lv_add(lv_component.add_page(var))
110
+ # Set outer config first
111
+ await set_obj_properties(page, config)
112
+ await set_obj_properties(page, pconf)
113
+ await add_widgets(page, pconf)
@@ -0,0 +1,77 @@
1
+ import esphome.codegen as cg
2
+ import esphome.config_validation as cv
3
+ from esphome.const import CONF_MODE, CONF_OPTIONS
4
+
5
+ from ..defines import (
6
+ CONF_ANIMATED,
7
+ CONF_MAIN,
8
+ CONF_SELECTED,
9
+ CONF_SELECTED_INDEX,
10
+ CONF_VISIBLE_ROW_COUNT,
11
+ ROLLER_MODES,
12
+ literal,
13
+ )
14
+ from ..lv_validation import animated, lv_int, option_string
15
+ from ..lvcode import lv
16
+ from ..types import LvSelect
17
+ from . import WidgetType
18
+ from .label import CONF_LABEL
19
+
20
+ CONF_ROLLER = "roller"
21
+ lv_roller_t = LvSelect("lv_roller_t")
22
+
23
+ ROLLER_BASE_SCHEMA = cv.Schema(
24
+ {
25
+ cv.Optional(CONF_SELECTED_INDEX): cv.templatable(cv.int_),
26
+ cv.Optional(CONF_VISIBLE_ROW_COUNT): lv_int,
27
+ }
28
+ )
29
+
30
+ ROLLER_SCHEMA = ROLLER_BASE_SCHEMA.extend(
31
+ {
32
+ cv.Required(CONF_OPTIONS): cv.ensure_list(option_string),
33
+ cv.Optional(CONF_MODE, default="NORMAL"): ROLLER_MODES.one_of,
34
+ }
35
+ )
36
+
37
+ ROLLER_MODIFY_SCHEMA = ROLLER_BASE_SCHEMA.extend(
38
+ {
39
+ cv.Optional(CONF_ANIMATED, default=True): animated,
40
+ }
41
+ )
42
+
43
+
44
+ class RollerType(WidgetType):
45
+ def __init__(self):
46
+ super().__init__(
47
+ CONF_ROLLER,
48
+ lv_roller_t,
49
+ (CONF_MAIN, CONF_SELECTED),
50
+ ROLLER_SCHEMA,
51
+ ROLLER_MODIFY_SCHEMA,
52
+ )
53
+
54
+ async def to_code(self, w, config):
55
+ if options := config.get(CONF_OPTIONS):
56
+ mode = await ROLLER_MODES.process(config[CONF_MODE])
57
+ text = cg.safe_exp("\n".join(options))
58
+ lv.roller_set_options(w.obj, text, mode)
59
+ animopt = literal(config.get(CONF_ANIMATED) or "LV_ANIM_OFF")
60
+ if CONF_SELECTED_INDEX in config:
61
+ if selected := config[CONF_SELECTED_INDEX]:
62
+ value = await lv_int.process(selected)
63
+ lv.roller_set_selected(w.obj, value, animopt)
64
+ await w.set_property(
65
+ CONF_VISIBLE_ROW_COUNT,
66
+ await lv_int.process(config.get(CONF_VISIBLE_ROW_COUNT)),
67
+ )
68
+
69
+ @property
70
+ def animated(self):
71
+ return True
72
+
73
+ def get_uses(self):
74
+ return (CONF_LABEL,)
75
+
76
+
77
+ roller_spec = RollerType()