1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-01 10:52:19 +01:00

[lvgl] Various validation fixes (#10141)

This commit is contained in:
Clyde Stubbs
2025-08-11 08:27:54 +10:00
committed by GitHub
parent da02f970d4
commit 581b4ef5a1
8 changed files with 52 additions and 31 deletions

View File

@@ -287,10 +287,14 @@ def angle(value):
:param value: The input in the range 0..360
:return: An angle in 1/10 degree units.
"""
return int(cv.float_range(0.0, 360.0)(cv.angle(value)) * 10)
return cv.float_range(0.0, 360.0)(cv.angle(value))
lv_angle = LValidator(angle, uint32)
# Validator for angles in LVGL expressed in 1/10 degree units.
lv_angle = LValidator(angle, uint32, retmapper=lambda x: int(x * 10))
# Validator for angles in LVGL expressed in whole degrees
lv_angle_degrees = LValidator(angle, uint32, retmapper=int)
@schema_extractor("one_of")

View File

@@ -161,7 +161,7 @@ class WidgetType:
"""
return []
def obj_creator(self, parent: MockObjClass, config: dict):
async def obj_creator(self, parent: MockObjClass, config: dict):
"""
Create an instance of the widget type
:param parent: The parent to which it should be attached

View File

@@ -439,7 +439,7 @@ async def widget_to_code(w_cnfig, w_type: WidgetType, parent):
:return:
"""
spec: WidgetType = WIDGET_TYPES[w_type]
creator = spec.obj_creator(parent, w_cnfig)
creator = await spec.obj_creator(parent, w_cnfig)
add_lv_use(spec.name)
add_lv_use(*spec.get_uses())
wid = w_cnfig[CONF_ID]

View File

@@ -20,7 +20,7 @@ from ..defines import (
CONF_START_ANGLE,
literal,
)
from ..lv_validation import angle, get_start_value, lv_float
from ..lv_validation import get_start_value, lv_angle_degrees, lv_float, lv_int
from ..lvcode import lv, lv_expr, lv_obj
from ..types import LvNumber, NumberType
from . import Widget
@@ -29,11 +29,11 @@ CONF_ARC = "arc"
ARC_SCHEMA = cv.Schema(
{
cv.Optional(CONF_VALUE): lv_float,
cv.Optional(CONF_MIN_VALUE, default=0): cv.int_,
cv.Optional(CONF_MAX_VALUE, default=100): cv.int_,
cv.Optional(CONF_START_ANGLE, default=135): angle,
cv.Optional(CONF_END_ANGLE, default=45): angle,
cv.Optional(CONF_ROTATION, default=0.0): angle,
cv.Optional(CONF_MIN_VALUE, default=0): lv_int,
cv.Optional(CONF_MAX_VALUE, default=100): lv_int,
cv.Optional(CONF_START_ANGLE, default=135): lv_angle_degrees,
cv.Optional(CONF_END_ANGLE, default=45): lv_angle_degrees,
cv.Optional(CONF_ROTATION, default=0.0): lv_angle_degrees,
cv.Optional(CONF_ADJUSTABLE, default=False): bool,
cv.Optional(CONF_MODE, default="NORMAL"): ARC_MODES.one_of,
cv.Optional(CONF_CHANGE_RATE, default=720): cv.uint16_t,
@@ -59,11 +59,14 @@ class ArcType(NumberType):
async def to_code(self, w: Widget, config):
if CONF_MIN_VALUE in config:
lv.arc_set_range(w.obj, config[CONF_MIN_VALUE], config[CONF_MAX_VALUE])
lv.arc_set_bg_angles(
w.obj, config[CONF_START_ANGLE] // 10, config[CONF_END_ANGLE] // 10
)
lv.arc_set_rotation(w.obj, config[CONF_ROTATION] // 10)
max_value = await lv_int.process(config[CONF_MAX_VALUE])
min_value = await lv_int.process(config[CONF_MIN_VALUE])
lv.arc_set_range(w.obj, min_value, max_value)
start = await lv_angle_degrees.process(config[CONF_START_ANGLE])
end = await lv_angle_degrees.process(config[CONF_END_ANGLE])
rotation = await lv_angle_degrees.process(config[CONF_ROTATION])
lv.arc_set_bg_angles(w.obj, start, end)
lv.arc_set_rotation(w.obj, rotation)
lv.arc_set_mode(w.obj, literal(config[CONF_MODE]))
lv.arc_set_change_rate(w.obj, config[CONF_CHANGE_RATE])

View File

@@ -4,7 +4,7 @@ from esphome.const import CONF_SIZE, CONF_TEXT
from esphome.cpp_generator import MockObjClass
from ..defines import CONF_MAIN
from ..lv_validation import color, color_retmapper, lv_text
from ..lv_validation import lv_color, lv_text
from ..lvcode import LocalVariable, lv, lv_expr
from ..schemas import TEXT_SCHEMA
from ..types import WidgetType, lv_obj_t
@@ -16,8 +16,8 @@ CONF_LIGHT_COLOR = "light_color"
QRCODE_SCHEMA = TEXT_SCHEMA.extend(
{
cv.Optional(CONF_DARK_COLOR, default="black"): color,
cv.Optional(CONF_LIGHT_COLOR, default="white"): color,
cv.Optional(CONF_DARK_COLOR, default="black"): lv_color,
cv.Optional(CONF_LIGHT_COLOR, default="white"): lv_color,
cv.Required(CONF_SIZE): cv.int_,
}
)
@@ -34,11 +34,11 @@ class QrCodeType(WidgetType):
)
def get_uses(self):
return ("canvas", "img", "label")
return "canvas", "img", "label"
def obj_creator(self, parent: MockObjClass, config: dict):
dark_color = color_retmapper(config[CONF_DARK_COLOR])
light_color = color_retmapper(config[CONF_LIGHT_COLOR])
async def obj_creator(self, parent: MockObjClass, config: dict):
dark_color = await lv_color.process(config[CONF_DARK_COLOR])
light_color = await lv_color.process(config[CONF_LIGHT_COLOR])
size = config[CONF_SIZE]
return lv_expr.call("qrcode_create", parent, size, dark_color, light_color)

View File

@@ -2,7 +2,7 @@ import esphome.config_validation as cv
from esphome.cpp_generator import MockObjClass
from ..defines import CONF_ARC_LENGTH, CONF_INDICATOR, CONF_MAIN, CONF_SPIN_TIME
from ..lv_validation import angle
from ..lv_validation import lv_angle_degrees, lv_milliseconds
from ..lvcode import lv_expr
from ..types import LvType
from . import Widget, WidgetType
@@ -12,8 +12,8 @@ CONF_SPINNER = "spinner"
SPINNER_SCHEMA = cv.Schema(
{
cv.Required(CONF_ARC_LENGTH): angle,
cv.Required(CONF_SPIN_TIME): cv.positive_time_period_milliseconds,
cv.Required(CONF_ARC_LENGTH): lv_angle_degrees,
cv.Required(CONF_SPIN_TIME): lv_milliseconds,
}
)
@@ -34,9 +34,9 @@ class SpinnerType(WidgetType):
def get_uses(self):
return (CONF_ARC,)
def obj_creator(self, parent: MockObjClass, config: dict):
spin_time = config[CONF_SPIN_TIME].total_milliseconds
arc_length = config[CONF_ARC_LENGTH] // 10
async def obj_creator(self, parent: MockObjClass, config: dict):
spin_time = await lv_milliseconds.process(config[CONF_SPIN_TIME])
arc_length = await lv_angle_degrees.process(config[CONF_ARC_LENGTH])
return lv_expr.call("spinner_create", parent, spin_time, arc_length)

View File

@@ -87,12 +87,12 @@ class TabviewType(WidgetType):
) as content_obj:
await set_obj_properties(Widget(content_obj, obj_spec), content_style)
def obj_creator(self, parent: MockObjClass, config: dict):
async def obj_creator(self, parent: MockObjClass, config: dict):
return lv_expr.call(
"tabview_create",
parent,
literal(config[CONF_POSITION]),
literal(config[CONF_SIZE]),
await DIRECTIONS.process(config[CONF_POSITION]),
await size.process(config[CONF_SIZE]),
)

View File

@@ -723,6 +723,20 @@ lvgl:
arc_color: 0xFFFF00
focused:
arc_color: 0x808080
- arc:
align: center
id: lv_arc_1
value: !lambda return 75;
min_value: !lambda return 50;
max_value: !lambda return 60;
arc_color: 0xFF0000
indicator:
arc_width: !lambda return 20;
arc_color: 0xF000FF
pressed:
arc_color: 0xFFFF00
focused:
arc_color: 0x808080
- bar:
id: bar_id
align: top_mid