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.
- esphome/__main__.py +15 -81
- esphome/automation.py +1 -1
- esphome/codegen.py +53 -53
- esphome/components/ade7953/sensor.py +1 -1
- esphome/components/ade7953_spi/ade7953_spi.cpp +1 -1
- esphome/components/airthings_wave_plus/airthings_wave_plus.cpp +5 -2
- esphome/components/airthings_wave_plus/airthings_wave_plus.h +2 -0
- esphome/components/airthings_wave_plus/sensor.py +12 -0
- esphome/components/alarm_control_panel/__init__.py +75 -66
- esphome/components/apds9306/__init__.py +4 -0
- esphome/components/apds9306/apds9306.cpp +151 -0
- esphome/components/apds9306/apds9306.h +66 -0
- esphome/components/apds9306/sensor.py +95 -0
- esphome/components/api/__init__.py +80 -52
- esphome/components/api/api_connection.cpp +14 -1
- esphome/components/api/api_pb2.cpp +33 -4
- esphome/components/api/api_pb2.h +8 -1
- esphome/components/api/api_server.cpp +10 -0
- esphome/components/api/api_server.h +3 -0
- esphome/components/atm90e32/__init__.py +7 -0
- esphome/components/atm90e32/atm90e32.cpp +68 -16
- esphome/components/atm90e32/atm90e32.h +20 -7
- esphome/components/atm90e32/atm90e32_reg.h +2 -0
- esphome/components/atm90e32/button/__init__.py +43 -0
- esphome/components/atm90e32/button/atm90e32_button.cpp +20 -0
- esphome/components/atm90e32/button/atm90e32_button.h +27 -0
- esphome/components/atm90e32/sensor.py +15 -11
- esphome/components/bedjet/bedjet_codec.h +1 -1
- esphome/components/binary/light/binary_light_output.h +3 -2
- esphome/components/binary_sensor/__init__.py +5 -5
- esphome/components/ble_client/__init__.py +3 -3
- esphome/components/ble_client/output/__init__.py +1 -1
- esphome/components/ble_client/sensor/__init__.py +4 -3
- esphome/components/ble_client/switch/__init__.py +2 -1
- esphome/components/ble_client/text_sensor/__init__.py +4 -3
- esphome/components/ble_presence/binary_sensor.py +3 -3
- esphome/components/ble_rssi/sensor.py +2 -2
- esphome/components/ble_scanner/text_sensor.py +1 -1
- esphome/components/bluetooth_proxy/__init__.py +3 -3
- esphome/components/bme68x_bsec2/__init__.py +196 -0
- esphome/components/bme68x_bsec2/bme68x_bsec2.cpp +523 -0
- esphome/components/bme68x_bsec2/bme68x_bsec2.h +163 -0
- esphome/components/bme68x_bsec2/sensor.py +130 -0
- esphome/components/bme68x_bsec2/text_sensor.py +33 -0
- esphome/components/bme68x_bsec2_i2c/__init__.py +28 -0
- esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.cpp +53 -0
- esphome/components/bme68x_bsec2_i2c/bme68x_bsec2_i2c.h +28 -0
- esphome/components/bmp3xx/sensor.py +1 -1
- esphome/components/button/__init__.py +4 -4
- esphome/components/climate/__init__.py +5 -5
- esphome/components/climate/climate.h +1 -1
- esphome/components/cover/__init__.py +8 -8
- esphome/components/cst226/touchscreen/cst226_touchscreen.cpp +11 -7
- esphome/components/cst226/touchscreen/cst226_touchscreen.h +1 -1
- esphome/components/datetime/__init__.py +11 -13
- esphome/components/demo/demo_sensor.h +3 -2
- esphome/components/display/display.cpp +31 -0
- esphome/components/display/display.h +3 -0
- esphome/components/display_menu_base/__init__.py +14 -13
- esphome/components/ens160/sensor.py +1 -1
- esphome/components/esp32/__init__.py +22 -10
- esphome/components/esp32/boards.py +1 -1
- esphome/components/esp32/gpio.py +12 -13
- esphome/components/esp32/gpio_esp32.py +1 -2
- esphome/components/esp32/gpio_esp32_c2.py +1 -2
- esphome/components/esp32/gpio_esp32_c3.py +1 -5
- esphome/components/esp32/gpio_esp32_c6.py +1 -2
- esphome/components/esp32/gpio_esp32_h2.py +1 -2
- esphome/components/esp32/gpio_esp32_s2.py +1 -2
- esphome/components/esp32/gpio_esp32_s3.py +1 -6
- esphome/components/esp32_ble/__init__.py +20 -3
- esphome/components/esp32_ble/ble.cpp +9 -1
- esphome/components/esp32_ble/ble.h +9 -0
- esphome/components/esp32_ble/ble_advertising.cpp +42 -9
- esphome/components/esp32_ble/ble_advertising.h +21 -1
- esphome/components/esp32_ble_beacon/__init__.py +17 -7
- esphome/components/esp32_ble_beacon/esp32_ble_beacon.cpp +45 -113
- esphome/components/esp32_ble_beacon/esp32_ble_beacon.h +17 -19
- esphome/components/esp32_ble_client/__init__.py +0 -1
- esphome/components/esp32_ble_server/__init__.py +2 -3
- esphome/components/esp32_ble_tracker/__init__.py +2 -2
- esphome/components/esp32_improv/__init__.py +2 -4
- esphome/components/ethernet/__init__.py +17 -17
- esphome/components/ethernet_info/text_sensor.py +2 -2
- esphome/components/event/__init__.py +5 -5
- esphome/components/fan/__init__.py +14 -14
- esphome/components/fan/fan.cpp +2 -2
- esphome/components/fingerprint_grow/fingerprint_grow.cpp +1 -1
- esphome/components/fingerprint_grow/fingerprint_grow.h +1 -1
- esphome/components/graphical_display_menu/__init__.py +11 -8
- esphome/components/haier/haier_base.h +2 -2
- esphome/components/homeassistant/__init__.py +8 -1
- esphome/components/homeassistant/number/__init__.py +33 -0
- esphome/components/homeassistant/number/homeassistant_number.cpp +100 -0
- esphome/components/homeassistant/number/homeassistant_number.h +31 -0
- esphome/components/homeassistant/switch/__init__.py +30 -0
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +59 -0
- esphome/components/homeassistant/switch/homeassistant_switch.h +22 -0
- esphome/components/host/__init__.py +3 -7
- esphome/components/http_request/__init__.py +12 -1
- esphome/components/http_request/http_request_arduino.cpp +2 -2
- esphome/components/http_request/http_request_idf.cpp +11 -2
- esphome/components/http_request/http_request_idf.h +10 -0
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +2 -2
- esphome/components/http_request/update/http_request_update.h +2 -1
- esphome/components/hx711/hx711.cpp +10 -1
- esphome/components/hydreon_rgxx/hydreon_rgxx.cpp +1 -1
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +11 -2
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +2 -0
- esphome/components/ili9xxx/ili9xxx_defines.h +3 -1
- esphome/components/ili9xxx/ili9xxx_display.cpp +9 -22
- esphome/components/ili9xxx/ili9xxx_display.h +5 -7
- esphome/components/ili9xxx/ili9xxx_init.h +4 -4
- esphome/components/improv_base/__init__.py +2 -3
- esphome/components/improv_serial/__init__.py +4 -10
- esphome/components/improv_serial/improv_serial_component.cpp +4 -0
- esphome/components/jsn_sr04t/jsn_sr04t.cpp +18 -1
- esphome/components/jsn_sr04t/jsn_sr04t.h +7 -1
- esphome/components/jsn_sr04t/sensor.py +13 -0
- esphome/components/kalman_combinator/sensor.py +1 -1
- esphome/components/light/__init__.py +16 -15
- esphome/components/light/addressable_light_effect.h +12 -8
- esphome/components/light/automation.h +16 -1
- esphome/components/light/automation.py +21 -0
- esphome/components/light/base_light_effects.h +5 -5
- esphome/components/light/esp_color_correction.h +8 -8
- esphome/components/light/types.py +7 -0
- esphome/components/lock/__init__.py +3 -3
- esphome/components/logger/__init__.py +15 -18
- esphome/components/lvgl/__init__.py +346 -0
- esphome/components/lvgl/automation.py +226 -0
- esphome/components/lvgl/binary_sensor/__init__.py +43 -0
- esphome/components/lvgl/defines.py +508 -0
- esphome/components/lvgl/encoders.py +77 -0
- esphome/components/lvgl/font.cpp +76 -0
- esphome/components/lvgl/helpers.py +49 -0
- esphome/components/lvgl/light/__init__.py +32 -0
- esphome/components/lvgl/light/lvgl_light.h +48 -0
- esphome/components/lvgl/lv_validation.py +303 -0
- esphome/components/lvgl/lvcode.py +349 -0
- esphome/components/lvgl/lvgl_esphome.cpp +407 -0
- esphome/components/lvgl/lvgl_esphome.h +274 -0
- esphome/components/lvgl/lvgl_hal.h +21 -0
- esphome/components/lvgl/number/__init__.py +66 -0
- esphome/components/lvgl/number/lvgl_number.h +34 -0
- esphome/components/lvgl/schemas.py +436 -0
- esphome/components/lvgl/select/__init__.py +55 -0
- esphome/components/lvgl/select/lvgl_select.h +62 -0
- esphome/components/lvgl/sensor/__init__.py +47 -0
- esphome/components/lvgl/styles.py +58 -0
- esphome/components/lvgl/switch/__init__.py +56 -0
- esphome/components/lvgl/switch/lvgl_switch.h +34 -0
- esphome/components/lvgl/text/__init__.py +50 -0
- esphome/components/lvgl/text/lvgl_text.h +34 -0
- esphome/components/lvgl/text_sensor/__init__.py +42 -0
- esphome/components/lvgl/touchscreens.py +45 -0
- esphome/components/lvgl/trigger.py +74 -0
- esphome/components/lvgl/types.py +191 -0
- esphome/components/lvgl/widgets/__init__.py +419 -0
- esphome/components/lvgl/widgets/animimg.py +117 -0
- esphome/components/lvgl/widgets/arc.py +78 -0
- esphome/components/lvgl/widgets/button.py +20 -0
- esphome/components/lvgl/widgets/buttonmatrix.py +275 -0
- esphome/components/lvgl/widgets/checkbox.py +27 -0
- esphome/components/lvgl/widgets/dropdown.py +76 -0
- esphome/components/lvgl/widgets/img.py +85 -0
- esphome/components/lvgl/widgets/keyboard.py +49 -0
- esphome/components/lvgl/widgets/label.py +42 -0
- esphome/components/lvgl/widgets/led.py +29 -0
- esphome/components/lvgl/widgets/line.py +50 -0
- esphome/components/lvgl/widgets/lv_bar.py +55 -0
- esphome/components/lvgl/widgets/meter.py +302 -0
- esphome/components/lvgl/widgets/msgbox.py +134 -0
- esphome/components/lvgl/widgets/obj.py +28 -0
- esphome/components/lvgl/widgets/page.py +113 -0
- esphome/components/lvgl/widgets/roller.py +77 -0
- esphome/components/lvgl/widgets/slider.py +63 -0
- esphome/components/lvgl/widgets/spinbox.py +178 -0
- esphome/components/lvgl/widgets/spinner.py +43 -0
- esphome/components/lvgl/widgets/switch.py +20 -0
- esphome/components/lvgl/widgets/tabview.py +114 -0
- esphome/components/lvgl/widgets/textarea.py +66 -0
- esphome/components/lvgl/widgets/tileview.py +128 -0
- esphome/components/m5stack_8angle/__init__.py +33 -0
- esphome/components/m5stack_8angle/binary_sensor/__init__.py +30 -0
- esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.cpp +17 -0
- esphome/components/m5stack_8angle/binary_sensor/m5stack_8angle_binary_sensor.h +19 -0
- esphome/components/m5stack_8angle/light/__init__.py +31 -0
- esphome/components/m5stack_8angle/light/m5stack_8angle_light.cpp +45 -0
- esphome/components/m5stack_8angle/light/m5stack_8angle_light.h +37 -0
- esphome/components/m5stack_8angle/m5stack_8angle.cpp +74 -0
- esphome/components/m5stack_8angle/m5stack_8angle.h +34 -0
- esphome/components/m5stack_8angle/sensor/__init__.py +66 -0
- esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.cpp +24 -0
- esphome/components/m5stack_8angle/sensor/m5stack_8angle_sensor.h +27 -0
- esphome/components/matrix_keypad/matrix_keypad.cpp +2 -0
- esphome/components/max31856/sensor.py +5 -5
- esphome/components/media_player/__init__.py +3 -5
- esphome/components/media_player/automation.h +31 -27
- esphome/components/micro_wake_word/__init__.py +20 -25
- esphome/components/micro_wake_word/streaming_model.cpp +6 -4
- esphome/components/microphone/microphone.h +4 -1
- esphome/components/mitsubishi/mitsubishi.cpp +7 -1
- esphome/components/modbus_controller/__init__.py +26 -2
- esphome/components/modbus_controller/automation.h +19 -0
- esphome/components/modbus_controller/const.py +1 -0
- esphome/components/modbus_controller/modbus_controller.cpp +8 -0
- esphome/components/modbus_controller/modbus_controller.h +3 -0
- esphome/components/mqtt/__init__.py +20 -9
- esphome/components/mqtt/mqtt_alarm_control_panel.cpp +128 -0
- esphome/components/mqtt/mqtt_alarm_control_panel.h +39 -0
- esphome/components/mqtt/mqtt_backend.h +3 -1
- esphome/components/mqtt/mqtt_backend_esp32.cpp +4 -1
- esphome/components/mqtt/mqtt_backend_esp32.h +3 -1
- esphome/components/mqtt/mqtt_backend_esp8266.h +3 -1
- esphome/components/mqtt/mqtt_backend_libretiny.h +3 -1
- esphome/components/mqtt/mqtt_client.cpp +16 -3
- esphome/components/mqtt/mqtt_client.h +5 -1
- esphome/components/mqtt/mqtt_component.cpp +32 -4
- esphome/components/mqtt/mqtt_const.h +2 -0
- esphome/components/network/__init__.py +15 -12
- esphome/components/network/ip_address.h +3 -0
- esphome/components/network/util.cpp +2 -1
- esphome/components/network/util.h +3 -1
- esphome/components/nextion/base_component.py +5 -8
- esphome/components/number/__init__.py +7 -8
- esphome/components/online_image/__init__.py +167 -0
- esphome/components/online_image/image_decoder.cpp +44 -0
- esphome/components/online_image/image_decoder.h +112 -0
- esphome/components/online_image/online_image.cpp +283 -0
- esphome/components/online_image/online_image.h +195 -0
- esphome/components/online_image/png_image.cpp +68 -0
- esphome/components/online_image/png_image.h +33 -0
- esphome/components/ota/__init__.py +8 -4
- esphome/components/pid/pid_climate.h +2 -0
- esphome/components/pmwcs3/pmwcs3.cpp +31 -30
- esphome/components/remote_base/pronto_protocol.cpp +0 -3
- esphome/components/remote_transmitter/remote_transmitter.h +1 -1
- esphome/components/rgbct/rgbct_light_output.h +3 -2
- esphome/components/rgbw/rgbw_light_output.h +3 -2
- esphome/components/rgbww/rgbww_light_output.h +3 -2
- esphome/components/rp2040_pio_led_strip/led_strip.cpp +31 -5
- esphome/components/rp2040_pio_led_strip/led_strip.h +5 -0
- esphome/components/rtttl/rtttl.cpp +108 -21
- esphome/components/rtttl/rtttl.h +15 -6
- esphome/components/select/__init__.py +7 -7
- esphome/components/sensor/__init__.py +29 -10
- esphome/components/sensor/filter.cpp +8 -0
- esphome/components/sensor/filter.h +9 -0
- esphome/components/sml/sml_parser.cpp +48 -22
- esphome/components/socket/socket.cpp +11 -14
- esphome/components/speaker/__init__.py +14 -5
- esphome/components/speaker/automation.h +10 -0
- esphome/components/speaker/speaker.h +9 -0
- esphome/components/spi/spi.cpp +0 -6
- esphome/components/spi/spi.h +2 -19
- esphome/components/spi_led_strip/spi_led_strip.h +5 -4
- esphome/components/sprinkler/sprinkler.cpp +2 -2
- esphome/components/sprinkler/sprinkler.h +1 -1
- esphome/components/switch/__init__.py +3 -3
- esphome/components/text/__init__.py +5 -5
- esphome/components/text_sensor/__init__.py +7 -7
- esphome/components/time/__init__.py +8 -8
- esphome/components/touchscreen/binary_sensor/__init__.py +24 -10
- esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.cpp +3 -2
- esphome/components/touchscreen/binary_sensor/touchscreen_binary_sensor.h +4 -2
- esphome/components/uart/uart_component_host.cpp +6 -2
- esphome/components/update/__init__.py +33 -15
- esphome/components/update/automation.h +23 -0
- esphome/components/update/update_entity.h +3 -1
- esphome/components/valve/__init__.py +3 -3
- esphome/components/voice_assistant/__init__.py +7 -8
- esphome/components/wake_on_lan/wake_on_lan.cpp +2 -0
- esphome/components/wake_on_lan/wake_on_lan.h +3 -1
- esphome/components/watchdog/__init__.py +1 -0
- esphome/components/{http_request → watchdog}/watchdog.cpp +0 -2
- esphome/components/{http_request → watchdog}/watchdog.h +0 -2
- esphome/components/waveshare_epaper/waveshare_epaper.cpp +5 -5
- esphome/components/web_server/server_index_v3.h +3615 -3603
- esphome/components/web_server/web_server.cpp +0 -209
- esphome/components/web_server/web_server.h +1 -1
- esphome/components/web_server/web_server_v1.cpp +217 -0
- esphome/components/web_server_base/web_server_base.h +1 -0
- esphome/components/wifi/__init__.py +15 -14
- esphome/components/wifi/wifi_component.cpp +2 -0
- esphome/components/wifi/wifi_component.h +7 -1
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +5 -2
- esphome/components/wifi/wifi_component_esp8266.cpp +2 -0
- esphome/components/wifi/wifi_component_esp_idf.cpp +43 -7
- esphome/components/wifi/wifi_component_libretiny.cpp +2 -0
- esphome/components/wifi/wifi_component_pico_w.cpp +2 -0
- esphome/components/wifi/wpa2_eap.py +6 -7
- esphome/components/wifi_info/text_sensor.py +3 -3
- esphome/components/wifi_info/wifi_info_text_sensor.cpp +2 -0
- esphome/components/wifi_info/wifi_info_text_sensor.h +2 -0
- esphome/components/wifi_signal/sensor.py +1 -1
- esphome/components/wifi_signal/wifi_signal_sensor.cpp +2 -0
- esphome/components/wifi_signal/wifi_signal_sensor.h +2 -1
- esphome/components/xiaomi_ble/xiaomi_ble.cpp +20 -3
- esphome/components/xiaomi_ble/xiaomi_ble.h +1 -0
- esphome/components/xiaomi_lywsd02mmc/__init__.py +0 -0
- esphome/components/xiaomi_lywsd02mmc/sensor.py +77 -0
- esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.cpp +73 -0
- esphome/components/xiaomi_lywsd02mmc/xiaomi_lywsd02mmc.h +37 -0
- esphome/config.py +17 -19
- esphome/config_validation.py +55 -23
- esphome/const.py +25 -9
- esphome/core/__init__.py +17 -14
- esphome/core/application.h +42 -21
- esphome/core/automation.h +5 -3
- esphome/core/base_automation.h +3 -2
- esphome/core/bytebuffer.cpp +134 -0
- esphome/core/bytebuffer.h +96 -0
- esphome/core/color.h +24 -16
- esphome/core/config.py +3 -3
- esphome/core/defines.h +14 -1
- esphome/core/entity_base.h +2 -2
- esphome/core/entity_helpers.py +1 -2
- esphome/core/gpio.h +0 -18
- esphome/core/helpers.h +1 -1
- esphome/core/optional.h +15 -16
- esphome/coroutine.py +1 -1
- esphome/cpp_generator.py +1 -1
- esphome/cpp_helpers.py +3 -5
- esphome/dashboard/core.py +3 -3
- esphome/dashboard/dashboard.py +3 -3
- esphome/dashboard/entries.py +1 -1
- esphome/dashboard/util/file.py +1 -1
- esphome/dashboard/web_server.py +3 -3
- esphome/external_files.py +5 -3
- esphome/final_validate.py +2 -2
- esphome/git.py +4 -4
- esphome/helpers.py +5 -5
- esphome/loader.py +15 -10
- esphome/mqtt.py +4 -8
- esphome/pins.py +6 -6
- esphome/platformio_api.py +5 -5
- esphome/storage_json.py +2 -1
- esphome/types.py +1 -1
- esphome/util.py +2 -3
- esphome/voluptuous_schema.py +1 -0
- esphome/vscode.py +5 -4
- esphome/wizard.py +1 -1
- esphome/writer.py +7 -7
- esphome/yaml_util.py +3 -3
- esphome/zeroconf.py +1 -1
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/METADATA +3 -3
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/RECORD +353 -247
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/LICENSE +0 -0
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/WHEEL +0 -0
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/entry_points.txt +0 -0
- {esphome-2024.7.2.dist-info → esphome-2024.8.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,66 @@
|
|
1
|
+
import esphome.codegen as cg
|
2
|
+
from esphome.components import number
|
3
|
+
import esphome.config_validation as cv
|
4
|
+
from esphome.cpp_generator import MockObj
|
5
|
+
|
6
|
+
from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_UPDATE_ON_RELEASE, CONF_WIDGET
|
7
|
+
from ..lv_validation import animated
|
8
|
+
from ..lvcode import (
|
9
|
+
API_EVENT,
|
10
|
+
EVENT_ARG,
|
11
|
+
UPDATE_EVENT,
|
12
|
+
LambdaContext,
|
13
|
+
LvContext,
|
14
|
+
lv,
|
15
|
+
lv_add,
|
16
|
+
)
|
17
|
+
from ..schemas import LVGL_SCHEMA
|
18
|
+
from ..types import LV_EVENT, LvNumber, lvgl_ns
|
19
|
+
from ..widgets import get_widgets
|
20
|
+
|
21
|
+
LVGLNumber = lvgl_ns.class_("LVGLNumber", number.Number)
|
22
|
+
|
23
|
+
CONFIG_SCHEMA = (
|
24
|
+
number.number_schema(LVGLNumber)
|
25
|
+
.extend(LVGL_SCHEMA)
|
26
|
+
.extend(
|
27
|
+
{
|
28
|
+
cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
|
29
|
+
cv.Optional(CONF_ANIMATED, default=True): animated,
|
30
|
+
cv.Optional(CONF_UPDATE_ON_RELEASE, default=False): cv.boolean,
|
31
|
+
}
|
32
|
+
)
|
33
|
+
)
|
34
|
+
|
35
|
+
|
36
|
+
async def to_code(config):
|
37
|
+
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
38
|
+
widget = await get_widgets(config, CONF_WIDGET)
|
39
|
+
widget = widget[0]
|
40
|
+
var = await number.new_number(
|
41
|
+
config,
|
42
|
+
max_value=widget.get_max(),
|
43
|
+
min_value=widget.get_min(),
|
44
|
+
step=widget.get_step(),
|
45
|
+
)
|
46
|
+
|
47
|
+
async with LambdaContext([(cg.float_, "v")]) as control:
|
48
|
+
await widget.set_property(
|
49
|
+
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
50
|
+
)
|
51
|
+
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
52
|
+
async with LambdaContext(EVENT_ARG) as event:
|
53
|
+
event.add(var.publish_state(widget.get_value()))
|
54
|
+
event_code = (
|
55
|
+
LV_EVENT.VALUE_CHANGED
|
56
|
+
if not config[CONF_UPDATE_ON_RELEASE]
|
57
|
+
else LV_EVENT.RELEASED
|
58
|
+
)
|
59
|
+
async with LvContext(paren):
|
60
|
+
lv_add(var.set_control_lambda(await control.get_lambda()))
|
61
|
+
lv_add(
|
62
|
+
paren.add_event_cb(
|
63
|
+
widget.obj, await event.get_lambda(), UPDATE_EVENT, event_code
|
64
|
+
)
|
65
|
+
)
|
66
|
+
lv_add(var.publish_state(widget.get_value()))
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/components/number/number.h"
|
4
|
+
#include "esphome/core/automation.h"
|
5
|
+
#include "esphome/core/component.h"
|
6
|
+
#include "esphome/core/preferences.h"
|
7
|
+
|
8
|
+
namespace esphome {
|
9
|
+
namespace lvgl {
|
10
|
+
|
11
|
+
class LVGLNumber : public number::Number {
|
12
|
+
public:
|
13
|
+
void set_control_lambda(std::function<void(float)> control_lambda) {
|
14
|
+
this->control_lambda_ = control_lambda;
|
15
|
+
if (this->initial_state_.has_value()) {
|
16
|
+
this->control_lambda_(this->initial_state_.value());
|
17
|
+
this->initial_state_.reset();
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
protected:
|
22
|
+
void control(float value) override {
|
23
|
+
if (this->control_lambda_ != nullptr) {
|
24
|
+
this->control_lambda_(value);
|
25
|
+
} else {
|
26
|
+
this->initial_state_ = value;
|
27
|
+
}
|
28
|
+
}
|
29
|
+
std::function<void(float)> control_lambda_{};
|
30
|
+
optional<float> initial_state_{};
|
31
|
+
};
|
32
|
+
|
33
|
+
} // namespace lvgl
|
34
|
+
} // namespace esphome
|
@@ -0,0 +1,436 @@
|
|
1
|
+
from esphome import config_validation as cv
|
2
|
+
from esphome.automation import Trigger, validate_automation
|
3
|
+
from esphome.components.time import RealTimeClock
|
4
|
+
from esphome.const import (
|
5
|
+
CONF_ARGS,
|
6
|
+
CONF_FORMAT,
|
7
|
+
CONF_GROUP,
|
8
|
+
CONF_ID,
|
9
|
+
CONF_ON_VALUE,
|
10
|
+
CONF_STATE,
|
11
|
+
CONF_TEXT,
|
12
|
+
CONF_TIME,
|
13
|
+
CONF_TRIGGER_ID,
|
14
|
+
CONF_TYPE,
|
15
|
+
)
|
16
|
+
from esphome.core import TimePeriod
|
17
|
+
from esphome.schema_extractors import SCHEMA_EXTRACT
|
18
|
+
|
19
|
+
from . import defines as df, lv_validation as lvalid
|
20
|
+
from .defines import CONF_TIME_FORMAT
|
21
|
+
from .helpers import add_lv_use, requires_component, validate_printf
|
22
|
+
from .lv_validation import lv_color, lv_font, lv_image
|
23
|
+
from .lvcode import LvglComponent
|
24
|
+
from .types import (
|
25
|
+
LVEncoderListener,
|
26
|
+
LvType,
|
27
|
+
WidgetType,
|
28
|
+
lv_group_t,
|
29
|
+
lv_obj_t,
|
30
|
+
lv_pseudo_button_t,
|
31
|
+
lv_style_t,
|
32
|
+
)
|
33
|
+
|
34
|
+
# this will be populated later, in __init__.py to avoid circular imports.
|
35
|
+
WIDGET_TYPES: dict = {}
|
36
|
+
|
37
|
+
# A schema for text properties
|
38
|
+
TEXT_SCHEMA = cv.Schema(
|
39
|
+
{
|
40
|
+
cv.Optional(CONF_TEXT): cv.Any(
|
41
|
+
cv.All(
|
42
|
+
cv.Schema(
|
43
|
+
{
|
44
|
+
cv.Required(CONF_FORMAT): cv.string,
|
45
|
+
cv.Optional(CONF_ARGS, default=list): cv.ensure_list(
|
46
|
+
cv.lambda_
|
47
|
+
),
|
48
|
+
},
|
49
|
+
),
|
50
|
+
validate_printf,
|
51
|
+
),
|
52
|
+
cv.Schema(
|
53
|
+
{
|
54
|
+
cv.Required(CONF_TIME_FORMAT): cv.string,
|
55
|
+
cv.GenerateID(CONF_TIME): cv.templatable(cv.use_id(RealTimeClock)),
|
56
|
+
}
|
57
|
+
),
|
58
|
+
cv.templatable(cv.string),
|
59
|
+
)
|
60
|
+
}
|
61
|
+
)
|
62
|
+
|
63
|
+
LIST_ACTION_SCHEMA = cv.ensure_list(
|
64
|
+
cv.maybe_simple_value(
|
65
|
+
{
|
66
|
+
cv.Required(CONF_ID): cv.use_id(lv_pseudo_button_t),
|
67
|
+
},
|
68
|
+
key=CONF_ID,
|
69
|
+
)
|
70
|
+
)
|
71
|
+
|
72
|
+
PRESS_TIME = cv.All(
|
73
|
+
lvalid.lv_milliseconds, cv.Range(max=TimePeriod(milliseconds=65535))
|
74
|
+
)
|
75
|
+
|
76
|
+
ENCODER_SCHEMA = cv.Schema(
|
77
|
+
{
|
78
|
+
cv.GenerateID(): cv.All(
|
79
|
+
cv.declare_id(LVEncoderListener), requires_component("binary_sensor")
|
80
|
+
),
|
81
|
+
cv.Optional(CONF_GROUP): cv.declare_id(lv_group_t),
|
82
|
+
cv.Optional(df.CONF_INITIAL_FOCUS): cv.use_id(lv_obj_t),
|
83
|
+
cv.Optional(df.CONF_LONG_PRESS_TIME, default="400ms"): PRESS_TIME,
|
84
|
+
cv.Optional(df.CONF_LONG_PRESS_REPEAT_TIME, default="100ms"): PRESS_TIME,
|
85
|
+
}
|
86
|
+
)
|
87
|
+
|
88
|
+
# All LVGL styles and their validators
|
89
|
+
STYLE_PROPS = {
|
90
|
+
"align": df.CHILD_ALIGNMENTS.one_of,
|
91
|
+
"arc_opa": lvalid.opacity,
|
92
|
+
"arc_color": lvalid.lv_color,
|
93
|
+
"arc_rounded": lvalid.lv_bool,
|
94
|
+
"arc_width": cv.positive_int,
|
95
|
+
"anim_time": lvalid.lv_milliseconds,
|
96
|
+
"bg_color": lvalid.lv_color,
|
97
|
+
"bg_grad_color": lvalid.lv_color,
|
98
|
+
"bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of,
|
99
|
+
"bg_grad_dir": df.LvConstant("LV_GRAD_DIR_", "NONE", "HOR", "VER").one_of,
|
100
|
+
"bg_grad_stop": lvalid.stop_value,
|
101
|
+
"bg_image_opa": lvalid.opacity,
|
102
|
+
"bg_image_recolor": lvalid.lv_color,
|
103
|
+
"bg_image_recolor_opa": lvalid.opacity,
|
104
|
+
"bg_image_src": lvalid.lv_image,
|
105
|
+
"bg_main_stop": lvalid.stop_value,
|
106
|
+
"bg_opa": lvalid.opacity,
|
107
|
+
"border_color": lvalid.lv_color,
|
108
|
+
"border_opa": lvalid.opacity,
|
109
|
+
"border_post": lvalid.lv_bool,
|
110
|
+
"border_side": df.LvConstant(
|
111
|
+
"LV_BORDER_SIDE_", "NONE", "TOP", "BOTTOM", "LEFT", "RIGHT", "INTERNAL"
|
112
|
+
).several_of,
|
113
|
+
"border_width": cv.positive_int,
|
114
|
+
"clip_corner": lvalid.lv_bool,
|
115
|
+
"color_filter_opa": lvalid.opacity,
|
116
|
+
"height": lvalid.size,
|
117
|
+
"image_recolor": lvalid.lv_color,
|
118
|
+
"image_recolor_opa": lvalid.opacity,
|
119
|
+
"line_width": cv.positive_int,
|
120
|
+
"line_dash_width": cv.positive_int,
|
121
|
+
"line_dash_gap": cv.positive_int,
|
122
|
+
"line_rounded": lvalid.lv_bool,
|
123
|
+
"line_color": lvalid.lv_color,
|
124
|
+
"opa": lvalid.opacity,
|
125
|
+
"opa_layered": lvalid.opacity,
|
126
|
+
"outline_color": lvalid.lv_color,
|
127
|
+
"outline_opa": lvalid.opacity,
|
128
|
+
"outline_pad": lvalid.pixels,
|
129
|
+
"outline_width": lvalid.pixels,
|
130
|
+
"pad_all": lvalid.pixels,
|
131
|
+
"pad_bottom": lvalid.pixels,
|
132
|
+
"pad_left": lvalid.pixels,
|
133
|
+
"pad_right": lvalid.pixels,
|
134
|
+
"pad_top": lvalid.pixels,
|
135
|
+
"shadow_color": lvalid.lv_color,
|
136
|
+
"shadow_ofs_x": cv.int_,
|
137
|
+
"shadow_ofs_y": cv.int_,
|
138
|
+
"shadow_opa": lvalid.opacity,
|
139
|
+
"shadow_spread": cv.int_,
|
140
|
+
"shadow_width": cv.positive_int,
|
141
|
+
"text_align": df.LvConstant(
|
142
|
+
"LV_TEXT_ALIGN_", "LEFT", "CENTER", "RIGHT", "AUTO"
|
143
|
+
).one_of,
|
144
|
+
"text_color": lvalid.lv_color,
|
145
|
+
"text_decor": df.LvConstant(
|
146
|
+
"LV_TEXT_DECOR_", "NONE", "UNDERLINE", "STRIKETHROUGH"
|
147
|
+
).several_of,
|
148
|
+
"text_font": lv_font,
|
149
|
+
"text_letter_space": cv.positive_int,
|
150
|
+
"text_line_space": cv.positive_int,
|
151
|
+
"text_opa": lvalid.opacity,
|
152
|
+
"transform_angle": lvalid.angle,
|
153
|
+
"transform_height": lvalid.pixels_or_percent,
|
154
|
+
"transform_pivot_x": lvalid.pixels_or_percent,
|
155
|
+
"transform_pivot_y": lvalid.pixels_or_percent,
|
156
|
+
"transform_zoom": lvalid.zoom,
|
157
|
+
"translate_x": lvalid.pixels_or_percent,
|
158
|
+
"translate_y": lvalid.pixels_or_percent,
|
159
|
+
"max_height": lvalid.pixels_or_percent,
|
160
|
+
"max_width": lvalid.pixels_or_percent,
|
161
|
+
"min_height": lvalid.pixels_or_percent,
|
162
|
+
"min_width": lvalid.pixels_or_percent,
|
163
|
+
"radius": lvalid.radius,
|
164
|
+
"width": lvalid.size,
|
165
|
+
"x": lvalid.pixels_or_percent,
|
166
|
+
"y": lvalid.pixels_or_percent,
|
167
|
+
}
|
168
|
+
|
169
|
+
STYLE_REMAP = {
|
170
|
+
"bg_image_opa": "bg_img_opa",
|
171
|
+
"bg_image_recolor": "bg_img_recolor",
|
172
|
+
"bg_image_recolor_opa": "bg_img_recolor_opa",
|
173
|
+
"bg_image_src": "bg_img_src",
|
174
|
+
"image_recolor": "img_recolor",
|
175
|
+
"image_recolor_opa": "img_recolor_opa",
|
176
|
+
}
|
177
|
+
|
178
|
+
# Complete object style schema
|
179
|
+
STYLE_SCHEMA = cv.Schema({cv.Optional(k): v for k, v in STYLE_PROPS.items()}).extend(
|
180
|
+
{
|
181
|
+
cv.Optional(df.CONF_STYLES): cv.ensure_list(cv.use_id(lv_style_t)),
|
182
|
+
cv.Optional(df.CONF_SCROLLBAR_MODE): df.LvConstant(
|
183
|
+
"LV_SCROLLBAR_MODE_", "OFF", "ON", "ACTIVE", "AUTO"
|
184
|
+
).one_of,
|
185
|
+
}
|
186
|
+
)
|
187
|
+
|
188
|
+
# Object states. Top level properties apply to MAIN
|
189
|
+
STATE_SCHEMA = cv.Schema(
|
190
|
+
{cv.Optional(state): STYLE_SCHEMA for state in df.STATES}
|
191
|
+
).extend(STYLE_SCHEMA)
|
192
|
+
# Setting object states
|
193
|
+
SET_STATE_SCHEMA = cv.Schema(
|
194
|
+
{cv.Optional(state): lvalid.lv_bool for state in df.STATES}
|
195
|
+
)
|
196
|
+
# Setting object flags
|
197
|
+
FLAG_SCHEMA = cv.Schema({cv.Optional(flag): lvalid.lv_bool for flag in df.OBJ_FLAGS})
|
198
|
+
FLAG_LIST = cv.ensure_list(df.LvConstant("LV_OBJ_FLAG_", *df.OBJ_FLAGS).one_of)
|
199
|
+
|
200
|
+
|
201
|
+
def part_schema(widget_type: WidgetType):
|
202
|
+
"""
|
203
|
+
Generate a schema for the various parts (e.g. main:, indicator:) of a widget type
|
204
|
+
:param widget_type: The type of widget to generate for
|
205
|
+
:return:
|
206
|
+
"""
|
207
|
+
parts = widget_type.parts
|
208
|
+
return cv.Schema({cv.Optional(part): STATE_SCHEMA for part in parts}).extend(
|
209
|
+
STATE_SCHEMA
|
210
|
+
)
|
211
|
+
|
212
|
+
|
213
|
+
def automation_schema(typ: LvType):
|
214
|
+
if typ.has_on_value:
|
215
|
+
events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,)
|
216
|
+
else:
|
217
|
+
events = df.LV_EVENT_TRIGGERS
|
218
|
+
if isinstance(typ, LvType):
|
219
|
+
template = Trigger.template(typ.get_arg_type())
|
220
|
+
else:
|
221
|
+
template = Trigger.template()
|
222
|
+
return {
|
223
|
+
cv.Optional(event): validate_automation(
|
224
|
+
{
|
225
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(template),
|
226
|
+
}
|
227
|
+
)
|
228
|
+
for event in events
|
229
|
+
}
|
230
|
+
|
231
|
+
|
232
|
+
def create_modify_schema(widget_type):
|
233
|
+
return (
|
234
|
+
part_schema(widget_type)
|
235
|
+
.extend(
|
236
|
+
{
|
237
|
+
cv.Required(CONF_ID): cv.ensure_list(
|
238
|
+
cv.maybe_simple_value(
|
239
|
+
{
|
240
|
+
cv.Required(CONF_ID): cv.use_id(widget_type),
|
241
|
+
},
|
242
|
+
key=CONF_ID,
|
243
|
+
)
|
244
|
+
),
|
245
|
+
cv.Optional(CONF_STATE): SET_STATE_SCHEMA,
|
246
|
+
}
|
247
|
+
)
|
248
|
+
.extend(FLAG_SCHEMA)
|
249
|
+
.extend(widget_type.modify_schema)
|
250
|
+
)
|
251
|
+
|
252
|
+
|
253
|
+
def obj_schema(widget_type: WidgetType):
|
254
|
+
"""
|
255
|
+
Create a schema for a widget type itself i.e. no allowance for children
|
256
|
+
:param widget_type:
|
257
|
+
:return:
|
258
|
+
"""
|
259
|
+
return (
|
260
|
+
part_schema(widget_type)
|
261
|
+
.extend(FLAG_SCHEMA)
|
262
|
+
.extend(LAYOUT_SCHEMA)
|
263
|
+
.extend(ALIGN_TO_SCHEMA)
|
264
|
+
.extend(automation_schema(widget_type.w_type))
|
265
|
+
.extend(
|
266
|
+
cv.Schema(
|
267
|
+
{
|
268
|
+
cv.Optional(CONF_STATE): SET_STATE_SCHEMA,
|
269
|
+
cv.Optional(CONF_GROUP): cv.use_id(lv_group_t),
|
270
|
+
}
|
271
|
+
)
|
272
|
+
)
|
273
|
+
)
|
274
|
+
|
275
|
+
|
276
|
+
LAYOUT_SCHEMAS = {}
|
277
|
+
|
278
|
+
ALIGN_TO_SCHEMA = {
|
279
|
+
cv.Optional(df.CONF_ALIGN_TO): cv.Schema(
|
280
|
+
{
|
281
|
+
cv.Required(CONF_ID): cv.use_id(lv_obj_t),
|
282
|
+
cv.Required(df.CONF_ALIGN): df.ALIGN_ALIGNMENTS.one_of,
|
283
|
+
cv.Optional(df.CONF_X, default=0): lvalid.pixels_or_percent,
|
284
|
+
cv.Optional(df.CONF_Y, default=0): lvalid.pixels_or_percent,
|
285
|
+
}
|
286
|
+
)
|
287
|
+
}
|
288
|
+
|
289
|
+
|
290
|
+
def grid_free_space(value):
|
291
|
+
value = cv.Upper(value)
|
292
|
+
if value.startswith("FR(") and value.endswith(")"):
|
293
|
+
value = value.removesuffix(")").removeprefix("FR(")
|
294
|
+
return f"LV_GRID_FR({cv.positive_int(value)})"
|
295
|
+
raise cv.Invalid("must be a size in pixels, CONTENT or FR(nn)")
|
296
|
+
|
297
|
+
|
298
|
+
grid_spec = cv.Any(
|
299
|
+
lvalid.size, df.LvConstant("LV_GRID_", "CONTENT").one_of, grid_free_space
|
300
|
+
)
|
301
|
+
|
302
|
+
cell_alignments = df.LV_CELL_ALIGNMENTS.one_of
|
303
|
+
grid_alignments = df.LV_GRID_ALIGNMENTS.one_of
|
304
|
+
flex_alignments = df.LV_FLEX_ALIGNMENTS.one_of
|
305
|
+
|
306
|
+
LAYOUT_SCHEMA = {
|
307
|
+
cv.Optional(df.CONF_LAYOUT): cv.typed_schema(
|
308
|
+
{
|
309
|
+
df.TYPE_GRID: {
|
310
|
+
cv.Required(df.CONF_GRID_ROWS): [grid_spec],
|
311
|
+
cv.Required(df.CONF_GRID_COLUMNS): [grid_spec],
|
312
|
+
cv.Optional(df.CONF_GRID_COLUMN_ALIGN): grid_alignments,
|
313
|
+
cv.Optional(df.CONF_GRID_ROW_ALIGN): grid_alignments,
|
314
|
+
cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
|
315
|
+
cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
|
316
|
+
},
|
317
|
+
df.TYPE_FLEX: {
|
318
|
+
cv.Optional(
|
319
|
+
df.CONF_FLEX_FLOW, default="row_wrap"
|
320
|
+
): df.FLEX_FLOWS.one_of,
|
321
|
+
cv.Optional(df.CONF_FLEX_ALIGN_MAIN, default="start"): flex_alignments,
|
322
|
+
cv.Optional(df.CONF_FLEX_ALIGN_CROSS, default="start"): flex_alignments,
|
323
|
+
cv.Optional(df.CONF_FLEX_ALIGN_TRACK, default="start"): flex_alignments,
|
324
|
+
cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
|
325
|
+
cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
|
326
|
+
},
|
327
|
+
},
|
328
|
+
lower=True,
|
329
|
+
)
|
330
|
+
}
|
331
|
+
|
332
|
+
GRID_CELL_SCHEMA = {
|
333
|
+
cv.Required(df.CONF_GRID_CELL_ROW_POS): cv.positive_int,
|
334
|
+
cv.Required(df.CONF_GRID_CELL_COLUMN_POS): cv.positive_int,
|
335
|
+
cv.Optional(df.CONF_GRID_CELL_ROW_SPAN, default=1): cv.positive_int,
|
336
|
+
cv.Optional(df.CONF_GRID_CELL_COLUMN_SPAN, default=1): cv.positive_int,
|
337
|
+
cv.Optional(df.CONF_GRID_CELL_X_ALIGN): grid_alignments,
|
338
|
+
cv.Optional(df.CONF_GRID_CELL_Y_ALIGN): grid_alignments,
|
339
|
+
}
|
340
|
+
|
341
|
+
FLEX_OBJ_SCHEMA = {
|
342
|
+
cv.Optional(df.CONF_FLEX_GROW): cv.int_,
|
343
|
+
}
|
344
|
+
|
345
|
+
DISP_BG_SCHEMA = cv.Schema(
|
346
|
+
{
|
347
|
+
cv.Optional(df.CONF_DISP_BG_IMAGE): lv_image,
|
348
|
+
cv.Optional(df.CONF_DISP_BG_COLOR): lv_color,
|
349
|
+
}
|
350
|
+
)
|
351
|
+
|
352
|
+
# A style schema that can include text
|
353
|
+
STYLED_TEXT_SCHEMA = cv.maybe_simple_value(
|
354
|
+
STYLE_SCHEMA.extend(TEXT_SCHEMA), key=CONF_TEXT
|
355
|
+
)
|
356
|
+
|
357
|
+
# For use by platform components
|
358
|
+
LVGL_SCHEMA = cv.Schema(
|
359
|
+
{
|
360
|
+
cv.GenerateID(df.CONF_LVGL_ID): cv.use_id(LvglComponent),
|
361
|
+
}
|
362
|
+
)
|
363
|
+
|
364
|
+
ALL_STYLES = {**STYLE_PROPS, **GRID_CELL_SCHEMA, **FLEX_OBJ_SCHEMA}
|
365
|
+
|
366
|
+
|
367
|
+
def container_validator(schema, widget_type: WidgetType):
|
368
|
+
"""
|
369
|
+
Create a validator for a container given the widget type
|
370
|
+
:param schema: Base schema to extend
|
371
|
+
:param widget_type:
|
372
|
+
:return:
|
373
|
+
"""
|
374
|
+
|
375
|
+
def validator(value):
|
376
|
+
result = schema
|
377
|
+
if w_sch := widget_type.schema:
|
378
|
+
result = result.extend(w_sch)
|
379
|
+
ltype = df.TYPE_NONE
|
380
|
+
if value and (layout := value.get(df.CONF_LAYOUT)):
|
381
|
+
if not isinstance(layout, dict):
|
382
|
+
raise cv.Invalid("Layout value must be a dict")
|
383
|
+
ltype = layout.get(CONF_TYPE)
|
384
|
+
if not ltype:
|
385
|
+
raise (cv.Invalid("Layout schema requires type:"))
|
386
|
+
add_lv_use(ltype)
|
387
|
+
if value == SCHEMA_EXTRACT:
|
388
|
+
return result
|
389
|
+
result = result.extend(LAYOUT_SCHEMAS[ltype.lower()])
|
390
|
+
return result(value)
|
391
|
+
|
392
|
+
return validator
|
393
|
+
|
394
|
+
|
395
|
+
def container_schema(widget_type: WidgetType, extras=None):
|
396
|
+
"""
|
397
|
+
Create a schema for a container widget of a given type. All obj properties are available, plus
|
398
|
+
the extras passed in, plus any defined for the specific widget being specified.
|
399
|
+
:param widget_type: The widget type, e.g. "img"
|
400
|
+
:param extras: Additional options to be made available, e.g. layout properties for children
|
401
|
+
:return: The schema for this type of widget.
|
402
|
+
"""
|
403
|
+
schema = obj_schema(widget_type).extend(
|
404
|
+
{cv.GenerateID(): cv.declare_id(widget_type.w_type)}
|
405
|
+
)
|
406
|
+
if extras:
|
407
|
+
schema = schema.extend(extras)
|
408
|
+
# Delayed evaluation for recursion
|
409
|
+
return container_validator(schema, widget_type)
|
410
|
+
|
411
|
+
|
412
|
+
def widget_schema(widget_type: WidgetType, extras=None):
|
413
|
+
"""
|
414
|
+
Create a schema for a given widget type
|
415
|
+
:param widget_type: The name of the widget
|
416
|
+
:param extras:
|
417
|
+
:return:
|
418
|
+
"""
|
419
|
+
validator = container_schema(widget_type, extras=extras)
|
420
|
+
if required := widget_type.required_component:
|
421
|
+
validator = cv.All(validator, requires_component(required))
|
422
|
+
return cv.Exclusive(widget_type.name, df.CONF_WIDGETS), validator
|
423
|
+
|
424
|
+
|
425
|
+
# All widget schemas must be defined before this is called.
|
426
|
+
|
427
|
+
|
428
|
+
def any_widget_schema(extras=None):
|
429
|
+
"""
|
430
|
+
Generate schemas for all possible LVGL widgets. This is what implements the ability to have a list of any kind of
|
431
|
+
widget under the widgets: key.
|
432
|
+
|
433
|
+
:param extras: Additional schema to be applied to each generated one
|
434
|
+
:return:
|
435
|
+
"""
|
436
|
+
return cv.Any(dict(widget_schema(wt, extras) for wt in WIDGET_TYPES.values()))
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import esphome.codegen as cg
|
2
|
+
from esphome.components import select
|
3
|
+
import esphome.config_validation as cv
|
4
|
+
from esphome.const import CONF_OPTIONS
|
5
|
+
|
6
|
+
from ..defines import CONF_ANIMATED, CONF_LVGL_ID, CONF_WIDGET
|
7
|
+
from ..lvcode import (
|
8
|
+
API_EVENT,
|
9
|
+
EVENT_ARG,
|
10
|
+
UPDATE_EVENT,
|
11
|
+
LambdaContext,
|
12
|
+
LvContext,
|
13
|
+
lv,
|
14
|
+
lv_add,
|
15
|
+
)
|
16
|
+
from ..schemas import LVGL_SCHEMA
|
17
|
+
from ..types import LV_EVENT, LvSelect, lvgl_ns
|
18
|
+
from ..widgets import get_widgets
|
19
|
+
|
20
|
+
LVGLSelect = lvgl_ns.class_("LVGLSelect", select.Select)
|
21
|
+
|
22
|
+
CONFIG_SCHEMA = (
|
23
|
+
select.select_schema(LVGLSelect)
|
24
|
+
.extend(LVGL_SCHEMA)
|
25
|
+
.extend(
|
26
|
+
{
|
27
|
+
cv.Required(CONF_WIDGET): cv.use_id(LvSelect),
|
28
|
+
cv.Optional(CONF_ANIMATED, default=False): cv.boolean,
|
29
|
+
}
|
30
|
+
)
|
31
|
+
)
|
32
|
+
|
33
|
+
|
34
|
+
async def to_code(config):
|
35
|
+
widget = await get_widgets(config, CONF_WIDGET)
|
36
|
+
widget = widget[0]
|
37
|
+
options = widget.config.get(CONF_OPTIONS, [])
|
38
|
+
selector = await select.new_select(config, options=options)
|
39
|
+
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
40
|
+
async with LambdaContext(EVENT_ARG) as pub_ctx:
|
41
|
+
pub_ctx.add(selector.publish_index(widget.get_value()))
|
42
|
+
async with LambdaContext([(cg.uint16, "v")]) as control:
|
43
|
+
await widget.set_property("selected", "v", animated=config[CONF_ANIMATED])
|
44
|
+
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
45
|
+
async with LvContext(paren) as ctx:
|
46
|
+
lv_add(selector.set_control_lambda(await control.get_lambda()))
|
47
|
+
ctx.add(
|
48
|
+
paren.add_event_cb(
|
49
|
+
widget.obj,
|
50
|
+
await pub_ctx.get_lambda(),
|
51
|
+
LV_EVENT.VALUE_CHANGED,
|
52
|
+
UPDATE_EVENT,
|
53
|
+
)
|
54
|
+
)
|
55
|
+
lv_add(selector.publish_index(widget.get_value()))
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "esphome/components/select/select.h"
|
4
|
+
#include "esphome/core/automation.h"
|
5
|
+
#include "esphome/core/component.h"
|
6
|
+
#include "esphome/core/preferences.h"
|
7
|
+
|
8
|
+
namespace esphome {
|
9
|
+
namespace lvgl {
|
10
|
+
|
11
|
+
static std::vector<std::string> split_string(const std::string &str) {
|
12
|
+
std::vector<std::string> strings;
|
13
|
+
auto delimiter = std::string("\n");
|
14
|
+
|
15
|
+
std::string::size_type pos;
|
16
|
+
std::string::size_type prev = 0;
|
17
|
+
while ((pos = str.find(delimiter, prev)) != std::string::npos) {
|
18
|
+
strings.push_back(str.substr(prev, pos - prev));
|
19
|
+
prev = pos + delimiter.size();
|
20
|
+
}
|
21
|
+
|
22
|
+
// To get the last substring (or only, if delimiter is not found)
|
23
|
+
strings.push_back(str.substr(prev));
|
24
|
+
|
25
|
+
return strings;
|
26
|
+
}
|
27
|
+
|
28
|
+
class LVGLSelect : public select::Select {
|
29
|
+
public:
|
30
|
+
void set_control_lambda(std::function<void(size_t)> lambda) {
|
31
|
+
this->control_lambda_ = lambda;
|
32
|
+
if (this->initial_state_.has_value()) {
|
33
|
+
this->control(this->initial_state_.value());
|
34
|
+
this->initial_state_.reset();
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
void publish_index(size_t index) {
|
39
|
+
auto value = this->at(index);
|
40
|
+
if (value)
|
41
|
+
this->publish_state(value.value());
|
42
|
+
}
|
43
|
+
|
44
|
+
void set_options(const char *str) { this->traits.set_options(split_string(str)); }
|
45
|
+
|
46
|
+
protected:
|
47
|
+
void control(const std::string &value) override {
|
48
|
+
if (this->control_lambda_ != nullptr) {
|
49
|
+
auto index = index_of(value);
|
50
|
+
if (index)
|
51
|
+
this->control_lambda_(index.value());
|
52
|
+
} else {
|
53
|
+
this->initial_state_ = value.c_str();
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
std::function<void(size_t)> control_lambda_{};
|
58
|
+
optional<const char *> initial_state_{};
|
59
|
+
};
|
60
|
+
|
61
|
+
} // namespace lvgl
|
62
|
+
} // namespace esphome
|
@@ -0,0 +1,47 @@
|
|
1
|
+
import esphome.codegen as cg
|
2
|
+
from esphome.components.sensor import Sensor, new_sensor, sensor_schema
|
3
|
+
import esphome.config_validation as cv
|
4
|
+
|
5
|
+
from ..defines import CONF_LVGL_ID, CONF_WIDGET
|
6
|
+
from ..lvcode import (
|
7
|
+
API_EVENT,
|
8
|
+
EVENT_ARG,
|
9
|
+
LVGL_COMP_ARG,
|
10
|
+
UPDATE_EVENT,
|
11
|
+
LambdaContext,
|
12
|
+
LvContext,
|
13
|
+
lv_add,
|
14
|
+
)
|
15
|
+
from ..schemas import LVGL_SCHEMA
|
16
|
+
from ..types import LV_EVENT, LvNumber
|
17
|
+
from ..widgets import Widget, get_widgets
|
18
|
+
|
19
|
+
CONFIG_SCHEMA = (
|
20
|
+
sensor_schema(Sensor)
|
21
|
+
.extend(LVGL_SCHEMA)
|
22
|
+
.extend(
|
23
|
+
{
|
24
|
+
cv.Required(CONF_WIDGET): cv.use_id(LvNumber),
|
25
|
+
}
|
26
|
+
)
|
27
|
+
)
|
28
|
+
|
29
|
+
|
30
|
+
async def to_code(config):
|
31
|
+
sensor = await new_sensor(config)
|
32
|
+
paren = await cg.get_variable(config[CONF_LVGL_ID])
|
33
|
+
widget = await get_widgets(config, CONF_WIDGET)
|
34
|
+
widget = widget[0]
|
35
|
+
assert isinstance(widget, Widget)
|
36
|
+
async with LambdaContext(EVENT_ARG) as lamb:
|
37
|
+
lv_add(sensor.publish_state(widget.get_value()))
|
38
|
+
async with LvContext(paren, LVGL_COMP_ARG):
|
39
|
+
lv_add(
|
40
|
+
paren.add_event_cb(
|
41
|
+
widget.obj,
|
42
|
+
await lamb.get_lambda(),
|
43
|
+
LV_EVENT.VALUE_CHANGED,
|
44
|
+
API_EVENT,
|
45
|
+
UPDATE_EVENT,
|
46
|
+
)
|
47
|
+
)
|