esphome 2024.7.3__py3-none-any.whl → 2024.8.0b1__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 (341) 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 +79 -51
  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 +9 -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/http_request/__init__.py +12 -1
  100. esphome/components/http_request/http_request_arduino.cpp +2 -2
  101. esphome/components/http_request/http_request_idf.cpp +11 -2
  102. esphome/components/http_request/http_request_idf.h +10 -0
  103. esphome/components/http_request/ota/ota_http_request.cpp +1 -1
  104. esphome/components/http_request/update/http_request_update.cpp +2 -2
  105. esphome/components/http_request/update/http_request_update.h +2 -1
  106. esphome/components/hx711/hx711.cpp +10 -1
  107. esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +1 -1
  108. esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +11 -2
  109. esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
  110. esphome/components/ili9xxx/ili9xxx_defines.h +3 -1
  111. esphome/components/ili9xxx/ili9xxx_display.cpp +9 -22
  112. esphome/components/ili9xxx/ili9xxx_display.h +5 -7
  113. esphome/components/ili9xxx/ili9xxx_init.h +4 -4
  114. esphome/components/improv_base/__init__.py +2 -3
  115. esphome/components/improv_serial/__init__.py +4 -10
  116. esphome/components/improv_serial/improv_serial_component.cpp +4 -0
  117. esphome/components/jsn_sr04t/jsn_sr04t.cpp +18 -1
  118. esphome/components/jsn_sr04t/jsn_sr04t.h +7 -1
  119. esphome/components/jsn_sr04t/sensor.py +13 -0
  120. esphome/components/kalman_combinator/sensor.py +1 -1
  121. esphome/components/light/__init__.py +16 -15
  122. esphome/components/light/addressable_light_effect.h +12 -8
  123. esphome/components/light/automation.h +16 -1
  124. esphome/components/light/automation.py +21 -0
  125. esphome/components/light/base_light_effects.h +5 -5
  126. esphome/components/light/types.py +7 -0
  127. esphome/components/lock/__init__.py +3 -3
  128. esphome/components/logger/__init__.py +15 -18
  129. esphome/components/lvgl/__init__.py +346 -0
  130. esphome/components/lvgl/automation.py +226 -0
  131. esphome/components/lvgl/binary_sensor/__init__.py +43 -0
  132. esphome/components/lvgl/defines.py +504 -0
  133. esphome/components/lvgl/encoders.py +77 -0
  134. esphome/components/lvgl/font.cpp +76 -0
  135. esphome/components/lvgl/helpers.py +49 -0
  136. esphome/components/lvgl/light/__init__.py +32 -0
  137. esphome/components/lvgl/light/lvgl_light.h +48 -0
  138. esphome/components/lvgl/lv_validation.py +279 -0
  139. esphome/components/lvgl/lvcode.py +349 -0
  140. esphome/components/lvgl/lvgl_esphome.cpp +407 -0
  141. esphome/components/lvgl/lvgl_esphome.h +274 -0
  142. esphome/components/lvgl/lvgl_hal.h +21 -0
  143. esphome/components/lvgl/number/__init__.py +66 -0
  144. esphome/components/lvgl/number/lvgl_number.h +34 -0
  145. esphome/components/lvgl/schemas.py +426 -0
  146. esphome/components/lvgl/select/__init__.py +55 -0
  147. esphome/components/lvgl/select/lvgl_select.h +62 -0
  148. esphome/components/lvgl/sensor/__init__.py +47 -0
  149. esphome/components/lvgl/styles.py +58 -0
  150. esphome/components/lvgl/switch/__init__.py +56 -0
  151. esphome/components/lvgl/switch/lvgl_switch.h +34 -0
  152. esphome/components/lvgl/text/__init__.py +50 -0
  153. esphome/components/lvgl/text/lvgl_text.h +34 -0
  154. esphome/components/lvgl/text_sensor/__init__.py +42 -0
  155. esphome/components/lvgl/touchscreens.py +45 -0
  156. esphome/components/lvgl/trigger.py +74 -0
  157. esphome/components/lvgl/types.py +191 -0
  158. esphome/components/lvgl/widgets/__init__.py +400 -0
  159. esphome/components/lvgl/widgets/animimg.py +117 -0
  160. esphome/components/lvgl/widgets/arc.py +78 -0
  161. esphome/components/lvgl/widgets/button.py +20 -0
  162. esphome/components/lvgl/widgets/buttonmatrix.py +275 -0
  163. esphome/components/lvgl/widgets/checkbox.py +27 -0
  164. esphome/components/lvgl/widgets/dropdown.py +76 -0
  165. esphome/components/lvgl/widgets/img.py +85 -0
  166. esphome/components/lvgl/widgets/keyboard.py +49 -0
  167. esphome/components/lvgl/widgets/label.py +42 -0
  168. esphome/components/lvgl/widgets/led.py +29 -0
  169. esphome/components/lvgl/widgets/line.py +50 -0
  170. esphome/components/lvgl/widgets/lv_bar.py +55 -0
  171. esphome/components/lvgl/widgets/meter.py +302 -0
  172. esphome/components/lvgl/widgets/msgbox.py +134 -0
  173. esphome/components/lvgl/widgets/obj.py +28 -0
  174. esphome/components/lvgl/widgets/page.py +113 -0
  175. esphome/components/lvgl/widgets/roller.py +77 -0
  176. esphome/components/lvgl/widgets/slider.py +63 -0
  177. esphome/components/lvgl/widgets/spinbox.py +178 -0
  178. esphome/components/lvgl/widgets/spinner.py +43 -0
  179. esphome/components/lvgl/widgets/switch.py +20 -0
  180. esphome/components/lvgl/widgets/tabview.py +114 -0
  181. esphome/components/lvgl/widgets/textarea.py +66 -0
  182. esphome/components/lvgl/widgets/tileview.py +128 -0
  183. esphome/components/m5stack_8angle/__init__.py +33 -0
  184. esphome/components/m5stack_8angle/binary_sensor/__init__.py +30 -0
  185. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +17 -0
  186. esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h +19 -0
  187. esphome/components/m5stack_8angle/light/__init__.py +31 -0
  188. esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +45 -0
  189. esphome/components/m5stack_8angle/light/m5stack_8angle_light.h +37 -0
  190. esphome/components/m5stack_8angle/m5stack_8angle.cpp +74 -0
  191. esphome/components/m5stack_8angle/m5stack_8angle.h +34 -0
  192. esphome/components/m5stack_8angle/sensor/__init__.py +66 -0
  193. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +24 -0
  194. esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h +27 -0
  195. esphome/components/matrix_keypad/matrix_keypad.cpp +2 -0
  196. esphome/components/max31856/sensor.py +5 -5
  197. esphome/components/media_player/__init__.py +3 -5
  198. esphome/components/media_player/automation.h +31 -27
  199. esphome/components/micro_wake_word/__init__.py +20 -25
  200. esphome/components/modbus_controller/__init__.py +26 -2
  201. esphome/components/modbus_controller/automation.h +19 -0
  202. esphome/components/modbus_controller/const.py +1 -0
  203. esphome/components/modbus_controller/modbus_controller.cpp +8 -0
  204. esphome/components/modbus_controller/modbus_controller.h +3 -0
  205. esphome/components/mqtt/__init__.py +20 -9
  206. esphome/components/mqtt/mqtt_alarm_control_panel.cpp +128 -0
  207. esphome/components/mqtt/mqtt_alarm_control_panel.h +39 -0
  208. esphome/components/mqtt/mqtt_backend.h +3 -1
  209. esphome/components/mqtt/mqtt_backend_esp32.cpp +4 -1
  210. esphome/components/mqtt/mqtt_backend_esp32.h +3 -1
  211. esphome/components/mqtt/mqtt_backend_esp8266.h +3 -1
  212. esphome/components/mqtt/mqtt_backend_libretiny.h +3 -1
  213. esphome/components/mqtt/mqtt_client.cpp +16 -3
  214. esphome/components/mqtt/mqtt_client.h +5 -1
  215. esphome/components/mqtt/mqtt_component.cpp +32 -4
  216. esphome/components/mqtt/mqtt_const.h +2 -0
  217. esphome/components/network/__init__.py +10 -11
  218. esphome/components/network/ip_address.h +3 -0
  219. esphome/components/network/util.cpp +2 -1
  220. esphome/components/network/util.h +3 -1
  221. esphome/components/nextion/base_component.py +5 -8
  222. esphome/components/number/__init__.py +7 -8
  223. esphome/components/online_image/__init__.py +167 -0
  224. esphome/components/online_image/image_decoder.cpp +44 -0
  225. esphome/components/online_image/image_decoder.h +112 -0
  226. esphome/components/online_image/online_image.cpp +283 -0
  227. esphome/components/online_image/online_image.h +195 -0
  228. esphome/components/online_image/png_image.cpp +68 -0
  229. esphome/components/online_image/png_image.h +33 -0
  230. esphome/components/ota/__init__.py +8 -4
  231. esphome/components/pid/pid_climate.h +2 -0
  232. esphome/components/remote_transmitter/remote_transmitter.h +1 -1
  233. esphome/components/rgbct/rgbct_light_output.h +3 -2
  234. esphome/components/rgbw/rgbw_light_output.h +3 -2
  235. esphome/components/rgbww/rgbww_light_output.h +3 -2
  236. esphome/components/select/__init__.py +7 -7
  237. esphome/components/sensor/__init__.py +29 -10
  238. esphome/components/sensor/filter.cpp +8 -0
  239. esphome/components/sensor/filter.h +9 -0
  240. esphome/components/sml/sml_parser.cpp +48 -22
  241. esphome/components/socket/socket.cpp +11 -14
  242. esphome/components/speaker/__init__.py +14 -5
  243. esphome/components/speaker/automation.h +10 -0
  244. esphome/components/speaker/speaker.h +5 -0
  245. esphome/components/spi/spi.cpp +0 -6
  246. esphome/components/spi/spi.h +2 -19
  247. esphome/components/spi_led_strip/spi_led_strip.h +5 -4
  248. esphome/components/sprinkler/sprinkler.cpp +2 -2
  249. esphome/components/sprinkler/sprinkler.h +1 -1
  250. esphome/components/switch/__init__.py +3 -3
  251. esphome/components/text/__init__.py +5 -5
  252. esphome/components/text_sensor/__init__.py +7 -7
  253. esphome/components/time/__init__.py +8 -8
  254. esphome/components/touchscreen/binary_sensor/__init__.py +24 -10
  255. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +3 -2
  256. esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +4 -2
  257. esphome/components/uart/uart_component_host.cpp +6 -2
  258. esphome/components/update/__init__.py +33 -15
  259. esphome/components/update/automation.h +23 -0
  260. esphome/components/update/update_entity.h +3 -1
  261. esphome/components/valve/__init__.py +3 -3
  262. esphome/components/voice_assistant/__init__.py +7 -8
  263. esphome/components/wake_on_lan/wake_on_lan.cpp +2 -0
  264. esphome/components/wake_on_lan/wake_on_lan.h +3 -1
  265. esphome/components/watchdog/__init__.py +1 -0
  266. esphome/components/{http_request → watchdog}/watchdog.cpp +0 -2
  267. esphome/components/{http_request → watchdog}/watchdog.h +0 -2
  268. esphome/components/web_server/server_index_v3.h +3615 -3603
  269. esphome/components/web_server/web_server.cpp +0 -209
  270. esphome/components/web_server/web_server.h +1 -1
  271. esphome/components/web_server/web_server_v1.cpp +217 -0
  272. esphome/components/web_server_base/web_server_base.h +1 -0
  273. esphome/components/wifi/__init__.py +15 -14
  274. esphome/components/wifi/wifi_component.cpp +2 -0
  275. esphome/components/wifi/wifi_component.h +7 -1
  276. esphome/components/wifi/wifi_component_esp32_arduino.cpp +5 -2
  277. esphome/components/wifi/wifi_component_esp8266.cpp +2 -0
  278. esphome/components/wifi/wifi_component_esp_idf.cpp +43 -7
  279. esphome/components/wifi/wifi_component_libretiny.cpp +2 -0
  280. esphome/components/wifi/wifi_component_pico_w.cpp +2 -0
  281. esphome/components/wifi/wpa2_eap.py +6 -7
  282. esphome/components/wifi_info/text_sensor.py +3 -3
  283. esphome/components/wifi_info/wifi_info_text_sensor.cpp +2 -0
  284. esphome/components/wifi_info/wifi_info_text_sensor.h +2 -0
  285. esphome/components/wifi_signal/sensor.py +1 -1
  286. esphome/components/wifi_signal/wifi_signal_sensor.cpp +2 -0
  287. esphome/components/wifi_signal/wifi_signal_sensor.h +2 -1
  288. esphome/components/xiaomi_ble/xiaomi_ble.cpp +20 -3
  289. esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
  290. esphome/components/xiaomi_lywsd02mmc/__init__.py +0 -0
  291. esphome/components/xiaomi_lywsd02mmc/sensor.py +77 -0
  292. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp +73 -0
  293. esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +37 -0
  294. esphome/config.py +17 -19
  295. esphome/config_validation.py +41 -23
  296. esphome/const.py +25 -9
  297. esphome/core/__init__.py +17 -14
  298. esphome/core/application.h +42 -21
  299. esphome/core/automation.h +5 -3
  300. esphome/core/base_automation.h +3 -2
  301. esphome/core/bytebuffer.cpp +134 -0
  302. esphome/core/bytebuffer.h +96 -0
  303. esphome/core/color.h +24 -16
  304. esphome/core/config.py +3 -3
  305. esphome/core/defines.h +14 -1
  306. esphome/core/entity_base.h +2 -2
  307. esphome/core/entity_helpers.py +1 -2
  308. esphome/core/gpio.h +0 -18
  309. esphome/core/helpers.h +1 -1
  310. esphome/core/optional.h +15 -16
  311. esphome/coroutine.py +1 -1
  312. esphome/cpp_generator.py +1 -1
  313. esphome/cpp_helpers.py +3 -5
  314. esphome/dashboard/core.py +3 -3
  315. esphome/dashboard/dashboard.py +3 -3
  316. esphome/dashboard/entries.py +1 -1
  317. esphome/dashboard/util/file.py +1 -1
  318. esphome/dashboard/web_server.py +3 -3
  319. esphome/external_files.py +5 -3
  320. esphome/final_validate.py +2 -2
  321. esphome/git.py +4 -4
  322. esphome/helpers.py +5 -5
  323. esphome/loader.py +15 -10
  324. esphome/mqtt.py +4 -8
  325. esphome/pins.py +6 -6
  326. esphome/platformio_api.py +5 -5
  327. esphome/storage_json.py +2 -1
  328. esphome/types.py +1 -1
  329. esphome/util.py +2 -3
  330. esphome/voluptuous_schema.py +1 -0
  331. esphome/vscode.py +5 -4
  332. esphome/wizard.py +1 -1
  333. esphome/writer.py +7 -7
  334. esphome/yaml_util.py +3 -3
  335. esphome/zeroconf.py +1 -1
  336. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/METADATA +3 -3
  337. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/RECORD +341 -235
  338. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/LICENSE +0 -0
  339. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/WHEEL +0 -0
  340. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/entry_points.txt +0 -0
  341. {esphome-2024.7.3.dist-info → esphome-2024.8.0b1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,400 @@
1
+ import sys
2
+ from typing import Any, Union
3
+
4
+ from esphome import codegen as cg, config_validation as cv
5
+ from esphome.config_validation import Invalid
6
+ from esphome.const import CONF_GROUP, CONF_ID, CONF_STATE, CONF_TYPE
7
+ from esphome.core import ID, TimePeriod
8
+ from esphome.coroutine import FakeAwaitable
9
+ from esphome.cpp_generator import CallExpression, MockObj
10
+
11
+ from ..defines import (
12
+ CONF_DEFAULT,
13
+ CONF_FLEX_ALIGN_CROSS,
14
+ CONF_FLEX_ALIGN_MAIN,
15
+ CONF_FLEX_ALIGN_TRACK,
16
+ CONF_FLEX_FLOW,
17
+ CONF_GRID_COLUMN_ALIGN,
18
+ CONF_GRID_COLUMNS,
19
+ CONF_GRID_ROW_ALIGN,
20
+ CONF_GRID_ROWS,
21
+ CONF_LAYOUT,
22
+ CONF_MAIN,
23
+ CONF_SCROLLBAR_MODE,
24
+ CONF_STYLES,
25
+ CONF_WIDGETS,
26
+ OBJ_FLAGS,
27
+ PARTS,
28
+ STATES,
29
+ TYPE_FLEX,
30
+ TYPE_GRID,
31
+ LValidator,
32
+ join_enums,
33
+ literal,
34
+ )
35
+ from ..helpers import add_lv_use
36
+ from ..lvcode import (
37
+ LvConditional,
38
+ add_line_marks,
39
+ lv,
40
+ lv_add,
41
+ lv_assign,
42
+ lv_expr,
43
+ lv_obj,
44
+ lv_Pvariable,
45
+ )
46
+ from ..schemas import ALL_STYLES, STYLE_REMAP, WIDGET_TYPES
47
+ from ..types import LV_STATE, LvType, WidgetType, lv_coord_t, lv_obj_t, lv_obj_t_ptr
48
+
49
+ EVENT_LAMB = "event_lamb__"
50
+
51
+ theme_widget_map = {}
52
+
53
+
54
+ class LvScrActType(WidgetType):
55
+ """
56
+ A "widget" representing the active screen.
57
+ """
58
+
59
+ def __init__(self):
60
+ super().__init__("lv_scr_act()", lv_obj_t, ())
61
+
62
+ async def to_code(self, w, config: dict):
63
+ return []
64
+
65
+
66
+ class Widget:
67
+ """
68
+ Represents a Widget.
69
+ """
70
+
71
+ widgets_completed = False
72
+
73
+ @staticmethod
74
+ def set_completed():
75
+ Widget.widgets_completed = True
76
+
77
+ def __init__(self, var, wtype: WidgetType, config: dict = None):
78
+ self.var = var
79
+ self.type = wtype
80
+ self.config = config
81
+ self.scale = 1.0
82
+ self.step = 1.0
83
+ self.range_from = -sys.maxsize
84
+ self.range_to = sys.maxsize
85
+ if wtype.is_compound():
86
+ self.obj = MockObj(f"{self.var}->obj")
87
+ else:
88
+ self.obj = var
89
+
90
+ @staticmethod
91
+ def create(name, var, wtype: WidgetType, config: dict = None):
92
+ w = Widget(var, wtype, config)
93
+ if name is not None:
94
+ widget_map[name] = w
95
+ return w
96
+
97
+ def add_state(self, state):
98
+ return lv_obj.add_state(self.obj, literal(state))
99
+
100
+ def clear_state(self, state):
101
+ return lv_obj.clear_state(self.obj, literal(state))
102
+
103
+ def has_state(self, state):
104
+ return (lv_expr.obj_get_state(self.obj) & literal(state)) != 0
105
+
106
+ def is_pressed(self):
107
+ return self.has_state(LV_STATE.PRESSED)
108
+
109
+ def is_checked(self):
110
+ return self.has_state(LV_STATE.CHECKED)
111
+
112
+ def add_flag(self, flag):
113
+ return lv_obj.add_flag(self.obj, literal(flag))
114
+
115
+ def clear_flag(self, flag):
116
+ return lv_obj.clear_flag(self.obj, literal(flag))
117
+
118
+ async def set_property(self, prop, value, animated: bool = None):
119
+ if isinstance(value, dict):
120
+ value = value.get(prop)
121
+ if isinstance(ALL_STYLES.get(prop), LValidator):
122
+ value = await ALL_STYLES[prop].process(value)
123
+ else:
124
+ value = literal(value)
125
+ if value is None:
126
+ return
127
+ if isinstance(value, TimePeriod):
128
+ value = value.total_milliseconds
129
+ if isinstance(value, str):
130
+ value = literal(value)
131
+ if animated is None or self.type.animated is not True:
132
+ lv.call(f"{self.type.lv_name}_set_{prop}", self.obj, value)
133
+ else:
134
+ lv.call(
135
+ f"{self.type.lv_name}_set_{prop}",
136
+ self.obj,
137
+ value,
138
+ literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"),
139
+ )
140
+
141
+ def get_property(self, prop, ltype=None):
142
+ ltype = ltype or self.__type_base()
143
+ return cg.RawExpression(f"lv_{ltype}_get_{prop}({self.obj})")
144
+
145
+ def set_style(self, prop, value, state):
146
+ if value is None:
147
+ return
148
+ lv.call(f"obj_set_style_{prop}", self.obj, value, state)
149
+
150
+ def __type_base(self):
151
+ wtype = self.type.w_type
152
+ base = str(wtype)
153
+ if base.startswith("Lv"):
154
+ return f"{wtype}".removeprefix("Lv").removesuffix("Type").lower()
155
+ return f"{wtype}".removeprefix("lv_").removesuffix("_t")
156
+
157
+ def __str__(self):
158
+ return f"({self.var}, {self.type})"
159
+
160
+ def get_args(self):
161
+ if isinstance(self.type.w_type, LvType):
162
+ return self.type.w_type.args
163
+ return [(lv_obj_t_ptr, "obj")]
164
+
165
+ def get_value(self):
166
+ if isinstance(self.type.w_type, LvType):
167
+ return self.type.w_type.value(self)
168
+ return self.obj
169
+
170
+ def get_number_value(self):
171
+ value = self.type.mock_obj.get_value(self.obj)
172
+ if self.scale == 1.0:
173
+ return value
174
+ return value / float(self.scale)
175
+
176
+ def is_selected(self):
177
+ """
178
+ Overridable property to determine if the widget is selected. Will be None except
179
+ for matrix buttons
180
+ :return:
181
+ """
182
+ return None
183
+
184
+ def get_max(self):
185
+ return self.type.get_max(self.config)
186
+
187
+ def get_min(self):
188
+ return self.type.get_min(self.config)
189
+
190
+ def get_step(self):
191
+ return self.type.get_step(self.config)
192
+
193
+ def get_scale(self):
194
+ return self.type.get_scale(self.config)
195
+
196
+
197
+ # Map of widgets to their config, used for trigger generation
198
+ widget_map: dict[Any, Widget] = {}
199
+
200
+
201
+ def get_widget_generator(wid):
202
+ """
203
+ Used to wait for a widget during code generation.
204
+ :param wid:
205
+ :return:
206
+ """
207
+ while True:
208
+ if obj := widget_map.get(wid):
209
+ return obj
210
+ if Widget.widgets_completed:
211
+ raise Invalid(
212
+ f"Widget {wid} not found, yet all widgets should be defined by now"
213
+ )
214
+ yield
215
+
216
+
217
+ async def get_widget_(wid: Widget):
218
+ if obj := widget_map.get(wid):
219
+ return obj
220
+ return await FakeAwaitable(get_widget_generator(wid))
221
+
222
+
223
+ async def get_widgets(config: Union[dict, list], id: str = CONF_ID) -> list[Widget]:
224
+ if not config:
225
+ return []
226
+ if not isinstance(config, list):
227
+ config = [config]
228
+ return [await get_widget_(c[id]) for c in config if id in c]
229
+
230
+
231
+ def collect_props(config):
232
+ """
233
+ Collect all properties from a configuration
234
+ :param config:
235
+ :return:
236
+ """
237
+ props = {}
238
+ for prop in [*ALL_STYLES, *OBJ_FLAGS, CONF_STYLES, CONF_GROUP]:
239
+ if prop in config:
240
+ props[prop] = config[prop]
241
+ return props
242
+
243
+
244
+ def collect_states(config):
245
+ """
246
+ Collect prperties for each state of a widget
247
+ :param config:
248
+ :return:
249
+ """
250
+ states = {CONF_DEFAULT: collect_props(config)}
251
+ for state in STATES:
252
+ if state in config:
253
+ states[state] = collect_props(config[state])
254
+ return states
255
+
256
+
257
+ def collect_parts(config):
258
+ """
259
+ Collect properties and states for all widget parts
260
+ :param config:
261
+ :return:
262
+ """
263
+ parts = {CONF_MAIN: collect_states(config)}
264
+ for part in PARTS:
265
+ if part in config:
266
+ parts[part] = collect_states(config[part])
267
+ return parts
268
+
269
+
270
+ async def set_obj_properties(w: Widget, config):
271
+ """Generate a list of C++ statements to apply properties to an lv_obj_t"""
272
+ if layout := config.get(CONF_LAYOUT):
273
+ layout_type: str = layout[CONF_TYPE]
274
+ add_lv_use(layout_type)
275
+ lv_obj.set_layout(w.obj, literal(f"LV_LAYOUT_{layout_type.upper()}"))
276
+ if layout_type == TYPE_GRID:
277
+ wid = config[CONF_ID]
278
+ rows = [str(x) for x in layout[CONF_GRID_ROWS]]
279
+ rows = "{" + ",".join(rows) + ", LV_GRID_TEMPLATE_LAST}"
280
+ row_id = ID(f"{wid}_row_dsc", is_declaration=True, type=lv_coord_t)
281
+ row_array = cg.static_const_array(row_id, cg.RawExpression(rows))
282
+ w.set_style("grid_row_dsc_array", row_array, 0)
283
+ columns = [str(x) for x in layout[CONF_GRID_COLUMNS]]
284
+ columns = "{" + ",".join(columns) + ", LV_GRID_TEMPLATE_LAST}"
285
+ column_id = ID(f"{wid}_column_dsc", is_declaration=True, type=lv_coord_t)
286
+ column_array = cg.static_const_array(column_id, cg.RawExpression(columns))
287
+ w.set_style("grid_column_dsc_array", column_array, 0)
288
+ w.set_style(
289
+ CONF_GRID_COLUMN_ALIGN, literal(layout.get(CONF_GRID_COLUMN_ALIGN)), 0
290
+ )
291
+ w.set_style(
292
+ CONF_GRID_ROW_ALIGN, literal(layout.get(CONF_GRID_ROW_ALIGN)), 0
293
+ )
294
+ if layout_type == TYPE_FLEX:
295
+ lv_obj.set_flex_flow(w.obj, literal(layout[CONF_FLEX_FLOW]))
296
+ main = literal(layout[CONF_FLEX_ALIGN_MAIN])
297
+ cross = literal(layout[CONF_FLEX_ALIGN_CROSS])
298
+ track = literal(layout[CONF_FLEX_ALIGN_TRACK])
299
+ lv_obj.set_flex_align(w.obj, main, cross, track)
300
+ parts = collect_parts(config)
301
+ for part, states in parts.items():
302
+ for state, props in states.items():
303
+ lv_state = join_enums((f"LV_STATE_{state}", f"LV_PART_{part}"))
304
+ for style_id in props.get(CONF_STYLES, ()):
305
+ lv_obj.add_style(w.obj, MockObj(style_id), lv_state)
306
+ for prop, value in {
307
+ k: v for k, v in props.items() if k in ALL_STYLES
308
+ }.items():
309
+ if isinstance(ALL_STYLES[prop], LValidator):
310
+ value = await ALL_STYLES[prop].process(value)
311
+ prop_r = STYLE_REMAP.get(prop, prop)
312
+ w.set_style(prop_r, value, lv_state)
313
+ if group := config.get(CONF_GROUP):
314
+ group = await cg.get_variable(group)
315
+ lv.group_add_obj(group, w.obj)
316
+ flag_clr = set()
317
+ flag_set = set()
318
+ props = parts[CONF_MAIN][CONF_DEFAULT]
319
+ for prop, value in {k: v for k, v in props.items() if k in OBJ_FLAGS}.items():
320
+ if value:
321
+ flag_set.add(prop)
322
+ else:
323
+ flag_clr.add(prop)
324
+ if flag_set:
325
+ adds = join_enums(flag_set, "LV_OBJ_FLAG_")
326
+ w.add_flag(adds)
327
+ if flag_clr:
328
+ clrs = join_enums(flag_clr, "LV_OBJ_FLAG_")
329
+ w.clear_flag(clrs)
330
+
331
+ if states := config.get(CONF_STATE):
332
+ adds = set()
333
+ clears = set()
334
+ lambs = {}
335
+ for key, value in states.items():
336
+ if isinstance(value, cv.Lambda):
337
+ lambs[key] = value
338
+ elif value:
339
+ adds.add(key)
340
+ else:
341
+ clears.add(key)
342
+ if adds:
343
+ adds = join_enums(adds, "LV_STATE_")
344
+ w.add_state(adds)
345
+ if clears:
346
+ clears = join_enums(clears, "LV_STATE_")
347
+ w.clear_state(clears)
348
+ for key, value in lambs.items():
349
+ lamb = await cg.process_lambda(value, [], return_type=cg.bool_)
350
+ state = f"LV_STATE_{key.upper()}"
351
+ with LvConditional(f"{lamb}()") as cond:
352
+ w.add_state(state)
353
+ cond.else_()
354
+ w.clear_state(state)
355
+ await w.set_property(CONF_SCROLLBAR_MODE, config)
356
+
357
+
358
+ async def add_widgets(parent: Widget, config: dict):
359
+ """
360
+ Add all widgets to an object
361
+ :param parent: The enclosing obj
362
+ :param config: The configuration
363
+ :return:
364
+ """
365
+ for w in config.get(CONF_WIDGETS, ()):
366
+ w_type, w_cnfig = next(iter(w.items()))
367
+ await widget_to_code(w_cnfig, w_type, parent.obj)
368
+
369
+
370
+ async def widget_to_code(w_cnfig, w_type: WidgetType, parent):
371
+ """
372
+ Converts a Widget definition to C code.
373
+ :param w_cnfig: The widget configuration
374
+ :param w_type: The Widget type
375
+ :param parent: The parent to which the widget should be added
376
+ :return:
377
+ """
378
+ spec: WidgetType = WIDGET_TYPES[w_type]
379
+ creator = spec.obj_creator(parent, w_cnfig)
380
+ add_lv_use(spec.name)
381
+ add_lv_use(*spec.get_uses())
382
+ wid = w_cnfig[CONF_ID]
383
+ add_line_marks(wid)
384
+ if spec.is_compound():
385
+ var = cg.new_Pvariable(wid)
386
+ lv_add(var.set_obj(creator))
387
+ else:
388
+ var = lv_Pvariable(lv_obj_t, wid)
389
+ lv_assign(var, creator)
390
+
391
+ w = Widget.create(wid, var, spec, w_cnfig)
392
+ if theme := theme_widget_map.get(w_type):
393
+ lv_add(CallExpression(theme, w.obj))
394
+ await set_obj_properties(w, w_cnfig)
395
+ await add_widgets(w, w_cnfig)
396
+ await spec.to_code(w, w_cnfig)
397
+
398
+
399
+ lv_scr_act_spec = LvScrActType()
400
+ lv_scr_act = Widget.create(None, literal("lv_scr_act()"), lv_scr_act_spec, {})
@@ -0,0 +1,117 @@
1
+ from esphome import automation
2
+ import esphome.codegen as cg
3
+ import esphome.config_validation as cv
4
+ from esphome.const import CONF_DURATION, CONF_ID
5
+ from esphome.cpp_generator import MockObj
6
+
7
+ from ..automation import action_to_code
8
+ from ..defines import CONF_AUTO_START, CONF_MAIN, CONF_REPEAT_COUNT, CONF_SRC
9
+ from ..helpers import lvgl_components_required
10
+ from ..lv_validation import lv_image, lv_milliseconds
11
+ from ..lvcode import lv, lv_expr
12
+ from ..types import LvType, ObjUpdateAction, void_ptr
13
+ from . import Widget, WidgetType, get_widgets
14
+ from .img import CONF_IMAGE
15
+ from .label import CONF_LABEL
16
+
17
+ CONF_ANIMIMG = "animimg"
18
+ CONF_SRC_LIST_ID = "src_list_id"
19
+
20
+
21
+ def lv_repeat_count(value):
22
+ if isinstance(value, str) and value.lower() in ("forever", "infinite"):
23
+ value = 0xFFFF
24
+ return cv.int_range(min=0, max=0xFFFF)(value)
25
+
26
+
27
+ ANIMIMG_BASE_SCHEMA = cv.Schema(
28
+ {
29
+ cv.Optional(CONF_REPEAT_COUNT, default="forever"): lv_repeat_count,
30
+ cv.Optional(CONF_AUTO_START, default=True): cv.boolean,
31
+ }
32
+ )
33
+ ANIMIMG_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
34
+ {
35
+ cv.Required(CONF_DURATION): lv_milliseconds,
36
+ cv.Required(CONF_SRC): cv.ensure_list(lv_image),
37
+ cv.GenerateID(CONF_SRC_LIST_ID): cv.declare_id(void_ptr),
38
+ }
39
+ )
40
+
41
+ ANIMIMG_MODIFY_SCHEMA = ANIMIMG_BASE_SCHEMA.extend(
42
+ {
43
+ cv.Optional(CONF_DURATION): lv_milliseconds,
44
+ }
45
+ )
46
+
47
+ lv_animimg_t = LvType("lv_animimg_t")
48
+
49
+
50
+ class AnimimgType(WidgetType):
51
+ def __init__(self):
52
+ super().__init__(
53
+ CONF_ANIMIMG,
54
+ lv_animimg_t,
55
+ (CONF_MAIN,),
56
+ ANIMIMG_SCHEMA,
57
+ ANIMIMG_MODIFY_SCHEMA,
58
+ )
59
+
60
+ async def to_code(self, w: Widget, config):
61
+ lvgl_components_required.add(CONF_IMAGE)
62
+ lvgl_components_required.add(CONF_ANIMIMG)
63
+ if CONF_SRC in config:
64
+ for x in config[CONF_SRC]:
65
+ await cg.get_variable(x)
66
+ srcs = [lv_expr.img_from(MockObj(x)) for x in config[CONF_SRC]]
67
+ src_id = cg.static_const_array(config[CONF_SRC_LIST_ID], srcs)
68
+ count = len(config[CONF_SRC])
69
+ lv.animimg_set_src(w.obj, src_id, count)
70
+ lv.animimg_set_repeat_count(w.obj, config[CONF_REPEAT_COUNT])
71
+ lv.animimg_set_duration(w.obj, config[CONF_DURATION])
72
+ if config.get(CONF_AUTO_START):
73
+ lv.animimg_start(w.obj)
74
+
75
+ def get_uses(self):
76
+ return CONF_IMAGE, CONF_LABEL
77
+
78
+
79
+ animimg_spec = AnimimgType()
80
+
81
+
82
+ @automation.register_action(
83
+ "lvgl.animimg.start",
84
+ ObjUpdateAction,
85
+ cv.maybe_simple_value(
86
+ {
87
+ cv.Required(CONF_ID): cv.use_id(lv_animimg_t),
88
+ },
89
+ key=CONF_ID,
90
+ ),
91
+ )
92
+ async def animimg_start(config, action_id, template_arg, args):
93
+ widget = await get_widgets(config)
94
+
95
+ async def do_start(w: Widget):
96
+ lv.animimg_start(w.obj)
97
+
98
+ return await action_to_code(widget, do_start, action_id, template_arg, args)
99
+
100
+
101
+ @automation.register_action(
102
+ "lvgl.animimg.stop",
103
+ ObjUpdateAction,
104
+ cv.maybe_simple_value(
105
+ {
106
+ cv.Required(CONF_ID): cv.use_id(lv_animimg_t),
107
+ },
108
+ key=CONF_ID,
109
+ ),
110
+ )
111
+ async def animimg_stop(config, action_id, template_arg, args):
112
+ widget = await get_widgets(config)
113
+
114
+ async def do_stop(w: Widget):
115
+ lv.animimg_stop(w.obj)
116
+
117
+ return await action_to_code(widget, do_stop, action_id, template_arg, args)
@@ -0,0 +1,78 @@
1
+ import esphome.config_validation as cv
2
+ from esphome.const import (
3
+ CONF_MAX_VALUE,
4
+ CONF_MIN_VALUE,
5
+ CONF_MODE,
6
+ CONF_ROTATION,
7
+ CONF_VALUE,
8
+ )
9
+ from esphome.cpp_types import nullptr
10
+
11
+ from ..defines import (
12
+ ARC_MODES,
13
+ CONF_ADJUSTABLE,
14
+ CONF_CHANGE_RATE,
15
+ CONF_END_ANGLE,
16
+ CONF_INDICATOR,
17
+ CONF_KNOB,
18
+ CONF_MAIN,
19
+ CONF_START_ANGLE,
20
+ literal,
21
+ )
22
+ from ..lv_validation import angle, get_start_value, lv_float
23
+ from ..lvcode import lv, lv_obj
24
+ from ..types import LvNumber, NumberType
25
+ from . import Widget
26
+
27
+ CONF_ARC = "arc"
28
+ ARC_SCHEMA = cv.Schema(
29
+ {
30
+ cv.Optional(CONF_VALUE): lv_float,
31
+ cv.Optional(CONF_MIN_VALUE, default=0): cv.int_,
32
+ cv.Optional(CONF_MAX_VALUE, default=100): cv.int_,
33
+ cv.Optional(CONF_START_ANGLE, default=135): angle,
34
+ cv.Optional(CONF_END_ANGLE, default=45): angle,
35
+ cv.Optional(CONF_ROTATION, default=0.0): angle,
36
+ cv.Optional(CONF_ADJUSTABLE, default=False): bool,
37
+ cv.Optional(CONF_MODE, default="NORMAL"): ARC_MODES.one_of,
38
+ cv.Optional(CONF_CHANGE_RATE, default=720): cv.uint16_t,
39
+ }
40
+ )
41
+
42
+ ARC_MODIFY_SCHEMA = cv.Schema(
43
+ {
44
+ cv.Optional(CONF_VALUE): lv_float,
45
+ }
46
+ )
47
+
48
+
49
+ class ArcType(NumberType):
50
+ def __init__(self):
51
+ super().__init__(
52
+ CONF_ARC,
53
+ LvNumber("lv_arc_t"),
54
+ parts=(CONF_MAIN, CONF_INDICATOR, CONF_KNOB),
55
+ schema=ARC_SCHEMA,
56
+ modify_schema=ARC_MODIFY_SCHEMA,
57
+ )
58
+
59
+ async def to_code(self, w: Widget, config):
60
+ if CONF_MIN_VALUE in config:
61
+ lv.arc_set_range(w.obj, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE])
62
+ lv.arc_set_bg_angles(
63
+ w.obj, config[CONF_START_ANGLE] // 10, config[CONF_END_ANGLE] // 10
64
+ )
65
+ lv.arc_set_rotation(w.obj, config[CONF_ROTATION] // 10)
66
+ lv.arc_set_mode(w.obj, literal(config[CONF_MODE]))
67
+ lv.arc_set_change_rate(w.obj, config[CONF_CHANGE_RATE])
68
+
69
+ if config.get(CONF_ADJUSTABLE) is False:
70
+ lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB"))
71
+ w.clear_flag("LV_OBJ_FLAG_CLICKABLE")
72
+
73
+ value = await get_start_value(config)
74
+ if value is not None:
75
+ lv.arc_set_value(w.obj, value)
76
+
77
+
78
+ arc_spec = ArcType()
@@ -0,0 +1,20 @@
1
+ from esphome.const import CONF_BUTTON
2
+
3
+ from ..defines import CONF_MAIN
4
+ from ..types import LvBoolean, WidgetType
5
+
6
+ lv_button_t = LvBoolean("lv_btn_t")
7
+
8
+
9
+ class ButtonType(WidgetType):
10
+ def __init__(self):
11
+ super().__init__(CONF_BUTTON, lv_button_t, (CONF_MAIN,), lv_name="btn")
12
+
13
+ def get_uses(self):
14
+ return ("btn",)
15
+
16
+ async def to_code(self, w, config):
17
+ return []
18
+
19
+
20
+ button_spec = ButtonType()