esphome 2024.10.3__py3-none-any.whl → 2024.11.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.
- esphome/__main__.py +22 -4
- esphome/automation.py +29 -2
- esphome/components/animation/__init__.py +5 -8
- esphome/components/animation/animation.cpp +1 -1
- esphome/components/audio/__init__.py +9 -0
- esphome/components/audio/audio.h +21 -0
- esphome/components/axs15231/__init__.py +6 -0
- esphome/components/axs15231/touchscreen/__init__.py +36 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.cpp +64 -0
- esphome/components/axs15231/touchscreen/axs15231_touchscreen.h +27 -0
- esphome/components/bme68x_bsec2/__init__.py +1 -1
- esphome/components/bytebuffer/__init__.py +5 -0
- esphome/components/bytebuffer/bytebuffer.h +421 -0
- esphome/components/climate/__init__.py +14 -13
- esphome/components/datetime/__init__.py +3 -3
- esphome/components/debug/debug_esp32.cpp +16 -8
- esphome/components/dfplayer/dfplayer.cpp +132 -6
- esphome/components/dfplayer/dfplayer.h +19 -53
- esphome/components/display/display.cpp +142 -0
- esphome/components/display/display.h +7 -0
- esphome/components/es8311/__init__.py +0 -0
- esphome/components/es8311/audio_dac.py +70 -0
- esphome/components/es8311/es8311.cpp +227 -0
- esphome/components/es8311/es8311.h +135 -0
- esphome/components/es8311/es8311_const.h +195 -0
- esphome/components/esp32/boards.py +199 -1
- esphome/components/esp32/gpio.py +3 -1
- esphome/components/esp32_ble/const_esp32c6.h +7 -0
- esphome/components/esp32_ble_client/ble_client_base.h +1 -1
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +2 -1
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +2 -2
- esphome/components/esp32_rmt_led_strip/led_strip.h +2 -0
- esphome/components/esp32_rmt_led_strip/light.py +3 -1
- esphome/components/esp8266/gpio.py +7 -5
- esphome/components/ethernet/__init__.py +55 -1
- esphome/components/ethernet/ethernet_component.cpp +14 -1
- esphome/components/ethernet/ethernet_component.h +7 -1
- esphome/components/font/__init__.py +213 -108
- esphome/components/gp8403/output/__init__.py +1 -1
- esphome/components/host/gpio.py +6 -4
- esphome/components/http_request/__init__.py +12 -0
- esphome/components/http_request/http_request.h +65 -3
- esphome/components/http_request/http_request_arduino.cpp +2 -3
- esphome/components/http_request/http_request_idf.cpp +6 -14
- esphome/components/http_request/ota/ota_http_request.cpp +1 -1
- esphome/components/http_request/update/http_request_update.cpp +1 -1
- esphome/components/i2c_device/__init__.py +26 -0
- esphome/components/i2c_device/i2c_device.cpp +17 -0
- esphome/components/i2c_device/i2c_device.h +18 -0
- esphome/components/i2s_audio/__init__.py +1 -3
- esphome/components/i2s_audio/speaker/__init__.py +12 -4
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +432 -197
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +91 -32
- esphome/components/ili9xxx/display.py +5 -1
- esphome/components/image/__init__.py +5 -8
- esphome/components/image/image.cpp +14 -14
- esphome/components/image/image.h +20 -24
- esphome/components/internal_temperature/internal_temperature.cpp +51 -2
- esphome/components/internal_temperature/internal_temperature.h +1 -0
- esphome/components/libretiny/gpio.py +4 -2
- esphome/components/light/__init__.py +32 -1
- esphome/components/light/automation.py +39 -32
- esphome/components/light/effects.py +36 -36
- esphome/components/light/light_state.cpp +6 -16
- esphome/components/light/light_state.h +34 -0
- esphome/components/light/types.py +3 -1
- esphome/components/logger/logger_esp32.cpp +15 -0
- esphome/components/lvgl/__init__.py +202 -95
- esphome/components/lvgl/automation.py +42 -40
- esphome/components/lvgl/binary_sensor/__init__.py +8 -15
- esphome/components/lvgl/defines.py +14 -8
- esphome/components/lvgl/encoders.py +11 -8
- esphome/components/lvgl/keypads.py +77 -0
- esphome/components/lvgl/light/__init__.py +6 -8
- esphome/components/lvgl/lv_validation.py +2 -4
- esphome/components/lvgl/lvcode.py +3 -9
- esphome/components/lvgl/lvgl_esphome.cpp +210 -89
- esphome/components/lvgl/lvgl_esphome.h +113 -30
- esphome/components/lvgl/lvgl_proxy.h +17 -0
- esphome/components/lvgl/number/__init__.py +10 -15
- esphome/components/lvgl/schemas.py +4 -2
- esphome/components/lvgl/select/__init__.py +12 -37
- esphome/components/lvgl/select/lvgl_select.h +27 -33
- esphome/components/lvgl/sensor/__init__.py +8 -14
- esphome/components/lvgl/styles.py +3 -4
- esphome/components/lvgl/switch/__init__.py +8 -13
- esphome/components/lvgl/text/__init__.py +5 -6
- esphome/components/lvgl/text_sensor/__init__.py +15 -15
- esphome/components/lvgl/touchscreens.py +2 -3
- esphome/components/lvgl/trigger.py +7 -9
- esphome/components/lvgl/types.py +9 -3
- esphome/components/lvgl/widgets/__init__.py +32 -21
- esphome/components/lvgl/widgets/dropdown.py +22 -10
- esphome/components/lvgl/widgets/msgbox.py +6 -5
- esphome/components/lvgl/widgets/obj.py +4 -2
- esphome/components/lvgl/widgets/page.py +3 -2
- esphome/components/lvgl/widgets/qrcode.py +54 -0
- esphome/components/lvgl/widgets/roller.py +21 -14
- esphome/components/lvgl/widgets/tileview.py +2 -1
- esphome/components/max17043/__init__.py +1 -0
- esphome/components/max17043/automation.h +20 -0
- esphome/components/max17043/max17043.cpp +98 -0
- esphome/components/max17043/max17043.h +29 -0
- esphome/components/max17043/sensor.py +77 -0
- esphome/components/media_player/__init__.py +11 -0
- esphome/components/media_player/automation.h +10 -0
- esphome/components/media_player/media_player.cpp +4 -0
- esphome/components/midea/air_conditioner.cpp +17 -1
- esphome/components/mlx90393/sensor.py +1 -1
- esphome/components/modbus_controller/__init__.py +31 -1
- esphome/components/modbus_controller/automation.h +16 -0
- esphome/components/modbus_controller/const.py +2 -0
- esphome/components/modbus_controller/modbus_controller.cpp +14 -2
- esphome/components/modbus_controller/modbus_controller.h +9 -0
- esphome/components/mopeka_pro_check/mopeka_pro_check.cpp +40 -21
- esphome/components/mopeka_pro_check/mopeka_pro_check.h +9 -2
- esphome/components/mopeka_pro_check/sensor.py +41 -0
- esphome/components/mqtt/__init__.py +36 -0
- esphome/components/mqtt/mqtt_client.cpp +27 -3
- esphome/components/mqtt/mqtt_client.h +27 -2
- esphome/components/mqtt/mqtt_climate.cpp +4 -2
- esphome/components/mqtt/mqtt_component.cpp +6 -0
- esphome/components/mqtt/mqtt_component.h +4 -0
- esphome/components/mqtt/mqtt_const.h +6 -0
- esphome/components/online_image/online_image.cpp +2 -8
- esphome/components/online_image/online_image.h +2 -6
- esphome/components/opentherm/__init__.py +35 -9
- esphome/components/opentherm/binary_sensor/__init__.py +33 -0
- esphome/components/opentherm/const.py +11 -0
- esphome/components/opentherm/generate.py +142 -0
- esphome/components/opentherm/hub.cpp +130 -24
- esphome/components/opentherm/hub.h +62 -9
- esphome/components/opentherm/input.h +18 -0
- esphome/components/opentherm/input.py +51 -0
- esphome/components/opentherm/number/__init__.py +74 -0
- esphome/components/opentherm/number/number.cpp +40 -0
- esphome/components/opentherm/number/number.h +31 -0
- esphome/components/opentherm/opentherm.cpp +30 -0
- esphome/components/opentherm/opentherm.h +34 -2
- esphome/components/opentherm/opentherm_macros.h +151 -0
- esphome/components/opentherm/output/__init__.py +47 -0
- esphome/components/opentherm/output/output.cpp +18 -0
- esphome/components/opentherm/output/output.h +33 -0
- esphome/components/opentherm/schema.py +814 -0
- esphome/components/opentherm/sensor/__init__.py +51 -0
- esphome/components/opentherm/switch/__init__.py +43 -0
- esphome/components/opentherm/switch/switch.cpp +28 -0
- esphome/components/opentherm/switch/switch.h +20 -0
- esphome/components/opentherm/validate.py +31 -0
- esphome/components/pcd8544/display.py +8 -4
- esphome/components/prometheus/prometheus_handler.cpp +176 -14
- esphome/components/prometheus/prometheus_handler.h +25 -7
- esphome/components/qspi_amoled/display.py +1 -141
- esphome/components/qspi_dbi/display.py +185 -0
- esphome/components/qspi_dbi/models.py +64 -0
- esphome/components/{qspi_amoled/qspi_amoled.cpp → qspi_dbi/qspi_dbi.cpp} +95 -46
- esphome/components/{qspi_amoled/qspi_amoled.h → qspi_dbi/qspi_dbi.h} +26 -15
- esphome/components/rp2040/__init__.py +6 -3
- esphome/components/rp2040/gpio.py +5 -3
- esphome/components/rtttl/rtttl.cpp +4 -1
- esphome/components/rtttl/rtttl.h +1 -0
- esphome/components/sdl/sdl_esphome.cpp +22 -5
- esphome/components/sdl/sdl_esphome.h +1 -0
- esphome/components/sensor/__init__.py +18 -8
- esphome/components/sensor/filter.cpp +19 -18
- esphome/components/sensor/filter.h +9 -10
- esphome/components/sgp4x/sgp4x.cpp +40 -74
- esphome/components/sgp4x/sgp4x.h +5 -3
- esphome/components/speaker/__init__.py +51 -5
- esphome/components/speaker/automation.h +25 -0
- esphome/components/speaker/speaker.h +72 -1
- esphome/components/spi/__init__.py +15 -14
- esphome/components/spi_device/__init__.py +4 -15
- esphome/components/ssd1306_spi/display.py +6 -2
- esphome/components/ssd1322_spi/display.py +6 -2
- esphome/components/ssd1325_spi/display.py +6 -2
- esphome/components/ssd1327_spi/display.py +6 -2
- esphome/components/ssd1331_spi/display.py +6 -2
- esphome/components/ssd1351_spi/display.py +6 -2
- esphome/components/st7567_spi/display.py +6 -2
- esphome/components/st7701s/display.py +5 -1
- esphome/components/st7735/display.py +10 -5
- esphome/components/st7789v/display.py +12 -7
- esphome/components/statsd/statsd.cpp +2 -0
- esphome/components/statsd/statsd.h +2 -0
- esphome/components/sun/sun.h +3 -0
- esphome/components/tc74/__init__.py +1 -0
- esphome/components/tc74/sensor.py +32 -0
- esphome/components/tc74/tc74.cpp +68 -0
- esphome/components/tc74/tc74.h +28 -0
- esphome/components/touchscreen/__init__.py +41 -50
- esphome/components/touchscreen/touchscreen.h +4 -8
- esphome/components/udp/udp_component.cpp +6 -3
- esphome/components/udp/udp_component.h +4 -2
- esphome/components/waveshare_epaper/display.py +6 -2
- esphome/components/web_server/web_server.cpp +22 -0
- esphome/components/web_server/web_server.h +3 -0
- esphome/components/weikai/weikai.h +2 -2
- esphome/components/wifi/wifi_component.cpp +2 -2
- esphome/components/wifi/wifi_component_esp32_arduino.cpp +4 -4
- esphome/components/wifi/wifi_component_esp8266.cpp +4 -4
- esphome/components/wifi/wifi_component_esp_idf.cpp +2 -2
- esphome/components/xpt2046/touchscreen/__init__.py +7 -32
- esphome/config_validation.py +3 -1
- esphome/const.py +8 -1
- esphome/core/defines.h +8 -2
- esphome/core/helpers.cpp +32 -17
- esphome/core/helpers.h +32 -16
- esphome/core/ring_buffer.cpp +2 -2
- esphome/core/ring_buffer.h +2 -2
- esphome/dashboard/core.py +25 -0
- esphome/dashboard/status/mdns.py +3 -4
- esphome/dashboard/web_server.py +54 -19
- esphome/espota2.py +36 -35
- esphome/helpers.py +68 -16
- esphome/mqtt.py +9 -2
- esphome/storage_json.py +4 -0
- esphome/writer.py +7 -18
- esphome/zeroconf.py +8 -6
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/METADATA +7 -5
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/RECORD +226 -180
- esphome/core/bytebuffer.cpp +0 -167
- esphome/core/bytebuffer.h +0 -144
- /esphome/components/{qspi_amoled → qspi_dbi}/__init__.py +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/LICENSE +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/WHEEL +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/entry_points.txt +0 -0
- {esphome-2024.10.3.dist-info → esphome-2024.11.0b1.dist-info}/top_level.txt +0 -0
@@ -1,59 +1,59 @@
|
|
1
|
-
from esphome
|
1
|
+
from esphome import automation
|
2
2
|
import esphome.codegen as cg
|
3
3
|
import esphome.config_validation as cv
|
4
|
-
from esphome import automation
|
5
|
-
|
6
4
|
from esphome.const import (
|
7
|
-
|
8
|
-
|
9
|
-
CONF_UPDATE_INTERVAL,
|
10
|
-
CONF_TRANSITION_LENGTH,
|
11
|
-
CONF_COLORS,
|
12
|
-
CONF_STATE,
|
13
|
-
CONF_DURATION,
|
5
|
+
CONF_ALPHA,
|
6
|
+
CONF_BLUE,
|
14
7
|
CONF_BRIGHTNESS,
|
15
|
-
|
8
|
+
CONF_COLD_WHITE,
|
16
9
|
CONF_COLOR_BRIGHTNESS,
|
17
|
-
|
18
|
-
CONF_GREEN,
|
19
|
-
CONF_BLUE,
|
20
|
-
CONF_WHITE,
|
10
|
+
CONF_COLOR_MODE,
|
21
11
|
CONF_COLOR_TEMPERATURE,
|
22
|
-
|
23
|
-
|
24
|
-
|
12
|
+
CONF_COLORS,
|
13
|
+
CONF_DURATION,
|
14
|
+
CONF_GREEN,
|
25
15
|
CONF_INTENSITY,
|
26
|
-
|
27
|
-
|
16
|
+
CONF_LAMBDA,
|
17
|
+
CONF_MAX_BRIGHTNESS,
|
18
|
+
CONF_MIN_BRIGHTNESS,
|
19
|
+
CONF_NAME,
|
28
20
|
CONF_NUM_LEDS,
|
29
21
|
CONF_RANDOM,
|
22
|
+
CONF_RED,
|
30
23
|
CONF_SEQUENCE,
|
31
|
-
|
32
|
-
|
24
|
+
CONF_SPEED,
|
25
|
+
CONF_STATE,
|
26
|
+
CONF_TRANSITION_LENGTH,
|
27
|
+
CONF_UPDATE_INTERVAL,
|
28
|
+
CONF_WARM_WHITE,
|
29
|
+
CONF_WHITE,
|
30
|
+
CONF_WIDTH,
|
33
31
|
)
|
32
|
+
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
34
33
|
from esphome.util import Registry
|
34
|
+
|
35
35
|
from .types import (
|
36
|
-
ColorMode,
|
37
36
|
COLOR_MODES,
|
38
|
-
LambdaLightEffect,
|
39
|
-
PulseLightEffect,
|
40
|
-
RandomLightEffect,
|
41
|
-
StrobeLightEffect,
|
42
|
-
StrobeLightEffectColor,
|
43
|
-
LightColorValues,
|
44
|
-
AddressableLightRef,
|
45
|
-
AddressableLambdaLightEffect,
|
46
|
-
FlickerLightEffect,
|
47
|
-
AddressableRainbowLightEffect,
|
48
37
|
AddressableColorWipeEffect,
|
49
38
|
AddressableColorWipeEffectColor,
|
50
|
-
AddressableScanEffect,
|
51
|
-
AddressableTwinkleEffect,
|
52
|
-
AddressableRandomTwinkleEffect,
|
53
39
|
AddressableFireworksEffect,
|
54
40
|
AddressableFlickerEffect,
|
41
|
+
AddressableLambdaLightEffect,
|
42
|
+
AddressableLightRef,
|
43
|
+
AddressableRainbowLightEffect,
|
44
|
+
AddressableRandomTwinkleEffect,
|
45
|
+
AddressableScanEffect,
|
46
|
+
AddressableTwinkleEffect,
|
55
47
|
AutomationLightEffect,
|
56
48
|
Color,
|
49
|
+
ColorMode,
|
50
|
+
FlickerLightEffect,
|
51
|
+
LambdaLightEffect,
|
52
|
+
LightColorValues,
|
53
|
+
PulseLightEffect,
|
54
|
+
RandomLightEffect,
|
55
|
+
StrobeLightEffect,
|
56
|
+
StrobeLightEffectColor,
|
57
57
|
)
|
58
58
|
|
59
59
|
CONF_ADD_LED_INTERVAL = "add_led_interval"
|
@@ -1,6 +1,7 @@
|
|
1
1
|
#include "esphome/core/log.h"
|
2
|
-
|
2
|
+
|
3
3
|
#include "light_output.h"
|
4
|
+
#include "light_state.h"
|
4
5
|
#include "transformers.h"
|
5
6
|
|
6
7
|
namespace esphome {
|
@@ -16,21 +17,6 @@ LightCall LightState::turn_off() { return this->make_call().set_state(false); }
|
|
16
17
|
LightCall LightState::toggle() { return this->make_call().set_state(!this->remote_values.is_on()); }
|
17
18
|
LightCall LightState::make_call() { return LightCall(this); }
|
18
19
|
|
19
|
-
struct LightStateRTCState {
|
20
|
-
ColorMode color_mode{ColorMode::UNKNOWN};
|
21
|
-
bool state{false};
|
22
|
-
float brightness{1.0f};
|
23
|
-
float color_brightness{1.0f};
|
24
|
-
float red{1.0f};
|
25
|
-
float green{1.0f};
|
26
|
-
float blue{1.0f};
|
27
|
-
float white{1.0f};
|
28
|
-
float color_temp{1.0f};
|
29
|
-
float cold_white{1.0f};
|
30
|
-
float warm_white{1.0f};
|
31
|
-
uint32_t effect{0};
|
32
|
-
};
|
33
|
-
|
34
20
|
void LightState::setup() {
|
35
21
|
ESP_LOGCONFIG(TAG, "Setting up light '%s'...", this->get_name().c_str());
|
36
22
|
|
@@ -48,6 +34,9 @@ void LightState::setup() {
|
|
48
34
|
|
49
35
|
auto call = this->make_call();
|
50
36
|
LightStateRTCState recovered{};
|
37
|
+
if (this->initial_state_.has_value()) {
|
38
|
+
recovered = *this->initial_state_;
|
39
|
+
}
|
51
40
|
switch (this->restore_mode_) {
|
52
41
|
case LIGHT_RESTORE_DEFAULT_OFF:
|
53
42
|
case LIGHT_RESTORE_DEFAULT_ON:
|
@@ -175,6 +164,7 @@ void LightState::set_flash_transition_length(uint32_t flash_transition_length) {
|
|
175
164
|
uint32_t LightState::get_flash_transition_length() const { return this->flash_transition_length_; }
|
176
165
|
void LightState::set_gamma_correct(float gamma_correct) { this->gamma_correct_ = gamma_correct; }
|
177
166
|
void LightState::set_restore_mode(LightRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
167
|
+
void LightState::set_initial_state(const LightStateRTCState &initial_state) { this->initial_state_ = initial_state; }
|
178
168
|
bool LightState::supports_effects() { return !this->effects_.empty(); }
|
179
169
|
const std::vector<LightEffect *> &LightState::get_effects() const { return this->effects_; }
|
180
170
|
void LightState::add_effects(const std::vector<LightEffect *> &effects) {
|
@@ -28,6 +28,35 @@ enum LightRestoreMode {
|
|
28
28
|
LIGHT_RESTORE_AND_ON,
|
29
29
|
};
|
30
30
|
|
31
|
+
struct LightStateRTCState {
|
32
|
+
LightStateRTCState(ColorMode color_mode, bool state, float brightness, float color_brightness, float red, float green,
|
33
|
+
float blue, float white, float color_temp, float cold_white, float warm_white)
|
34
|
+
: color_mode(color_mode),
|
35
|
+
state(state),
|
36
|
+
brightness(brightness),
|
37
|
+
color_brightness(color_brightness),
|
38
|
+
red(red),
|
39
|
+
green(green),
|
40
|
+
blue(blue),
|
41
|
+
white(white),
|
42
|
+
color_temp(color_temp),
|
43
|
+
cold_white(cold_white),
|
44
|
+
warm_white(warm_white) {}
|
45
|
+
LightStateRTCState() = default;
|
46
|
+
ColorMode color_mode{ColorMode::UNKNOWN};
|
47
|
+
bool state{false};
|
48
|
+
float brightness{1.0f};
|
49
|
+
float color_brightness{1.0f};
|
50
|
+
float red{1.0f};
|
51
|
+
float green{1.0f};
|
52
|
+
float blue{1.0f};
|
53
|
+
float white{1.0f};
|
54
|
+
float color_temp{1.0f};
|
55
|
+
float cold_white{1.0f};
|
56
|
+
float warm_white{1.0f};
|
57
|
+
uint32_t effect{0};
|
58
|
+
};
|
59
|
+
|
31
60
|
/** This class represents the communication layer between the front-end MQTT layer and the
|
32
61
|
* hardware output layer.
|
33
62
|
*/
|
@@ -116,6 +145,9 @@ class LightState : public EntityBase, public Component {
|
|
116
145
|
/// Set the restore mode of this light
|
117
146
|
void set_restore_mode(LightRestoreMode restore_mode);
|
118
147
|
|
148
|
+
/// Set the initial state of this light
|
149
|
+
void set_initial_state(const LightStateRTCState &initial_state);
|
150
|
+
|
119
151
|
/// Return whether the light has any effects that meet the trait requirements.
|
120
152
|
bool supports_effects();
|
121
153
|
|
@@ -212,6 +244,8 @@ class LightState : public EntityBase, public Component {
|
|
212
244
|
float gamma_correct_{};
|
213
245
|
/// Restore mode of the light.
|
214
246
|
LightRestoreMode restore_mode_;
|
247
|
+
/// Initial state of the light.
|
248
|
+
optional<LightStateRTCState> initial_state_{};
|
215
249
|
/// List of effects for this light.
|
216
250
|
std::vector<LightEffect *> effects_;
|
217
251
|
|
@@ -1,5 +1,5 @@
|
|
1
|
-
import esphome.codegen as cg
|
2
1
|
from esphome import automation
|
2
|
+
import esphome.codegen as cg
|
3
3
|
|
4
4
|
# Base
|
5
5
|
light_ns = cg.esphome_ns.namespace("light")
|
@@ -12,6 +12,8 @@ AddressableLightRef = AddressableLight.operator("ref")
|
|
12
12
|
Color = cg.esphome_ns.class_("Color")
|
13
13
|
LightColorValues = light_ns.class_("LightColorValues")
|
14
14
|
|
15
|
+
LightStateRTCState = light_ns.struct("LightStateRTCState")
|
16
|
+
|
15
17
|
# Color modes
|
16
18
|
ColorMode = light_ns.enum("ColorMode", is_class=True)
|
17
19
|
COLOR_MODES = {
|
@@ -10,8 +10,12 @@
|
|
10
10
|
|
11
11
|
#ifdef USE_LOGGER_USB_SERIAL_JTAG
|
12
12
|
#include <driver/usb_serial_jtag.h>
|
13
|
+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
|
13
14
|
#include <esp_vfs_dev.h>
|
14
15
|
#include <esp_vfs_usb_serial_jtag.h>
|
16
|
+
#else
|
17
|
+
#include <driver/usb_serial_jtag_vfs.h>
|
18
|
+
#endif
|
15
19
|
#endif
|
16
20
|
|
17
21
|
#include "freertos/FreeRTOS.h"
|
@@ -36,10 +40,17 @@ static const char *const TAG = "logger";
|
|
36
40
|
static void init_usb_serial_jtag_() {
|
37
41
|
setvbuf(stdin, NULL, _IONBF, 0); // Disable buffering on stdin
|
38
42
|
|
43
|
+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
|
39
44
|
// Minicom, screen, idf_monitor send CR when ENTER key is pressed
|
40
45
|
esp_vfs_dev_usb_serial_jtag_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
41
46
|
// Move the caret to the beginning of the next line on '\n'
|
42
47
|
esp_vfs_dev_usb_serial_jtag_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
48
|
+
#else
|
49
|
+
// Minicom, screen, idf_monitor send CR when ENTER key is pressed
|
50
|
+
usb_serial_jtag_vfs_set_rx_line_endings(ESP_LINE_ENDINGS_CR);
|
51
|
+
// Move the caret to the beginning of the next line on '\n'
|
52
|
+
usb_serial_jtag_vfs_set_tx_line_endings(ESP_LINE_ENDINGS_CRLF);
|
53
|
+
#endif
|
43
54
|
|
44
55
|
// Enable non-blocking mode on stdin and stdout
|
45
56
|
fcntl(fileno(stdout), F_SETFL, 0);
|
@@ -57,7 +68,11 @@ static void init_usb_serial_jtag_() {
|
|
57
68
|
}
|
58
69
|
|
59
70
|
// Tell vfs to use usb-serial-jtag driver
|
71
|
+
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 3, 0)
|
60
72
|
esp_vfs_usb_serial_jtag_use_driver();
|
73
|
+
#else
|
74
|
+
usb_serial_jtag_vfs_use_driver();
|
75
|
+
#endif
|
61
76
|
}
|
62
77
|
#endif
|
63
78
|
|
@@ -7,6 +7,7 @@ import esphome.config_validation as cv
|
|
7
7
|
from esphome.const import (
|
8
8
|
CONF_AUTO_CLEAR_ENABLED,
|
9
9
|
CONF_BUFFER_SIZE,
|
10
|
+
CONF_GROUP,
|
10
11
|
CONF_ID,
|
11
12
|
CONF_LAMBDA,
|
12
13
|
CONF_ON_IDLE,
|
@@ -22,12 +23,18 @@ from esphome.helpers import write_file_if_changed
|
|
22
23
|
|
23
24
|
from . import defines as df, helpers, lv_validation as lvalid
|
24
25
|
from .automation import disp_update, focused_widgets, update_to_code
|
25
|
-
from .defines import
|
26
|
-
from .encoders import
|
26
|
+
from .defines import add_define
|
27
|
+
from .encoders import (
|
28
|
+
ENCODERS_CONFIG,
|
29
|
+
encoders_to_code,
|
30
|
+
get_default_group,
|
31
|
+
initial_focus_to_code,
|
32
|
+
)
|
27
33
|
from .gradient import GRADIENT_SCHEMA, gradients_to_code
|
28
34
|
from .hello_world import get_hello_world
|
35
|
+
from .keypads import KEYPADS_CONFIG, keypads_to_code
|
29
36
|
from .lv_validation import lv_bool, lv_images_used
|
30
|
-
from .lvcode import LvContext, LvglComponent
|
37
|
+
from .lvcode import LvContext, LvglComponent, lvgl_static
|
31
38
|
from .schemas import (
|
32
39
|
DISP_BG_SCHEMA,
|
33
40
|
FLEX_OBJ_SCHEMA,
|
@@ -48,12 +55,13 @@ from .types import (
|
|
48
55
|
FontEngine,
|
49
56
|
IdleTrigger,
|
50
57
|
ObjUpdateAction,
|
58
|
+
PauseTrigger,
|
51
59
|
lv_font_t,
|
52
60
|
lv_group_t,
|
53
61
|
lv_style_t,
|
54
62
|
lvgl_ns,
|
55
63
|
)
|
56
|
-
from .widgets import Widget, add_widgets,
|
64
|
+
from .widgets import Widget, add_widgets, get_scr_act, set_obj_properties, styles_used
|
57
65
|
from .widgets.animimg import animimg_spec
|
58
66
|
from .widgets.arc import arc_spec
|
59
67
|
from .widgets.button import button_spec
|
@@ -70,6 +78,7 @@ from .widgets.meter import meter_spec
|
|
70
78
|
from .widgets.msgbox import MSGBOX_SCHEMA, msgboxes_to_code
|
71
79
|
from .widgets.obj import obj_spec
|
72
80
|
from .widgets.page import add_pages, generate_page_triggers, page_spec
|
81
|
+
from .widgets.qrcode import qr_code_spec
|
73
82
|
from .widgets.roller import roller_spec
|
74
83
|
from .widgets.slider import slider_spec
|
75
84
|
from .widgets.spinbox import spinbox_spec
|
@@ -108,6 +117,7 @@ for w_type in (
|
|
108
117
|
spinbox_spec,
|
109
118
|
keyboard_spec,
|
110
119
|
tileview_spec,
|
120
|
+
qr_code_spec,
|
111
121
|
):
|
112
122
|
WIDGET_TYPES[w_type.name] = w_type
|
113
123
|
|
@@ -149,43 +159,80 @@ def generate_lv_conf_h():
|
|
149
159
|
return LV_CONF_H_FORMAT.format("\n".join(definitions))
|
150
160
|
|
151
161
|
|
152
|
-
def
|
153
|
-
|
154
|
-
|
155
|
-
|
162
|
+
def multi_conf_validate(configs: list[dict]):
|
163
|
+
displays = [config[df.CONF_DISPLAYS] for config in configs]
|
164
|
+
# flatten the display list
|
165
|
+
display_list = [disp for disps in displays for disp in disps]
|
166
|
+
if len(display_list) != len(set(display_list)):
|
167
|
+
raise cv.Invalid("A display ID may be used in only one LVGL instance")
|
168
|
+
for config in configs:
|
169
|
+
for item in (df.CONF_ENCODERS, df.CONF_KEYPADS):
|
170
|
+
for enc in config.get(item, ()):
|
171
|
+
if CONF_GROUP not in enc:
|
172
|
+
raise cv.Invalid(
|
173
|
+
f"'{item}' must have an explicit group set when using multiple LVGL instances"
|
174
|
+
)
|
175
|
+
base_config = configs[0]
|
176
|
+
for config in configs[1:]:
|
177
|
+
for item in (
|
178
|
+
df.CONF_LOG_LEVEL,
|
179
|
+
df.CONF_COLOR_DEPTH,
|
180
|
+
df.CONF_BYTE_ORDER,
|
181
|
+
df.CONF_TRANSPARENCY_KEY,
|
182
|
+
):
|
183
|
+
if base_config[item] != config[item]:
|
184
|
+
raise cv.Invalid(
|
185
|
+
f"Config item '{item}' must be the same for all LVGL instances"
|
186
|
+
)
|
187
|
+
|
188
|
+
|
189
|
+
def final_validation(configs):
|
190
|
+
if len(configs) != 1:
|
191
|
+
multi_conf_validate(configs)
|
156
192
|
global_config = full_config.get()
|
157
|
-
for
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
)
|
184
|
-
|
185
|
-
|
186
|
-
|
193
|
+
for config in configs:
|
194
|
+
if pages := config.get(CONF_PAGES):
|
195
|
+
if all(p[df.CONF_SKIP] for p in pages):
|
196
|
+
raise cv.Invalid("At least one page must not be skipped")
|
197
|
+
for display_id in config[df.CONF_DISPLAYS]:
|
198
|
+
path = global_config.get_path_for_id(display_id)[:-1]
|
199
|
+
display = global_config.get_config_for_path(path)
|
200
|
+
if CONF_LAMBDA in display:
|
201
|
+
raise cv.Invalid(
|
202
|
+
"Using lambda: in display config not compatible with LVGL"
|
203
|
+
)
|
204
|
+
if display[CONF_AUTO_CLEAR_ENABLED]:
|
205
|
+
raise cv.Invalid(
|
206
|
+
"Using auto_clear_enabled: true in display config not compatible with LVGL"
|
207
|
+
)
|
208
|
+
buffer_frac = config[CONF_BUFFER_SIZE]
|
209
|
+
if CORE.is_esp32 and buffer_frac > 0.5 and "psram" not in global_config:
|
210
|
+
LOGGER.warning("buffer_size: may need to be reduced without PSRAM")
|
211
|
+
for image_id in lv_images_used:
|
212
|
+
path = global_config.get_path_for_id(image_id)[:-1]
|
213
|
+
image_conf = global_config.get_config_for_path(path)
|
214
|
+
if image_conf[CONF_TYPE] in ("RGBA", "RGB24"):
|
215
|
+
raise cv.Invalid(
|
216
|
+
"Using RGBA or RGB24 in image config not compatible with LVGL", path
|
217
|
+
)
|
218
|
+
for w in focused_widgets:
|
219
|
+
path = global_config.get_path_for_id(w)
|
220
|
+
widget_conf = global_config.get_config_for_path(path[:-1])
|
221
|
+
if (
|
222
|
+
df.CONF_ADJUSTABLE in widget_conf
|
223
|
+
and not widget_conf[df.CONF_ADJUSTABLE]
|
224
|
+
):
|
225
|
+
raise cv.Invalid(
|
226
|
+
"A non adjustable arc may not be focused",
|
227
|
+
path,
|
228
|
+
)
|
229
|
+
|
230
|
+
|
231
|
+
async def to_code(configs):
|
232
|
+
config_0 = configs[0]
|
233
|
+
# Global configuration
|
187
234
|
cg.add_library("lvgl/lvgl", "8.4.0")
|
188
|
-
|
235
|
+
cg.add_define("USE_LVGL")
|
189
236
|
# suppress default enabling of extra widgets
|
190
237
|
add_define("_LV_KCONFIG_PRESENT")
|
191
238
|
# Always enable - lots of things use it.
|
@@ -199,45 +246,34 @@ async def to_code(config):
|
|
199
246
|
add_define("LV_MEM_CUSTOM_REALLOC", "lv_custom_mem_realloc")
|
200
247
|
add_define("LV_MEM_CUSTOM_INCLUDE", '"esphome/components/lvgl/lvgl_hal.h"')
|
201
248
|
|
202
|
-
add_define(
|
203
|
-
|
249
|
+
add_define(
|
250
|
+
"LV_LOG_LEVEL",
|
251
|
+
f"LV_LOG_LEVEL_{df.LV_LOG_LEVELS[config_0[df.CONF_LOG_LEVEL]]}",
|
252
|
+
)
|
253
|
+
cg.add_define(
|
254
|
+
"LVGL_LOG_LEVEL",
|
255
|
+
cg.RawExpression(f"ESPHOME_LOG_LEVEL_{config_0[df.CONF_LOG_LEVEL]}"),
|
256
|
+
)
|
257
|
+
add_define("LV_COLOR_DEPTH", config_0[df.CONF_COLOR_DEPTH])
|
204
258
|
for font in helpers.lv_fonts_used:
|
205
259
|
add_define(f"LV_FONT_{font.upper()}")
|
206
260
|
|
207
|
-
if
|
261
|
+
if config_0[df.CONF_COLOR_DEPTH] == 16:
|
208
262
|
add_define(
|
209
263
|
"LV_COLOR_16_SWAP",
|
210
|
-
"1" if
|
264
|
+
"1" if config_0[df.CONF_BYTE_ORDER] == "big_endian" else "0",
|
211
265
|
)
|
212
266
|
add_define(
|
213
267
|
"LV_COLOR_CHROMA_KEY",
|
214
|
-
await lvalid.lv_color.process(
|
268
|
+
await lvalid.lv_color.process(config_0[df.CONF_TRANSPARENCY_KEY]),
|
215
269
|
)
|
216
|
-
|
270
|
+
cg.add_build_flag("-Isrc")
|
217
271
|
|
218
272
|
cg.add_global(lvgl_ns.using)
|
219
|
-
lv_component = cg.new_Pvariable(config[CONF_ID])
|
220
|
-
await cg.register_component(lv_component, config)
|
221
|
-
Widget.create(config[CONF_ID], lv_component, obj_spec, config)
|
222
|
-
for display in config[df.CONF_DISPLAYS]:
|
223
|
-
cg.add(lv_component.add_display(await cg.get_variable(display)))
|
224
|
-
|
225
|
-
frac = config[CONF_BUFFER_SIZE]
|
226
|
-
if frac >= 0.75:
|
227
|
-
frac = 1
|
228
|
-
elif frac >= 0.375:
|
229
|
-
frac = 2
|
230
|
-
elif frac > 0.19:
|
231
|
-
frac = 4
|
232
|
-
else:
|
233
|
-
frac = 8
|
234
|
-
cg.add(lv_component.set_buffer_frac(int(frac)))
|
235
|
-
cg.add(lv_component.set_full_refresh(config[df.CONF_FULL_REFRESH]))
|
236
|
-
|
237
273
|
for font in helpers.esphome_fonts_used:
|
238
274
|
await cg.get_variable(font)
|
239
275
|
cg.new_Pvariable(ID(f"{font}_engine", True, type=FontEngine), MockObj(font))
|
240
|
-
default_font =
|
276
|
+
default_font = config_0[df.CONF_DEFAULT_FONT]
|
241
277
|
if not lvalid.is_lv_font(default_font):
|
242
278
|
add_define(
|
243
279
|
"LV_FONT_CUSTOM_DECLARE", f"LV_FONT_DECLARE(*{df.DEFAULT_ESPHOME_FONT})"
|
@@ -253,58 +289,103 @@ async def to_code(config):
|
|
253
289
|
add_define("LV_FONT_DEFAULT", df.DEFAULT_ESPHOME_FONT)
|
254
290
|
else:
|
255
291
|
add_define("LV_FONT_DEFAULT", await lvalid.lv_font.process(default_font))
|
292
|
+
cg.add(lvgl_static.esphome_lvgl_init())
|
293
|
+
default_group = get_default_group(config_0)
|
256
294
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
295
|
+
for config in configs:
|
296
|
+
frac = config[CONF_BUFFER_SIZE]
|
297
|
+
if frac >= 0.75:
|
298
|
+
frac = 1
|
299
|
+
elif frac >= 0.375:
|
300
|
+
frac = 2
|
301
|
+
elif frac > 0.19:
|
302
|
+
frac = 4
|
303
|
+
else:
|
304
|
+
frac = 8
|
305
|
+
displays = [
|
306
|
+
await cg.get_variable(display) for display in config[df.CONF_DISPLAYS]
|
307
|
+
]
|
308
|
+
lv_component = cg.new_Pvariable(
|
309
|
+
config[CONF_ID],
|
310
|
+
displays,
|
311
|
+
frac,
|
312
|
+
config[df.CONF_FULL_REFRESH],
|
313
|
+
config[df.CONF_DRAW_ROUNDING],
|
314
|
+
config[df.CONF_RESUME_ON_INPUT],
|
315
|
+
)
|
316
|
+
await cg.register_component(lv_component, config)
|
317
|
+
Widget.create(config[CONF_ID], lv_component, obj_spec, config)
|
318
|
+
|
319
|
+
lv_scr_act = get_scr_act(lv_component)
|
320
|
+
async with LvContext():
|
321
|
+
await touchscreens_to_code(lv_component, config)
|
322
|
+
await encoders_to_code(lv_component, config, default_group)
|
323
|
+
await keypads_to_code(lv_component, config, default_group)
|
324
|
+
await theme_to_code(config)
|
325
|
+
await styles_to_code(config)
|
326
|
+
await gradients_to_code(config)
|
327
|
+
await set_obj_properties(lv_scr_act, config)
|
328
|
+
await add_widgets(lv_scr_act, config)
|
329
|
+
await add_pages(lv_component, config)
|
330
|
+
await add_top_layer(lv_component, config)
|
331
|
+
await msgboxes_to_code(lv_component, config)
|
332
|
+
await disp_update(lv_component.get_disp(), config)
|
333
|
+
# Set this directly since we are limited in how many methods can be added to the Widget class.
|
334
|
+
Widget.widgets_completed = True
|
335
|
+
async with LvContext():
|
336
|
+
await generate_triggers()
|
337
|
+
for config in configs:
|
338
|
+
lv_component = await cg.get_variable(config[CONF_ID])
|
339
|
+
await generate_page_triggers(config)
|
340
|
+
await initial_focus_to_code(config)
|
341
|
+
for conf in config.get(CONF_ON_IDLE, ()):
|
342
|
+
templ = await cg.templatable(conf[CONF_TIMEOUT], [], cg.uint32)
|
343
|
+
idle_trigger = cg.new_Pvariable(
|
344
|
+
conf[CONF_TRIGGER_ID], lv_component, templ
|
345
|
+
)
|
346
|
+
await build_automation(idle_trigger, [], conf)
|
347
|
+
for conf in config.get(df.CONF_ON_PAUSE, ()):
|
348
|
+
pause_trigger = cg.new_Pvariable(
|
349
|
+
conf[CONF_TRIGGER_ID], lv_component, True
|
350
|
+
)
|
351
|
+
await build_automation(pause_trigger, [], conf)
|
352
|
+
for conf in config.get(df.CONF_ON_RESUME, ()):
|
353
|
+
resume_trigger = cg.new_Pvariable(
|
354
|
+
conf[CONF_TRIGGER_ID], lv_component, False
|
355
|
+
)
|
356
|
+
await build_automation(resume_trigger, [], conf)
|
280
357
|
|
358
|
+
# This must be done after all widgets are created
|
281
359
|
for comp in helpers.lvgl_components_required:
|
282
|
-
|
360
|
+
cg.add_define(f"USE_LVGL_{comp.upper()}")
|
283
361
|
if "transform_angle" in styles_used:
|
284
362
|
add_define("LV_COLOR_SCREEN_TRANSP", "1")
|
285
363
|
for use in helpers.lv_uses:
|
286
364
|
add_define(f"LV_USE_{use.upper()}")
|
287
365
|
lv_conf_h_file = CORE.relative_src_path(LV_CONF_FILENAME)
|
288
366
|
write_file_if_changed(lv_conf_h_file, generate_lv_conf_h())
|
289
|
-
|
290
|
-
|
367
|
+
cg.add_build_flag("-DLV_CONF_H=1")
|
368
|
+
cg.add_build_flag(f'-DLV_CONF_PATH="{LV_CONF_FILENAME}"')
|
291
369
|
|
292
370
|
|
293
371
|
def display_schema(config):
|
294
372
|
value = cv.ensure_list(cv.use_id(Display))(config)
|
295
|
-
|
373
|
+
value = value or [cv.use_id(Display)(config)]
|
374
|
+
if len(set(value)) != len(value):
|
375
|
+
raise cv.Invalid("Display IDs must be unique")
|
376
|
+
return value
|
296
377
|
|
297
378
|
|
298
379
|
def add_hello_world(config):
|
299
|
-
if CONF_WIDGETS not in config and CONF_PAGES not in config:
|
380
|
+
if df.CONF_WIDGETS not in config and CONF_PAGES not in config:
|
300
381
|
LOGGER.info("No pages or widgets configured, creating default hello_world page")
|
301
|
-
config[CONF_WIDGETS] = cv.ensure_list(WIDGET_SCHEMA)(get_hello_world())
|
382
|
+
config[df.CONF_WIDGETS] = cv.ensure_list(WIDGET_SCHEMA)(get_hello_world())
|
302
383
|
return config
|
303
384
|
|
304
385
|
|
305
386
|
FINAL_VALIDATE_SCHEMA = final_validation
|
306
387
|
|
307
|
-
|
388
|
+
LVGL_SCHEMA = (
|
308
389
|
cv.polling_component_schema("1s")
|
309
390
|
.extend(obj_schema(obj_spec))
|
310
391
|
.extend(
|
@@ -314,9 +395,10 @@ CONFIG_SCHEMA = (
|
|
314
395
|
cv.Optional(df.CONF_COLOR_DEPTH, default=16): cv.one_of(16),
|
315
396
|
cv.Optional(df.CONF_DEFAULT_FONT, default="montserrat_14"): lvalid.lv_font,
|
316
397
|
cv.Optional(df.CONF_FULL_REFRESH, default=False): cv.boolean,
|
398
|
+
cv.Optional(df.CONF_DRAW_ROUNDING, default=2): cv.positive_int,
|
317
399
|
cv.Optional(CONF_BUFFER_SIZE, default="100%"): cv.percentage,
|
318
400
|
cv.Optional(df.CONF_LOG_LEVEL, default="WARN"): cv.one_of(
|
319
|
-
*df.
|
401
|
+
*df.LV_LOG_LEVELS, upper=True
|
320
402
|
),
|
321
403
|
cv.Optional(df.CONF_BYTE_ORDER, default="big_endian"): cv.one_of(
|
322
404
|
"big_endian", "little_endian"
|
@@ -341,6 +423,16 @@ CONFIG_SCHEMA = (
|
|
341
423
|
),
|
342
424
|
}
|
343
425
|
),
|
426
|
+
cv.Optional(df.CONF_ON_PAUSE): validate_automation(
|
427
|
+
{
|
428
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger),
|
429
|
+
}
|
430
|
+
),
|
431
|
+
cv.Optional(df.CONF_ON_RESUME): validate_automation(
|
432
|
+
{
|
433
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(PauseTrigger),
|
434
|
+
}
|
435
|
+
),
|
344
436
|
cv.Exclusive(df.CONF_WIDGETS, CONF_PAGES): cv.ensure_list(WIDGET_SCHEMA),
|
345
437
|
cv.Exclusive(CONF_PAGES, CONF_PAGES): cv.ensure_list(
|
346
438
|
container_schema(page_spec)
|
@@ -355,9 +447,24 @@ CONFIG_SCHEMA = (
|
|
355
447
|
cv.Optional(df.CONF_GRADIENTS): GRADIENT_SCHEMA,
|
356
448
|
cv.Optional(df.CONF_TOUCHSCREENS, default=None): touchscreen_schema,
|
357
449
|
cv.Optional(df.CONF_ENCODERS, default=None): ENCODERS_CONFIG,
|
450
|
+
cv.Optional(df.CONF_KEYPADS, default=None): KEYPADS_CONFIG,
|
358
451
|
cv.GenerateID(df.CONF_DEFAULT_GROUP): cv.declare_id(lv_group_t),
|
452
|
+
cv.Optional(df.CONF_RESUME_ON_INPUT, default=True): cv.boolean,
|
359
453
|
}
|
360
454
|
)
|
361
455
|
.extend(DISP_BG_SCHEMA)
|
362
456
|
.add_extra(add_hello_world)
|
363
457
|
)
|
458
|
+
|
459
|
+
|
460
|
+
def lvgl_config_schema(config):
|
461
|
+
"""
|
462
|
+
Can't use cv.ensure_list here because it converts an empty config to an empty list,
|
463
|
+
rather than a default config.
|
464
|
+
"""
|
465
|
+
if not config or isinstance(config, dict):
|
466
|
+
return [LVGL_SCHEMA(config)]
|
467
|
+
return cv.Schema([LVGL_SCHEMA])(config)
|
468
|
+
|
469
|
+
|
470
|
+
CONFIG_SCHEMA = lvgl_config_schema
|