From 60fced53c214b5ccdb7fb0907cd01e06ba899456 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Mon, 26 Aug 2024 08:08:30 +1000 Subject: [PATCH] [lvgl] Bug fixes: (#7341) --- esphome/components/lvgl/automation.py | 2 +- esphome/components/lvgl/defines.py | 8 ++++++- esphome/components/lvgl/number/__init__.py | 1 + esphome/components/lvgl/select/__init__.py | 1 + esphome/components/lvgl/switch/__init__.py | 3 ++- esphome/components/lvgl/text/__init__.py | 1 + esphome/components/lvgl/widgets/__init__.py | 25 ++++++++++++++++----- tests/components/lvgl/lvgl-package.yaml | 16 +++++++++++++ 8 files changed, 49 insertions(+), 8 deletions(-) diff --git a/esphome/components/lvgl/automation.py b/esphome/components/lvgl/automation.py index efcac977ab..eb1b54e3ec 100644 --- a/esphome/components/lvgl/automation.py +++ b/esphome/components/lvgl/automation.py @@ -157,7 +157,7 @@ async def lvgl_update_to_code(config, action_id, template_arg, args): widgets = await get_widgets(config) w = widgets[0] disp = f"{w.obj}->get_disp()" - async with LambdaContext(parameters=args, where=action_id) as context: + async with LambdaContext(LVGL_COMP_ARG, where=action_id) as context: await disp_update(disp, config) var = cg.new_Pvariable(action_id, template_arg, await context.get_lambda()) await cg.register_parented(var, w.var) diff --git a/esphome/components/lvgl/defines.py b/esphome/components/lvgl/defines.py index 6a8b20b505..7bb1667e77 100644 --- a/esphome/components/lvgl/defines.py +++ b/esphome/components/lvgl/defines.py @@ -505,4 +505,10 @@ DEFAULT_ESPHOME_FONT = "esphome_lv_default_font" def join_enums(enums, prefix=""): - return literal("|".join(f"(int){prefix}{e.upper()}" for e in enums)) + enums = list(enums) + enums.sort() + # If a prefix is provided, prepend each constant with the prefix, and assume that all the constants are within the + # same namespace, otherwise cast to int to avoid triggering warnings about mixing enum types. + if prefix: + return literal("|".join(f"{prefix}{e.upper()}" for e in enums)) + return literal("|".join(f"(int){e.upper()}" for e in enums)) diff --git a/esphome/components/lvgl/number/__init__.py b/esphome/components/lvgl/number/__init__.py index 3e1ede0dec..07f92635b5 100644 --- a/esphome/components/lvgl/number/__init__.py +++ b/esphome/components/lvgl/number/__init__.py @@ -50,6 +50,7 @@ async def to_code(config): "value", MockObj("v") * MockObj(widget.get_scale()), config[CONF_ANIMATED] ) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(var.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as event: event.add(var.publish_state(widget.get_value())) event_code = ( diff --git a/esphome/components/lvgl/select/__init__.py b/esphome/components/lvgl/select/__init__.py index e77d0cfb32..73ac50aa55 100644 --- a/esphome/components/lvgl/select/__init__.py +++ b/esphome/components/lvgl/select/__init__.py @@ -43,6 +43,7 @@ async def to_code(config): async with LambdaContext([(cg.uint16, "v")]) as control: await widget.set_property("selected", "v", animated=config[CONF_ANIMATED]) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(selector.publish_index(widget.get_value())) async with LvContext(paren) as ctx: lv_add(selector.set_control_lambda(await control.get_lambda())) ctx.add( diff --git a/esphome/components/lvgl/switch/__init__.py b/esphome/components/lvgl/switch/__init__.py index f855c2a034..8c090543f9 100644 --- a/esphome/components/lvgl/switch/__init__.py +++ b/esphome/components/lvgl/switch/__init__.py @@ -3,7 +3,7 @@ from esphome.components.switch import Switch, new_switch, switch_schema import esphome.config_validation as cv from esphome.cpp_generator import MockObj -from ..defines import CONF_LVGL_ID, CONF_WIDGET +from ..defines import CONF_LVGL_ID, CONF_WIDGET, literal from ..lvcode import ( API_EVENT, EVENT_ARG, @@ -44,6 +44,7 @@ async def to_code(config): cond.else_() widget.clear_state(LV_STATE.CHECKED) lv.event_send(widget.obj, API_EVENT, cg.nullptr) + control.add(switch.publish_state(literal("v"))) async with LvContext(paren) as ctx: lv_add(switch.set_control_lambda(await control.get_lambda())) ctx.add( diff --git a/esphome/components/lvgl/text/__init__.py b/esphome/components/lvgl/text/__init__.py index 56fa42e131..540591d24b 100644 --- a/esphome/components/lvgl/text/__init__.py +++ b/esphome/components/lvgl/text/__init__.py @@ -36,6 +36,7 @@ async def to_code(config): async with LambdaContext([(cg.std_string, "text_value")]) as control: await widget.set_property("text", "text_value.c_str())") lv.event_send(widget.obj, API_EVENT, None) + control.add(textvar.publish_state(widget.get_value())) async with LambdaContext(EVENT_ARG) as lamb: lv_add(textvar.publish_state(widget.get_value())) async with LvContext(paren): diff --git a/esphome/components/lvgl/widgets/__init__.py b/esphome/components/lvgl/widgets/__init__.py index 17d73c1714..062c268135 100644 --- a/esphome/components/lvgl/widgets/__init__.py +++ b/esphome/components/lvgl/widgets/__init__.py @@ -118,7 +118,14 @@ class Widget: def clear_flag(self, flag): return lv_obj.clear_flag(self.obj, literal(flag)) - async def set_property(self, prop, value, animated: bool = None): + async def set_property(self, prop, value, animated: bool = None, lv_name=None): + """ + Set a property of the widget. + :param prop: The property name + :param value: The value + :param animated: If the change should be animated + :param lv_name: The base type of the widget e.g. "obj" + """ if isinstance(value, dict): value = value.get(prop) if isinstance(ALL_STYLES.get(prop), LValidator): @@ -131,11 +138,12 @@ class Widget: value = value.total_milliseconds if isinstance(value, str): value = literal(value) + lv_name = lv_name or self.type.lv_name if animated is None or self.type.animated is not True: - lv.call(f"{self.type.lv_name}_set_{prop}", self.obj, value) + lv.call(f"{lv_name}_set_{prop}", self.obj, value) else: lv.call( - f"{self.type.lv_name}_set_{prop}", + f"{lv_name}_set_{prop}", self.obj, value, literal("LV_ANIM_ON" if animated else "LV_ANIM_OFF"), @@ -319,8 +327,15 @@ async def set_obj_properties(w: Widget, config): lv_obj.set_flex_align(w.obj, main, cross, track) parts = collect_parts(config) for part, states in parts.items(): + part = "LV_PART_" + part.upper() for state, props in states.items(): - lv_state = join_enums((f"LV_STATE_{state}", f"LV_PART_{part}")) + state = "LV_STATE_" + state.upper() + if state == "LV_STATE_DEFAULT": + lv_state = literal(part) + elif part == "LV_PART_MAIN": + lv_state = literal(state) + else: + lv_state = join_enums((state, part)) for style_id in props.get(CONF_STYLES, ()): lv_obj.add_style(w.obj, MockObj(style_id), lv_state) for prop, value in { @@ -384,7 +399,7 @@ async def set_obj_properties(w: Widget, config): w.add_state(state) cond.else_() w.clear_state(state) - await w.set_property(CONF_SCROLLBAR_MODE, config) + await w.set_property(CONF_SCROLLBAR_MODE, config, lv_name="obj") async def add_widgets(parent: Widget, config: dict): diff --git a/tests/components/lvgl/lvgl-package.yaml b/tests/components/lvgl/lvgl-package.yaml index 1479ce7358..0e2c37048b 100644 --- a/tests/components/lvgl/lvgl-package.yaml +++ b/tests/components/lvgl/lvgl-package.yaml @@ -1,6 +1,8 @@ lvgl: log_level: TRACE bg_color: light_blue + disp_bg_color: 0xffff00 + disp_bg_image: cat_image theme: obj: border_width: 1 @@ -78,6 +80,9 @@ lvgl: on_click: then: - lvgl.animimg.stop: anim_img + - lvgl.update: + disp_bg_color: 0xffff00 + disp_bg_image: cat_image - label: text: "Hello shiny day" text_color: 0xFFFFFF @@ -304,6 +309,17 @@ lvgl: src: cat_image align: top_left y: 50 + - tileview: + id: tileview_id + scrollbar_mode: active + tiles: + - id: page_1 + row: 0 + column: 0 + dir: HOR + widgets: + - obj: + bg_color: 0x000000 - id: page2 widgets: