esphome 2024.8.2__py3-none-any.whl → 2024.9.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 +6 -2
- esphome/components/api/api_connection.cpp +53 -0
- esphome/components/api/api_connection.h +4 -0
- esphome/components/api/api_pb2.cpp +280 -0
- esphome/components/api/api_pb2.h +91 -0
- esphome/components/api/api_pb2_service.cpp +85 -0
- esphome/components/api/api_pb2_service.h +28 -0
- esphome/components/async_tcp/__init__.py +3 -3
- esphome/components/atm90e26/sensor.py +10 -10
- esphome/components/atm90e32/sensor.py +1 -1
- esphome/components/bl0906/__init__.py +1 -0
- esphome/components/bl0906/bl0906.cpp +238 -0
- esphome/components/bl0906/bl0906.h +96 -0
- esphome/components/bl0906/const.py +4 -0
- esphome/components/bl0906/constants.h +122 -0
- esphome/components/bl0906/sensor.py +184 -0
- esphome/components/bl0942/__init__.py +1 -1
- esphome/components/bl0942/bl0942.cpp +127 -34
- esphome/components/bl0942/bl0942.h +87 -3
- esphome/components/bl0942/sensor.py +46 -8
- esphome/components/ble_client/__init__.py +1 -3
- esphome/components/ble_presence/binary_sensor.py +2 -2
- esphome/components/bluetooth_proxy/bluetooth_proxy.cpp +5 -0
- esphome/components/bmp280/sensor.py +2 -93
- esphome/components/bmp280_base/__init__.py +88 -0
- esphome/components/{bmp280/bmp280.cpp → bmp280_base/bmp280_base.cpp} +11 -4
- esphome/components/{bmp280/bmp280.h → bmp280_base/bmp280_base.h} +9 -5
- esphome/components/bmp280_i2c/__init__.py +0 -0
- esphome/components/bmp280_i2c/bmp280_i2c.cpp +27 -0
- esphome/components/bmp280_i2c/bmp280_i2c.h +22 -0
- esphome/components/bmp280_i2c/sensor.py +22 -0
- esphome/components/bmp280_spi/__init__.py +0 -0
- esphome/components/bmp280_spi/bmp280_spi.cpp +65 -0
- esphome/components/bmp280_spi/bmp280_spi.h +20 -0
- esphome/components/bmp280_spi/sensor.py +22 -0
- esphome/components/captive_portal/captive_portal.cpp +2 -0
- esphome/components/captive_portal/captive_portal.h +3 -1
- esphome/components/ch422g/__init__.py +67 -0
- esphome/components/ch422g/ch422g.cpp +122 -0
- esphome/components/ch422g/ch422g.h +70 -0
- esphome/components/debug/debug_esp32.cpp +3 -1
- esphome/components/display/__init__.py +5 -4
- esphome/components/dsmr/dsmr.cpp +6 -0
- esphome/components/dsmr/dsmr.h +6 -0
- esphome/components/dsmr/text_sensor.py +7 -2
- esphome/components/e131/e131.cpp +2 -0
- esphome/components/e131/e131.h +3 -1
- esphome/components/e131/e131_addressable_light_effect.cpp +2 -0
- esphome/components/e131/e131_addressable_light_effect.h +2 -1
- esphome/components/e131/e131_packet.cpp +2 -0
- esphome/components/esp32_ble/ble_uuid.cpp +7 -0
- esphome/components/esp32_ble/ble_uuid.h +1 -0
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.cpp +11 -9
- esphome/components/esp32_ble_tracker/esp32_ble_tracker.h +3 -3
- esphome/components/esp32_camera/__init__.py +4 -0
- esphome/components/esp32_camera/esp32_camera.cpp +9 -1
- esphome/components/esp32_camera/esp32_camera.h +3 -0
- esphome/components/esp32_can/canbus.py +18 -7
- esphome/components/esp32_can/esp32_can.cpp +8 -0
- esphome/components/esp32_can/esp32_can.h +4 -0
- esphome/components/esp32_rmt_led_strip/led_strip.cpp +14 -2
- esphome/components/esp32_rmt_led_strip/led_strip.h +3 -2
- esphome/components/esp32_rmt_led_strip/light.py +21 -4
- esphome/components/esphome/ota/ota_esphome.cpp +2 -1
- esphome/components/esphome/ota/ota_esphome.h +2 -0
- esphome/components/font/__init__.py +11 -22
- esphome/components/font/font.cpp +3 -2
- esphome/components/font/font.h +12 -3
- esphome/components/gree/climate.py +2 -1
- esphome/components/gree/gree.cpp +54 -3
- esphome/components/gree/gree.h +10 -2
- esphome/components/gt911/touchscreen/__init__.py +6 -4
- esphome/components/gt911/touchscreen/gt911_touchscreen.cpp +17 -0
- esphome/components/gt911/touchscreen/gt911_touchscreen.h +2 -0
- esphome/components/hmac_md5/__init__.py +2 -0
- esphome/components/hmac_md5/hmac_md5.cpp +56 -0
- esphome/components/hmac_md5/hmac_md5.h +48 -0
- esphome/components/homeassistant/__init__.py +13 -0
- esphome/components/homeassistant/switch/__init__.py +15 -2
- esphome/components/homeassistant/switch/homeassistant_switch.cpp +2 -2
- esphome/components/i2s_audio/__init__.py +88 -9
- esphome/components/i2s_audio/i2s_audio.h +20 -2
- esphome/components/i2s_audio/media_player/__init__.py +8 -4
- esphome/components/i2s_audio/media_player/i2s_audio_media_player.h +1 -1
- esphome/components/i2s_audio/microphone/__init__.py +19 -51
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.cpp +18 -15
- esphome/components/i2s_audio/microphone/i2s_audio_microphone.h +0 -12
- esphome/components/i2s_audio/speaker/__init__.py +39 -27
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.cpp +49 -37
- esphome/components/i2s_audio/speaker/i2s_audio_speaker.h +3 -4
- esphome/components/ili9xxx/display.py +16 -17
- esphome/components/ili9xxx/ili9xxx_display.cpp +1 -1
- esphome/components/ili9xxx/ili9xxx_display.h +18 -18
- esphome/components/ili9xxx/ili9xxx_init.h +0 -3
- esphome/components/improv_serial/improv_serial_component.cpp +2 -1
- esphome/components/improv_serial/improv_serial_component.h +2 -1
- esphome/components/ledc/ledc_output.cpp +11 -7
- esphome/components/libretiny/__init__.py +8 -13
- esphome/components/ltr501/__init__.py +1 -0
- esphome/components/ltr501/ltr501.cpp +542 -0
- esphome/components/ltr501/ltr501.h +184 -0
- esphome/components/ltr501/ltr_definitions_501.h +260 -0
- esphome/components/ltr501/sensor.py +274 -0
- esphome/components/ltr_als_ps/sensor.py +2 -2
- esphome/components/lvgl/__init__.py +19 -16
- esphome/components/lvgl/automation.py +90 -9
- esphome/components/lvgl/defines.py +29 -2
- esphome/components/lvgl/gradient.py +61 -0
- esphome/components/lvgl/lv_validation.py +45 -27
- esphome/components/lvgl/lvcode.py +8 -3
- esphome/components/lvgl/lvgl_esphome.cpp +54 -0
- esphome/components/lvgl/lvgl_esphome.h +9 -3
- esphome/components/lvgl/number/__init__.py +1 -0
- esphome/components/lvgl/number/lvgl_number.h +3 -1
- esphome/components/lvgl/schemas.py +16 -11
- esphome/components/lvgl/select/__init__.py +1 -0
- esphome/components/lvgl/select/lvgl_select.h +3 -1
- esphome/components/lvgl/switch/__init__.py +2 -1
- esphome/components/lvgl/switch/lvgl_switch.h +3 -1
- esphome/components/lvgl/text/__init__.py +1 -0
- esphome/components/lvgl/text/lvgl_text.h +3 -1
- esphome/components/lvgl/trigger.py +3 -2
- esphome/components/lvgl/types.py +2 -1
- esphome/components/lvgl/widgets/__init__.py +23 -8
- esphome/components/lvgl/widgets/arc.py +5 -1
- esphome/components/lvgl/widgets/buttonmatrix.py +5 -1
- esphome/components/lvgl/widgets/checkbox.py +8 -3
- esphome/components/lvgl/widgets/meter.py +8 -1
- esphome/components/lvgl/widgets/msgbox.py +26 -15
- esphome/components/lvgl/widgets/page.py +51 -7
- esphome/components/lvgl/widgets/tileview.py +2 -8
- esphome/components/max31856/max31856.cpp +12 -1
- esphome/components/max31856/max31856.h +5 -2
- esphome/components/max31856/sensor.py +20 -0
- esphome/components/mcp9600/sensor.py +2 -2
- esphome/components/mdns/__init__.py +6 -6
- esphome/components/media_player/media_player.h +16 -0
- esphome/components/micro_wake_word/__init__.py +2 -25
- esphome/components/microphone/microphone.h +1 -1
- esphome/components/mics_4514/mics_4514.cpp +26 -36
- esphome/components/modbus_controller/__init__.py +6 -0
- esphome/components/modbus_controller/const.py +2 -0
- esphome/components/modbus_controller/modbus_controller.cpp +30 -27
- esphome/components/modbus_controller/modbus_controller.h +22 -4
- esphome/components/network/__init__.py +11 -8
- esphome/components/pipsolar/pipsolar.cpp +3 -0
- esphome/components/pipsolar/pipsolar.h +1 -0
- esphome/components/pipsolar/switch/__init__.py +2 -0
- esphome/components/prometheus/prometheus_handler.cpp +2 -0
- esphome/components/prometheus/prometheus_handler.h +3 -1
- esphome/components/rp2040/__init__.py +7 -8
- esphome/components/rpi_dpi_rgb/display.py +20 -17
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.cpp +36 -6
- esphome/components/rpi_dpi_rgb/rpi_dpi_rgb.h +4 -0
- esphome/components/socket/socket.cpp +2 -0
- esphome/components/socket/socket.h +2 -0
- esphome/components/speaker/speaker.h +1 -1
- esphome/components/st7701s/display.py +35 -37
- esphome/components/st7701s/st7701s.cpp +11 -6
- esphome/components/st7701s/st7701s.h +1 -0
- esphome/components/statsd/__init__.py +65 -0
- esphome/components/statsd/statsd.cpp +156 -0
- esphome/components/statsd/statsd.h +86 -0
- esphome/components/tuya/__init__.py +1 -0
- esphome/components/tuya/number/__init__.py +39 -2
- esphome/components/tuya/number/tuya_number.cpp +58 -2
- esphome/components/tuya/number/tuya_number.h +12 -3
- esphome/components/udp/__init__.py +158 -0
- esphome/components/udp/binary_sensor.py +27 -0
- esphome/components/udp/sensor.py +27 -0
- esphome/components/udp/udp_component.cpp +616 -0
- esphome/components/udp/udp_component.h +158 -0
- esphome/components/uponor_smatrix/uponor_smatrix.cpp +4 -6
- esphome/components/uponor_smatrix/uponor_smatrix.h +0 -1
- esphome/components/veml7700/sensor.py +2 -2
- esphome/components/voice_assistant/__init__.py +6 -0
- esphome/components/voice_assistant/voice_assistant.cpp +24 -2
- esphome/components/voice_assistant/voice_assistant.h +20 -0
- esphome/components/web_server/__init__.py +11 -11
- esphome/components/web_server/list_entities.cpp +2 -0
- esphome/components/web_server/list_entities.h +3 -1
- esphome/components/web_server/web_server.cpp +2 -1
- esphome/components/web_server/web_server.h +2 -0
- esphome/components/web_server_base/web_server_base.cpp +2 -0
- esphome/components/web_server_base/web_server_base.h +3 -1
- esphome/components/wifi/wifi_component_libretiny.cpp +15 -1
- esphome/components/wireguard/__init__.py +9 -6
- esphome/components/wireguard/wireguard.cpp +2 -1
- esphome/components/wireguard/wireguard.h +3 -1
- esphome/config_validation.py +8 -0
- esphome/const.py +8 -1
- esphome/core/bytebuffer.cpp +117 -84
- esphome/core/bytebuffer.h +69 -21
- esphome/core/config.py +0 -3
- esphome/core/defines.h +2 -0
- esphome/core/ring_buffer.cpp +13 -2
- esphome/core/ring_buffer.h +56 -0
- esphome/external_files.py +5 -3
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/METADATA +1 -1
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/RECORD +204 -169
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/LICENSE +0 -0
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/WHEEL +0 -0
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/entry_points.txt +0 -0
- {esphome-2024.8.2.dist-info → esphome-2024.9.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,61 @@
|
|
1
|
+
from esphome import config_validation as cv
|
2
|
+
import esphome.codegen as cg
|
3
|
+
from esphome.const import (
|
4
|
+
CONF_COLOR,
|
5
|
+
CONF_DIRECTION,
|
6
|
+
CONF_DITHER,
|
7
|
+
CONF_ID,
|
8
|
+
CONF_POSITION,
|
9
|
+
)
|
10
|
+
from esphome.cpp_generator import MockObj
|
11
|
+
|
12
|
+
from .defines import CONF_GRADIENTS, LV_DITHER, LV_GRAD_DIR, add_define
|
13
|
+
from .lv_validation import lv_color, lv_fraction
|
14
|
+
from .lvcode import lv_assign
|
15
|
+
from .types import lv_gradient_t
|
16
|
+
|
17
|
+
CONF_STOPS = "stops"
|
18
|
+
|
19
|
+
|
20
|
+
def min_stops(value):
|
21
|
+
if len(value) < 2:
|
22
|
+
raise cv.Invalid("Must have at least 2 stops")
|
23
|
+
return value
|
24
|
+
|
25
|
+
|
26
|
+
GRADIENT_SCHEMA = cv.ensure_list(
|
27
|
+
cv.Schema(
|
28
|
+
{
|
29
|
+
cv.GenerateID(CONF_ID): cv.declare_id(lv_gradient_t),
|
30
|
+
cv.Optional(CONF_DIRECTION, default="NONE"): LV_GRAD_DIR.one_of,
|
31
|
+
cv.Optional(CONF_DITHER, default="NONE"): LV_DITHER.one_of,
|
32
|
+
cv.Required(CONF_STOPS): cv.All(
|
33
|
+
[
|
34
|
+
cv.Schema(
|
35
|
+
{
|
36
|
+
cv.Required(CONF_COLOR): lv_color,
|
37
|
+
cv.Required(CONF_POSITION): lv_fraction,
|
38
|
+
}
|
39
|
+
)
|
40
|
+
],
|
41
|
+
min_stops,
|
42
|
+
),
|
43
|
+
}
|
44
|
+
)
|
45
|
+
)
|
46
|
+
|
47
|
+
|
48
|
+
async def gradients_to_code(config):
|
49
|
+
max_stops = 2
|
50
|
+
for gradient in config.get(CONF_GRADIENTS, ()):
|
51
|
+
var = MockObj(cg.new_Pvariable(gradient[CONF_ID]), "->")
|
52
|
+
max_stops = max(max_stops, len(gradient[CONF_STOPS]))
|
53
|
+
lv_assign(var.dir, await LV_GRAD_DIR.process(gradient[CONF_DIRECTION]))
|
54
|
+
lv_assign(var.dither, await LV_DITHER.process(gradient[CONF_DITHER]))
|
55
|
+
lv_assign(var.stops_count, len(gradient[CONF_STOPS]))
|
56
|
+
for index, stop in enumerate(gradient[CONF_STOPS]):
|
57
|
+
lv_assign(var.stops[index].color, await lv_color.process(stop[CONF_COLOR]))
|
58
|
+
lv_assign(
|
59
|
+
var.stops[index].frac, await lv_fraction.process(stop[CONF_POSITION])
|
60
|
+
)
|
61
|
+
add_define("LV_GRADIENT_MAX_STOPS", max_stops)
|
@@ -1,12 +1,19 @@
|
|
1
1
|
from typing import Union
|
2
2
|
|
3
3
|
import esphome.codegen as cg
|
4
|
-
from esphome.components.color import ColorStruct
|
4
|
+
from esphome.components.color import CONF_HEX, ColorStruct, from_rgbw
|
5
5
|
from esphome.components.font import Font
|
6
6
|
from esphome.components.image import Image_
|
7
7
|
import esphome.config_validation as cv
|
8
|
-
from esphome.const import
|
9
|
-
|
8
|
+
from esphome.const import (
|
9
|
+
CONF_ARGS,
|
10
|
+
CONF_COLOR,
|
11
|
+
CONF_FORMAT,
|
12
|
+
CONF_ID,
|
13
|
+
CONF_TIME,
|
14
|
+
CONF_VALUE,
|
15
|
+
)
|
16
|
+
from esphome.core import CORE, ID, Lambda
|
10
17
|
from esphome.cpp_generator import MockObj
|
11
18
|
from esphome.cpp_types import ESPTime, uint32
|
12
19
|
from esphome.helpers import cpp_string_escape
|
@@ -23,14 +30,9 @@ from .defines import (
|
|
23
30
|
call_lambda,
|
24
31
|
literal,
|
25
32
|
)
|
26
|
-
from .helpers import
|
27
|
-
esphome_fonts_used,
|
28
|
-
lv_fonts_used,
|
29
|
-
lvgl_components_required,
|
30
|
-
requires_component,
|
31
|
-
)
|
33
|
+
from .helpers import esphome_fonts_used, lv_fonts_used, requires_component
|
32
34
|
from .lvcode import lv_expr
|
33
|
-
from .types import lv_font_t, lv_img_t
|
35
|
+
from .types import lv_font_t, lv_gradient_t, lv_img_t
|
34
36
|
|
35
37
|
opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
|
36
38
|
|
@@ -52,20 +54,24 @@ opacity = LValidator(opacity_validator, uint32, retmapper=literal)
|
|
52
54
|
def color(value):
|
53
55
|
if value == SCHEMA_EXTRACT:
|
54
56
|
return ["hex color value", "color ID"]
|
55
|
-
|
56
|
-
return value
|
57
|
-
return cv.use_id(ColorStruct)(value)
|
57
|
+
return cv.Any(cv.int_, cv.use_id(ColorStruct))(value)
|
58
58
|
|
59
59
|
|
60
60
|
def color_retmapper(value):
|
61
61
|
if isinstance(value, cv.Lambda):
|
62
62
|
return cv.returning_lambda(value)
|
63
63
|
if isinstance(value, int):
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
64
|
+
return literal(
|
65
|
+
f"lv_color_make({(value >> 16) & 0xFF}, {(value >> 8) & 0xFF}, {value & 0xFF})"
|
66
|
+
)
|
67
|
+
if isinstance(value, ID):
|
68
|
+
cval = [x for x in CORE.config[CONF_COLOR] if x[CONF_ID] == value][0]
|
69
|
+
if CONF_HEX in cval:
|
70
|
+
r, g, b = cval[CONF_HEX]
|
71
|
+
else:
|
72
|
+
r, g, b, _ = from_rgbw(cval)
|
73
|
+
return literal(f"lv_color_make({r}, {g}, {b})")
|
74
|
+
assert False
|
69
75
|
|
70
76
|
|
71
77
|
def option_string(value):
|
@@ -82,10 +88,10 @@ def pixels_or_percent_validator(value):
|
|
82
88
|
"""A length in one axis - either a number (pixels) or a percentage"""
|
83
89
|
if value == SCHEMA_EXTRACT:
|
84
90
|
return ["pixels", "..%"]
|
91
|
+
value = cv.Any(cv.int_, cv.percentage)(value)
|
85
92
|
if isinstance(value, int):
|
86
|
-
return
|
87
|
-
|
88
|
-
return f"lv_pct({int(cv.percentage(value) * 100)})"
|
93
|
+
return value
|
94
|
+
return f"lv_pct({int(value * 100)})"
|
89
95
|
|
90
96
|
|
91
97
|
pixels_or_percent = LValidator(pixels_or_percent_validator, uint32, retmapper=literal)
|
@@ -116,10 +122,7 @@ def size_validator(value):
|
|
116
122
|
if value.upper() == "SIZE_CONTENT":
|
117
123
|
return "LV_SIZE_CONTENT"
|
118
124
|
raise cv.Invalid("must be 'size_content', a percentage or an integer (pixels)")
|
119
|
-
|
120
|
-
return cv.int_(value)
|
121
|
-
# Will throw an exception if not a percentage.
|
122
|
-
return f"lv_pct({int(cv.percentage(value) * 100)})"
|
125
|
+
return pixels_or_percent_validator(value)
|
123
126
|
|
124
127
|
|
125
128
|
size = LValidator(size_validator, uint32, retmapper=literal)
|
@@ -137,7 +140,7 @@ radius_consts = LvConstant("LV_RADIUS_", "CIRCLE")
|
|
137
140
|
|
138
141
|
|
139
142
|
@schema_extractor("one_of")
|
140
|
-
def
|
143
|
+
def fraction_validator(value):
|
141
144
|
if value == SCHEMA_EXTRACT:
|
142
145
|
return radius_consts.choices
|
143
146
|
value = cv.Any(size, cv.percentage, radius_consts.one_of)(value)
|
@@ -146,7 +149,7 @@ def radius_validator(value):
|
|
146
149
|
return value
|
147
150
|
|
148
151
|
|
149
|
-
|
152
|
+
lv_fraction = LValidator(fraction_validator, uint32, retmapper=literal)
|
150
153
|
|
151
154
|
|
152
155
|
def id_name(value):
|
@@ -247,6 +250,21 @@ lv_int = LValidator(cv.int_, cg.int_)
|
|
247
250
|
lv_brightness = LValidator(cv.percentage, cg.float_, retmapper=lambda x: int(x * 255))
|
248
251
|
|
249
252
|
|
253
|
+
def gradient_mapper(value):
|
254
|
+
return MockObj(value)
|
255
|
+
|
256
|
+
|
257
|
+
def gradient_validator(value):
|
258
|
+
return cv.use_id(lv_gradient_t)(value)
|
259
|
+
|
260
|
+
|
261
|
+
lv_gradient = LValidator(
|
262
|
+
validator=gradient_validator,
|
263
|
+
rtype=lv_gradient_t,
|
264
|
+
retmapper=gradient_mapper,
|
265
|
+
)
|
266
|
+
|
267
|
+
|
250
268
|
def is_lv_font(font):
|
251
269
|
return isinstance(font, str) and font.lower() in LV_FONTS
|
252
270
|
|
@@ -28,7 +28,7 @@ LVGL_COMP = "lv_component" # used as a lambda argument in lvgl_comp()
|
|
28
28
|
LvglComponent = lvgl_ns.class_("LvglComponent", cg.PollingComponent)
|
29
29
|
LVGL_COMP_ARG = [(LvglComponent.operator("ptr"), LVGL_COMP)]
|
30
30
|
lv_event_t_ptr = cg.global_ns.namespace("lv_event_t").operator("ptr")
|
31
|
-
EVENT_ARG = [(lv_event_t_ptr, "
|
31
|
+
EVENT_ARG = [(lv_event_t_ptr, "event")]
|
32
32
|
# Two custom events; API_EVENT is fired when an entity is updated remotely by an API interaction;
|
33
33
|
# UPDATE_EVENT is fired when an entity is programmatically updated locally.
|
34
34
|
# VALUE_CHANGED is the event generated by LVGL when an entity's value changes through user interaction.
|
@@ -184,8 +184,9 @@ class LvContext(LambdaContext):
|
|
184
184
|
self.lv_component = lv_component
|
185
185
|
|
186
186
|
async def add_init_lambda(self):
|
187
|
-
|
188
|
-
|
187
|
+
if self.code_list:
|
188
|
+
cg.add(self.lv_component.add_init_lambda(await self.get_lambda()))
|
189
|
+
LvContext.added_lambda_count += 1
|
189
190
|
|
190
191
|
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
191
192
|
await super().__aexit__(exc_type, exc_val, exc_tb)
|
@@ -291,6 +292,10 @@ class LvExpr(MockLv):
|
|
291
292
|
pass
|
292
293
|
|
293
294
|
|
295
|
+
def static_cast(type, value):
|
296
|
+
return literal(f"static_cast<{type}>({value})")
|
297
|
+
|
298
|
+
|
294
299
|
# Top level mock for generic lv_ calls to be recorded
|
295
300
|
lv = MockLv("lv_")
|
296
301
|
# Just generate an expression
|
@@ -15,6 +15,60 @@ static void log_cb(const char *buf) {
|
|
15
15
|
}
|
16
16
|
#endif // LV_USE_LOG
|
17
17
|
|
18
|
+
static const char *const EVENT_NAMES[] = {
|
19
|
+
"NONE",
|
20
|
+
"PRESSED",
|
21
|
+
"PRESSING",
|
22
|
+
"PRESS_LOST",
|
23
|
+
"SHORT_CLICKED",
|
24
|
+
"LONG_PRESSED",
|
25
|
+
"LONG_PRESSED_REPEAT",
|
26
|
+
"CLICKED",
|
27
|
+
"RELEASED",
|
28
|
+
"SCROLL_BEGIN",
|
29
|
+
"SCROLL_END",
|
30
|
+
"SCROLL",
|
31
|
+
"GESTURE",
|
32
|
+
"KEY",
|
33
|
+
"FOCUSED",
|
34
|
+
"DEFOCUSED",
|
35
|
+
"LEAVE",
|
36
|
+
"HIT_TEST",
|
37
|
+
"COVER_CHECK",
|
38
|
+
"REFR_EXT_DRAW_SIZE",
|
39
|
+
"DRAW_MAIN_BEGIN",
|
40
|
+
"DRAW_MAIN",
|
41
|
+
"DRAW_MAIN_END",
|
42
|
+
"DRAW_POST_BEGIN",
|
43
|
+
"DRAW_POST",
|
44
|
+
"DRAW_POST_END",
|
45
|
+
"DRAW_PART_BEGIN",
|
46
|
+
"DRAW_PART_END",
|
47
|
+
"VALUE_CHANGED",
|
48
|
+
"INSERT",
|
49
|
+
"REFRESH",
|
50
|
+
"READY",
|
51
|
+
"CANCEL",
|
52
|
+
"DELETE",
|
53
|
+
"CHILD_CHANGED",
|
54
|
+
"CHILD_CREATED",
|
55
|
+
"CHILD_DELETED",
|
56
|
+
"SCREEN_UNLOAD_START",
|
57
|
+
"SCREEN_LOAD_START",
|
58
|
+
"SCREEN_LOADED",
|
59
|
+
"SCREEN_UNLOADED",
|
60
|
+
"SIZE_CHANGED",
|
61
|
+
"STYLE_CHANGED",
|
62
|
+
"LAYOUT_CHANGED",
|
63
|
+
"GET_SELF_SIZE",
|
64
|
+
};
|
65
|
+
|
66
|
+
std::string lv_event_code_name_for(uint8_t event_code) {
|
67
|
+
if (event_code < sizeof(EVENT_NAMES) / sizeof(EVENT_NAMES[0])) {
|
68
|
+
return EVENT_NAMES[event_code];
|
69
|
+
}
|
70
|
+
return str_sprintf("%2d", event_code);
|
71
|
+
}
|
18
72
|
static void rounder_cb(lv_disp_drv_t *disp_drv, lv_area_t *area) {
|
19
73
|
// make sure all coordinates are even
|
20
74
|
if (area->x1 & 1)
|
@@ -40,10 +40,8 @@ namespace lvgl {
|
|
40
40
|
|
41
41
|
extern lv_event_code_t lv_api_event; // NOLINT
|
42
42
|
extern lv_event_code_t lv_update_event; // NOLINT
|
43
|
+
extern std::string lv_event_code_name_for(uint8_t event_code);
|
43
44
|
extern bool lv_is_pre_initialise();
|
44
|
-
#ifdef USE_LVGL_COLOR
|
45
|
-
inline lv_color_t lv_color_from(Color color) { return lv_color_make(color.red, color.green, color.blue); }
|
46
|
-
#endif // USE_LVGL_COLOR
|
47
45
|
#if LV_COLOR_DEPTH == 16
|
48
46
|
static const display::ColorBitness LV_BITNESS = display::ColorBitness::COLOR_BITNESS_565;
|
49
47
|
#elif LV_COLOR_DEPTH == 32
|
@@ -143,6 +141,13 @@ class LvglComponent : public PollingComponent {
|
|
143
141
|
void show_next_page(lv_scr_load_anim_t anim, uint32_t time);
|
144
142
|
void show_prev_page(lv_scr_load_anim_t anim, uint32_t time);
|
145
143
|
void set_page_wrap(bool wrap) { this->page_wrap_ = wrap; }
|
144
|
+
void set_focus_mark(lv_group_t *group) { this->focus_marks_[group] = lv_group_get_focused(group); }
|
145
|
+
void restore_focus_mark(lv_group_t *group) {
|
146
|
+
auto *mark = this->focus_marks_[group];
|
147
|
+
if (mark != nullptr) {
|
148
|
+
lv_group_focus_obj(mark);
|
149
|
+
}
|
150
|
+
}
|
146
151
|
|
147
152
|
protected:
|
148
153
|
void write_random_();
|
@@ -158,6 +163,7 @@ class LvglComponent : public PollingComponent {
|
|
158
163
|
bool show_snow_{};
|
159
164
|
lv_coord_t snow_line_{};
|
160
165
|
bool page_wrap_{true};
|
166
|
+
std::map<lv_group_t *, lv_obj_t *> focus_marks_{};
|
161
167
|
|
162
168
|
std::vector<std::function<void(LvglComponent *lv_component)>> init_lambdas_;
|
163
169
|
CallbackManager<void(uint32_t)> idle_callbacks_{};
|
@@ -50,6 +50,7 @@ async def to_code(config):
|
|
50
50
|
"value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED]
|
51
51
|
)
|
52
52
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
53
|
+
control.add(var.publish_state(widget.get_value()))
|
53
54
|
async with LambdaContext(EVENT_ARG) as event:
|
54
55
|
event.add(var.publish_state(widget.get_value()))
|
55
56
|
event_code = (
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
+
#include <utility>
|
4
|
+
|
3
5
|
#include "esphome/components/number/number.h"
|
4
6
|
#include "esphome/core/automation.h"
|
5
7
|
#include "esphome/core/component.h"
|
@@ -11,7 +13,7 @@ namespace lvgl {
|
|
11
13
|
class LVGLNumber : public number::Number {
|
12
14
|
public:
|
13
15
|
void set_control_lambda(std::function<void(float)> control_lambda) {
|
14
|
-
this->control_lambda_ = control_lambda;
|
16
|
+
this->control_lambda_ = std::move(control_lambda);
|
15
17
|
if (this->initial_state_.has_value()) {
|
16
18
|
this->control_lambda_(this->initial_state_.value());
|
17
19
|
this->initial_state_.reset();
|
@@ -17,10 +17,10 @@ from esphome.core import TimePeriod
|
|
17
17
|
from esphome.schema_extractors import SCHEMA_EXTRACT
|
18
18
|
|
19
19
|
from . import defines as df, lv_validation as lvalid
|
20
|
-
from .defines import CONF_TIME_FORMAT
|
20
|
+
from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
|
21
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
|
22
|
+
from .lv_validation import lv_color, lv_font, lv_gradient, lv_image
|
23
|
+
from .lvcode import LvglComponent, lv_event_t_ptr
|
24
24
|
from .types import (
|
25
25
|
LVEncoderListener,
|
26
26
|
LvType,
|
@@ -94,9 +94,10 @@ STYLE_PROPS = {
|
|
94
94
|
"arc_width": cv.positive_int,
|
95
95
|
"anim_time": lvalid.lv_milliseconds,
|
96
96
|
"bg_color": lvalid.lv_color,
|
97
|
+
"bg_grad": lv_gradient,
|
97
98
|
"bg_grad_color": lvalid.lv_color,
|
98
99
|
"bg_dither_mode": df.LvConstant("LV_DITHER_", "NONE", "ORDERED", "ERR_DIFF").one_of,
|
99
|
-
"bg_grad_dir":
|
100
|
+
"bg_grad_dir": LV_GRAD_DIR.one_of,
|
100
101
|
"bg_grad_stop": lvalid.stop_value,
|
101
102
|
"bg_image_opa": lvalid.opacity,
|
102
103
|
"bg_image_recolor": lvalid.lv_color,
|
@@ -160,7 +161,7 @@ STYLE_PROPS = {
|
|
160
161
|
"max_width": lvalid.pixels_or_percent,
|
161
162
|
"min_height": lvalid.pixels_or_percent,
|
162
163
|
"min_width": lvalid.pixels_or_percent,
|
163
|
-
"radius": lvalid.
|
164
|
+
"radius": lvalid.lv_fraction,
|
164
165
|
"width": lvalid.size,
|
165
166
|
"x": lvalid.pixels_or_percent,
|
166
167
|
"y": lvalid.pixels_or_percent,
|
@@ -215,14 +216,12 @@ def automation_schema(typ: LvType):
|
|
215
216
|
events = df.LV_EVENT_TRIGGERS + (CONF_ON_VALUE,)
|
216
217
|
else:
|
217
218
|
events = df.LV_EVENT_TRIGGERS
|
218
|
-
if isinstance(typ, LvType)
|
219
|
-
|
220
|
-
else:
|
221
|
-
template = Trigger.template()
|
219
|
+
args = [typ.get_arg_type()] if isinstance(typ, LvType) else []
|
220
|
+
args.append(lv_event_t_ptr)
|
222
221
|
return {
|
223
222
|
cv.Optional(event): validate_automation(
|
224
223
|
{
|
225
|
-
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(template),
|
224
|
+
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(Trigger.template(*args)),
|
226
225
|
}
|
227
226
|
)
|
228
227
|
for event in events
|
@@ -361,7 +360,13 @@ LVGL_SCHEMA = cv.Schema(
|
|
361
360
|
}
|
362
361
|
)
|
363
362
|
|
364
|
-
ALL_STYLES = {
|
363
|
+
ALL_STYLES = {
|
364
|
+
**STYLE_PROPS,
|
365
|
+
**GRID_CELL_SCHEMA,
|
366
|
+
**FLEX_OBJ_SCHEMA,
|
367
|
+
cv.Optional(df.CONF_PAD_ROW): lvalid.pixels,
|
368
|
+
cv.Optional(df.CONF_PAD_COLUMN): lvalid.pixels,
|
369
|
+
}
|
365
370
|
|
366
371
|
|
367
372
|
def container_validator(schema, widget_type: WidgetType):
|
@@ -43,6 +43,7 @@ async def to_code(config):
|
|
43
43
|
async with LambdaContext([(cg.uint16, "v")]) as control:
|
44
44
|
await widget.set_property("selected", "v", animated=config[CONF_ANIMATED])
|
45
45
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
46
|
+
control.add(selector.publish_index(widget.get_value()))
|
46
47
|
async with LvContext(paren) as ctx:
|
47
48
|
lv_add(selector.set_control_lambda(await control.get_lambda()))
|
48
49
|
ctx.add(
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
+
#include <utility>
|
4
|
+
|
3
5
|
#include "esphome/components/select/select.h"
|
4
6
|
#include "esphome/core/automation.h"
|
5
7
|
#include "esphome/core/component.h"
|
@@ -28,7 +30,7 @@ static std::vector<std::string> split_string(const std::string &str) {
|
|
28
30
|
class LVGLSelect : public select::Select {
|
29
31
|
public:
|
30
32
|
void set_control_lambda(std::function<void(size_t)> lambda) {
|
31
|
-
this->control_lambda_ = lambda;
|
33
|
+
this->control_lambda_ = std::move(lambda);
|
32
34
|
if (this->initial_state_.has_value()) {
|
33
35
|
this->control(this->initial_state_.value());
|
34
36
|
this->initial_state_.reset();
|
@@ -3,7 +3,7 @@ from esphome.components.switch import Switch, new_switch, switch_schema
|
|
3
3
|
import esphome.config_validation as cv
|
4
4
|
from esphome.cpp_generator import MockObj
|
5
5
|
|
6
|
-
from ..defines import CONF_LVGL_ID, CONF_WIDGET
|
6
|
+
from ..defines import CONF_LVGL_ID, CONF_WIDGET, literal
|
7
7
|
from ..lvcode import (
|
8
8
|
API_EVENT,
|
9
9
|
EVENT_ARG,
|
@@ -44,6 +44,7 @@ async def to_code(config):
|
|
44
44
|
cond.else_()
|
45
45
|
widget.clear_state(LV_STATE.CHECKED)
|
46
46
|
lv.event_send(widget.obj, API_EVENT, cg.nullptr)
|
47
|
+
control.add(switch.publish_state(literal("v")))
|
47
48
|
async with LvContext(paren) as ctx:
|
48
49
|
lv_add(switch.set_control_lambda(await control.get_lambda()))
|
49
50
|
ctx.add(
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
+
#include <utility>
|
4
|
+
|
3
5
|
#include "esphome/components/switch/switch.h"
|
4
6
|
#include "esphome/core/automation.h"
|
5
7
|
#include "esphome/core/component.h"
|
@@ -11,7 +13,7 @@ namespace lvgl {
|
|
11
13
|
class LVGLSwitch : public switch_::Switch {
|
12
14
|
public:
|
13
15
|
void set_control_lambda(std::function<void(bool)> state_lambda) {
|
14
|
-
this->state_lambda_ = state_lambda;
|
16
|
+
this->state_lambda_ = std::move(state_lambda);
|
15
17
|
if (this->initial_state_.has_value()) {
|
16
18
|
this->state_lambda_(this->initial_state_.value());
|
17
19
|
this->initial_state_.reset();
|
@@ -36,6 +36,7 @@ async def to_code(config):
|
|
36
36
|
async with LambdaContext([(cg.std_string, "text_value")]) as control:
|
37
37
|
await widget.set_property("text", "text_value.c_str())")
|
38
38
|
lv.event_send(widget.obj, API_EVENT, None)
|
39
|
+
control.add(textvar.publish_state(widget.get_value()))
|
39
40
|
async with LambdaContext(EVENT_ARG) as lamb:
|
40
41
|
lv_add(textvar.publish_state(widget.get_value()))
|
41
42
|
async with LvContext(paren):
|
@@ -1,5 +1,7 @@
|
|
1
1
|
#pragma once
|
2
2
|
|
3
|
+
#include <utility>
|
4
|
+
|
3
5
|
#include "esphome/components/text/text.h"
|
4
6
|
#include "esphome/core/automation.h"
|
5
7
|
#include "esphome/core/component.h"
|
@@ -11,7 +13,7 @@ namespace lvgl {
|
|
11
13
|
class LVGLText : public text::Text {
|
12
14
|
public:
|
13
15
|
void set_control_lambda(std::function<void(const std::string)> control_lambda) {
|
14
|
-
this->control_lambda_ = control_lambda;
|
16
|
+
this->control_lambda_ = std::move(control_lambda);
|
15
17
|
if (this->initial_state_.has_value()) {
|
16
18
|
this->control_lambda_(this->initial_state_.value());
|
17
19
|
this->initial_state_.reset();
|
@@ -19,6 +19,7 @@ from .lvcode import (
|
|
19
19
|
LvConditional,
|
20
20
|
lv,
|
21
21
|
lv_add,
|
22
|
+
lv_event_t_ptr,
|
22
23
|
)
|
23
24
|
from .types import LV_EVENT
|
24
25
|
from .widgets import widget_map
|
@@ -65,10 +66,10 @@ async def generate_triggers(lv_component):
|
|
65
66
|
async def add_trigger(conf, lv_component, w, *events):
|
66
67
|
tid = conf[CONF_TRIGGER_ID]
|
67
68
|
trigger = cg.new_Pvariable(tid)
|
68
|
-
args = w.get_args()
|
69
|
+
args = w.get_args() + [(lv_event_t_ptr, "event")]
|
69
70
|
value = w.get_value()
|
70
71
|
await automation.build_automation(trigger, args, conf)
|
71
72
|
async with LambdaContext(EVENT_ARG, where=tid) as context:
|
72
73
|
with LvConditional(w.is_selected()):
|
73
|
-
lv_add(trigger.trigger(value))
|
74
|
+
lv_add(trigger.trigger(value, literal("event")))
|
74
75
|
lv_add(lv_component.add_event_cb(w.obj, await context.get_lambda(), *events))
|
esphome/components/lvgl/types.py
CHANGED
@@ -57,8 +57,9 @@ lv_group_t = cg.global_ns.struct("lv_group_t")
|
|
57
57
|
LVTouchListener = lvgl_ns.class_("LVTouchListener")
|
58
58
|
LVEncoderListener = lvgl_ns.class_("LVEncoderListener")
|
59
59
|
lv_obj_t = LvType("lv_obj_t")
|
60
|
-
lv_page_t =
|
60
|
+
lv_page_t = LvType("LvPageType", parents=(LvCompound,))
|
61
61
|
lv_img_t = LvType("lv_img_t")
|
62
|
+
lv_gradient_t = LvType("lv_grad_dsc_t")
|
62
63
|
|
63
64
|
LV_EVENT = MockObj(base="LV_EVENT_", op="")
|
64
65
|
LV_STATE = MockObj(base="LV_STATE_", op="")
|
@@ -89,6 +89,8 @@ class Widget:
|
|
89
89
|
self.obj = MockObj(f"{self.var}->obj")
|
90
90
|
else:
|
91
91
|
self.obj = var
|
92
|
+
self.outer = None
|
93
|
+
self.move_to_foreground = False
|
92
94
|
|
93
95
|
@staticmethod
|
94
96
|
def create(name, var, wtype: WidgetType, config: dict = None):
|
@@ -118,7 +120,14 @@ class Widget:
|
|
118
120
|
def clear_flag(self, flag):
|
119
121
|
return lv_obj.clear_flag(self.obj, literal(flag))
|
120
122
|
|
121
|
-
async def set_property(self, prop, value, animated: bool = None):
|
123
|
+
async def set_property(self, prop, value, animated: bool = None, lv_name=None):
|
124
|
+
"""
|
125
|
+
Set a property of the widget.
|
126
|
+
:param prop: The property name
|
127
|
+
:param value: The value
|
128
|
+
:param animated: If the change should be animated
|
129
|
+
:param lv_name: The base type of the widget e.g. "obj"
|
130
|
+
"""
|
122
131
|
if isinstance(value, dict):
|
123
132
|
value = value.get(prop)
|
124
133
|
if isinstance(ALL_STYLES.get(prop), LValidator):
|
@@ -131,11 +140,12 @@ class Widget:
|
|
131
140
|
value = value.total_milliseconds
|
132
141
|
if isinstance(value, str):
|
133
142
|
value = literal(value)
|
143
|
+
lv_name = lv_name or self.type.lv_name
|
134
144
|
if animated is None or self.type.animated is not True:
|
135
|
-
lv.call(f"{
|
145
|
+
lv.call(f"{lv_name}_set_{prop}", self.obj, value)
|
136
146
|
else:
|
137
147
|
lv.call(
|
138
|
-
f"{
|
148
|
+
f"{lv_name}_set_{prop}",
|
139
149
|
self.obj,
|
140
150
|
value,
|
141
151
|
literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"),
|
@@ -217,7 +227,7 @@ def get_widget_generator(wid):
|
|
217
227
|
yield
|
218
228
|
|
219
229
|
|
220
|
-
async def get_widget_(wid
|
230
|
+
async def get_widget_(wid):
|
221
231
|
if obj := widget_map.get(wid):
|
222
232
|
return obj
|
223
233
|
return await FakeAwaitable(get_widget_generator(wid))
|
@@ -319,8 +329,15 @@ async def set_obj_properties(w: Widget, config):
|
|
319
329
|
lv_obj.set_flex_align(w.obj, main, cross, track)
|
320
330
|
parts = collect_parts(config)
|
321
331
|
for part, states in parts.items():
|
332
|
+
part = "LV_PART_" + part.upper()
|
322
333
|
for state, props in states.items():
|
323
|
-
|
334
|
+
state = "LV_STATE_" + state.upper()
|
335
|
+
if state == "LV_STATE_DEFAULT":
|
336
|
+
lv_state = literal(part)
|
337
|
+
elif part == "LV_PART_MAIN":
|
338
|
+
lv_state = literal(state)
|
339
|
+
else:
|
340
|
+
lv_state = join_enums((state, part))
|
324
341
|
for style_id in props.get(CONF_STYLES, ()):
|
325
342
|
lv_obj.add_style(w.obj, MockObj(style_id), lv_state)
|
326
343
|
for prop, value in {
|
@@ -333,8 +350,6 @@ async def set_obj_properties(w: Widget, config):
|
|
333
350
|
if group := config.get(CONF_GROUP):
|
334
351
|
group = await cg.get_variable(group)
|
335
352
|
lv.group_add_obj(group, w.obj)
|
336
|
-
flag_clr = set()
|
337
|
-
flag_set = set()
|
338
353
|
props = parts[CONF_MAIN][CONF_DEFAULT]
|
339
354
|
lambs = {}
|
340
355
|
flag_set = set()
|
@@ -384,7 +399,7 @@ async def set_obj_properties(w: Widget, config):
|
|
384
399
|
w.add_state(state)
|
385
400
|
cond.else_()
|
386
401
|
w.clear_state(state)
|
387
|
-
await w.set_property(CONF_SCROLLBAR_MODE, config)
|
402
|
+
await w.set_property(CONF_SCROLLBAR_MODE, config, lv_name="obj")
|
388
403
|
|
389
404
|
|
390
405
|
async def add_widgets(parent: Widget, config: dict):
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import esphome.config_validation as cv
|
2
2
|
from esphome.const import (
|
3
|
+
CONF_GROUP,
|
3
4
|
CONF_MAX_VALUE,
|
4
5
|
CONF_MIN_VALUE,
|
5
6
|
CONF_MODE,
|
@@ -20,7 +21,7 @@ from ..defines import (
|
|
20
21
|
literal,
|
21
22
|
)
|
22
23
|
from ..lv_validation import angle, get_start_value, lv_float
|
23
|
-
from ..lvcode import lv, lv_obj
|
24
|
+
from ..lvcode import lv, lv_expr, lv_obj
|
24
25
|
from ..types import LvNumber, NumberType
|
25
26
|
from . import Widget
|
26
27
|
|
@@ -69,6 +70,9 @@ class ArcType(NumberType):
|
|
69
70
|
if config.get(CONF_ADJUSTABLE) is False:
|
70
71
|
lv_obj.remove_style(w.obj, nullptr, literal("LV_PART_KNOB"))
|
71
72
|
w.clear_flag("LV_OBJ_FLAG_CLICKABLE")
|
73
|
+
elif CONF_GROUP not in config:
|
74
|
+
# For some reason arc does not get automatically added to the default group
|
75
|
+
lv.group_add_obj(lv_expr.group_get_default(), w.obj)
|
72
76
|
|
73
77
|
value = await get_start_value(config)
|
74
78
|
if value is not None:
|
@@ -13,11 +13,13 @@ from ..defines import (
|
|
13
13
|
CONF_KEY_CODE,
|
14
14
|
CONF_MAIN,
|
15
15
|
CONF_ONE_CHECKED,
|
16
|
+
CONF_PAD_COLUMN,
|
17
|
+
CONF_PAD_ROW,
|
16
18
|
CONF_ROWS,
|
17
19
|
CONF_SELECTED,
|
18
20
|
)
|
19
21
|
from ..helpers import lvgl_components_required
|
20
|
-
from ..lv_validation import key_code, lv_bool
|
22
|
+
from ..lv_validation import key_code, lv_bool, pixels
|
21
23
|
from ..lvcode import lv, lv_add, lv_expr
|
22
24
|
from ..schemas import automation_schema
|
23
25
|
from ..types import (
|
@@ -57,6 +59,8 @@ BUTTONMATRIX_BUTTON_SCHEMA = cv.Schema(
|
|
57
59
|
BUTTONMATRIX_SCHEMA = cv.Schema(
|
58
60
|
{
|
59
61
|
cv.Optional(CONF_ONE_CHECKED, default=False): lv_bool,
|
62
|
+
cv.Optional(CONF_PAD_ROW): pixels,
|
63
|
+
cv.Optional(CONF_PAD_COLUMN): pixels,
|
60
64
|
cv.GenerateID(CONF_BUTTON_TEXT_LIST_ID): cv.declare_id(char_ptr),
|
61
65
|
cv.Required(CONF_ROWS): cv.ensure_list(
|
62
66
|
cv.Schema(
|