[lvgl] Fix setting triggers on display (#15364)

This commit is contained in:
Clyde Stubbs
2026-04-07 08:48:14 +10:00
committed by GitHub
parent ce0d360790
commit c98bb9060f
4 changed files with 114 additions and 72 deletions
+15 -5
View File
@@ -2,7 +2,7 @@ import importlib
from pathlib import Path from pathlib import Path
import pkgutil import pkgutil
from esphome.automation import build_automation, validate_automation from esphome.automation import Trigger, build_automation, validate_automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.const import ( from esphome.components.const import (
CONF_BYTE_ORDER, CONF_BYTE_ORDER,
@@ -34,7 +34,6 @@ from esphome.const import (
CONF_ID, CONF_ID,
CONF_LAMBDA, CONF_LAMBDA,
CONF_LOG_LEVEL, CONF_LOG_LEVEL,
CONF_ON_BOOT,
CONF_ON_IDLE, CONF_ON_IDLE,
CONF_PAGES, CONF_PAGES,
CONF_ROTATION, CONF_ROTATION,
@@ -59,7 +58,7 @@ from .encoders import (
from .gradient import GRADIENT_SCHEMA, gradients_to_code from .gradient import GRADIENT_SCHEMA, gradients_to_code
from .keypads import KEYPADS_CONFIG, keypads_to_code from .keypads import KEYPADS_CONFIG, keypads_to_code
from .lv_validation import lv_bool, lv_images_used from .lv_validation import lv_bool, lv_images_used
from .lvcode import LvContext, LvglComponent, lvgl_static from .lvcode import LvContext, LvglComponent, lv_event_t_ptr, lvgl_static
from .schemas import ( from .schemas import (
DISP_BG_SCHEMA, DISP_BG_SCHEMA,
FULL_STYLE_SCHEMA, FULL_STYLE_SCHEMA,
@@ -71,7 +70,7 @@ from .schemas import (
) )
from .styles import styles_to_code, theme_to_code from .styles import styles_to_code, theme_to_code
from .touchscreens import touchscreen_schema, touchscreens_to_code from .touchscreens import touchscreen_schema, touchscreens_to_code
from .trigger import add_on_boot_triggers, generate_align_tos, generate_triggers from .trigger import generate_align_tos, generate_triggers
from .types import ( from .types import (
IdleTrigger, IdleTrigger,
PlainTrigger, PlainTrigger,
@@ -79,6 +78,7 @@ from .types import (
lv_font_t, lv_font_t,
lv_group_t, lv_group_t,
lv_lambda_t, lv_lambda_t,
lv_obj_t_ptr,
lv_style_t, lv_style_t,
lvgl_ns, lvgl_ns,
) )
@@ -398,7 +398,6 @@ async def to_code(configs):
f"set_{trigger_name.removeprefix('on_')}_trigger", f"set_{trigger_name.removeprefix('on_')}_trigger",
)(trigger_var) )(trigger_var)
) )
await add_on_boot_triggers(config.get(CONF_ON_BOOT, ()))
# This must be done after all widgets are created # This must be done after all widgets are created
for comp in helpers.lvgl_components_required: for comp in helpers.lvgl_components_required:
@@ -502,6 +501,17 @@ LVGL_SCHEMA = cv.All(
cv.polling_component_schema("1s") cv.polling_component_schema("1s")
.extend( .extend(
{ {
**{
cv.Optional(event): validate_automation(
{
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(
Trigger.template(lv_obj_t_ptr, lv_event_t_ptr)
),
}
)
for event in df.LV_SCREEN_EVENT_TRIGGERS
+ df.LV_DISPLAY_EVENT_TRIGGERS
},
cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent), cv.GenerateID(CONF_ID): cv.declare_id(LvglComponent),
cv.GenerateID(CONF_ALIGN_TO_LAMBDA_ID): cv.declare_id(lv_lambda_t), cv.GenerateID(CONF_ALIGN_TO_LAMBDA_ID): cv.declare_id(lv_lambda_t),
cv.GenerateID(df.CONF_DISPLAYS): display_schema, cv.GenerateID(df.CONF_DISPLAYS): display_schema,
+22 -14
View File
@@ -276,10 +276,6 @@ LV_EVENT_MAP = {
"DRAW_POST_BEGIN": "DRAW_POST_BEGIN", "DRAW_POST_BEGIN": "DRAW_POST_BEGIN",
"DRAW_POST_END": "DRAW_POST_END", "DRAW_POST_END": "DRAW_POST_END",
"DRAW_TASK_ADD": "DRAW_TASK_ADDED", "DRAW_TASK_ADD": "DRAW_TASK_ADDED",
"FLUSH_FINISH": "FLUSH_FINISH",
"FLUSH_START": "FLUSH_START",
"FLUSH_WAIT_FINISH": "FLUSH_WAIT_FINISH",
"FLUSH_WAIT_START": "FLUSH_WAIT_START",
"FOCUS": "FOCUSED", "FOCUS": "FOCUSED",
"GESTURE": "GESTURE", "GESTURE": "GESTURE",
"GET_SELF_SIZE": "GET_SELF_SIZE", "GET_SELF_SIZE": "GET_SELF_SIZE",
@@ -300,18 +296,8 @@ LV_EVENT_MAP = {
"READY": "READY", "READY": "READY",
"REFRESH": "REFRESH", "REFRESH": "REFRESH",
"REFR_EXT_DRAW_SIZE": "REFR_EXT_DRAW_SIZE", "REFR_EXT_DRAW_SIZE": "REFR_EXT_DRAW_SIZE",
"REFR_READY": "REFR_READY",
"REFR_REQUEST": "REFR_REQUEST",
"REFR_START": "REFR_START",
"RELEASE": "RELEASED", "RELEASE": "RELEASED",
"RENDER_READY": "RENDER_READY",
"RENDER_START": "RENDER_START",
"RESOLUTION_CHANGE": "RESOLUTION_CHANGED",
"ROTARY": "ROTARY", "ROTARY": "ROTARY",
"SCREEN_LOAD": "SCREEN_LOADED",
"SCREEN_LOAD_START": "SCREEN_LOAD_START",
"SCREEN_UNLOAD": "SCREEN_UNLOADED",
"SCREEN_UNLOAD_START": "SCREEN_UNLOAD_START",
"SCROLL": "SCROLL", "SCROLL": "SCROLL",
"SCROLL_BEGIN": "SCROLL_BEGIN", "SCROLL_BEGIN": "SCROLL_BEGIN",
"SCROLL_END": "SCROLL_END", "SCROLL_END": "SCROLL_END",
@@ -322,12 +308,34 @@ LV_EVENT_MAP = {
"STATE_CHANGE": "STATE_CHANGED", "STATE_CHANGE": "STATE_CHANGED",
"STYLE_CHANGE": "STYLE_CHANGED", "STYLE_CHANGE": "STYLE_CHANGED",
"TRIPLE_CLICK": "TRIPLE_CLICKED", "TRIPLE_CLICK": "TRIPLE_CLICKED",
}
LV_SCREEN_EVENT_MAP = {
"SCREEN_LOAD": "SCREEN_LOADED",
"SCREEN_LOAD_START": "SCREEN_LOAD_START",
"SCREEN_UNLOAD": "SCREEN_UNLOADED",
"SCREEN_UNLOAD_START": "SCREEN_UNLOAD_START",
}
LV_DISPLAY_EVENT_MAP = {
"FLUSH_FINISH": "FLUSH_FINISH",
"FLUSH_START": "FLUSH_START",
"FLUSH_WAIT_FINISH": "FLUSH_WAIT_FINISH",
"FLUSH_WAIT_START": "FLUSH_WAIT_START",
"REFR_READY": "REFR_READY",
"REFR_REQUEST": "REFR_REQUEST",
"REFR_START": "REFR_START",
"RENDER_READY": "RENDER_READY",
"RENDER_START": "RENDER_START",
"RESOLUTION_CHANGE": "RESOLUTION_CHANGED",
"UPDATE_LAYOUT_COMPLETE": "UPDATE_LAYOUT_COMPLETED", "UPDATE_LAYOUT_COMPLETE": "UPDATE_LAYOUT_COMPLETED",
"VSYNC": "VSYNC", "VSYNC": "VSYNC",
"VSYNC_REQUEST": "VSYNC_REQUEST", "VSYNC_REQUEST": "VSYNC_REQUEST",
} }
LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP) LV_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_EVENT_MAP)
LV_DISPLAY_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_DISPLAY_EVENT_MAP)
LV_SCREEN_EVENT_TRIGGERS = tuple(f"on_{x.lower()}" for x in LV_SCREEN_EVENT_MAP)
SWIPE_TRIGGERS = tuple( SWIPE_TRIGGERS = tuple(
f"on_swipe_{x.lower()}" for x in DIRECTIONS.choices + ("up", "down") f"on_swipe_{x.lower()}" for x in DIRECTIONS.choices + ("up", "down")
) )
+39 -15
View File
@@ -8,16 +8,21 @@ from esphome.const import (
CONF_X, CONF_X,
CONF_Y, CONF_Y,
) )
from esphome.cpp_generator import new_Pvariable from esphome.cpp_generator import MockObj, new_Pvariable
from esphome.cpp_helpers import register_component from esphome.cpp_helpers import register_component
from esphome.cpp_types import nullptr
from .defines import ( from .defines import (
CONF_ALIGN, CONF_ALIGN,
CONF_ALIGN_TO, CONF_ALIGN_TO,
CONF_ALIGN_TO_LAMBDA_ID, CONF_ALIGN_TO_LAMBDA_ID,
DIRECTIONS, DIRECTIONS,
LV_DISPLAY_EVENT_MAP,
LV_DISPLAY_EVENT_TRIGGERS,
LV_EVENT_MAP, LV_EVENT_MAP,
LV_EVENT_TRIGGERS, LV_EVENT_TRIGGERS,
LV_SCREEN_EVENT_MAP,
LV_SCREEN_EVENT_TRIGGERS,
SWIPE_TRIGGERS, SWIPE_TRIGGERS,
literal, literal,
) )
@@ -30,6 +35,7 @@ from .lvcode import (
lv, lv,
lv_add, lv_add,
lv_event_t_ptr, lv_event_t_ptr,
lv_expr,
lvgl_static, lvgl_static,
) )
from .types import LV_EVENT from .types import LV_EVENT
@@ -49,25 +55,24 @@ async def generate_triggers():
Must be done after all widgets completed Must be done after all widgets completed
""" """
all_triggers = (
LV_EVENT_TRIGGERS + LV_DISPLAY_EVENT_TRIGGERS + LV_SCREEN_EVENT_TRIGGERS
)
for w in widget_map.values(): for w in widget_map.values():
config = w.config
if isinstance(w.type, LvScrActType): if isinstance(w.type, LvScrActType):
w = get_screen_active(w.var) w = get_screen_active(w.var)
if w.config: if config:
for event, conf in { for event, conf in {
event: conf event: conf for event, conf in config.items() if event in all_triggers
for event, conf in w.config.items()
if event in LV_EVENT_TRIGGERS
}.items(): }.items():
conf = conf[0] conf = conf[0]
w.add_flag("LV_OBJ_FLAG_CLICKABLE") w.add_flag("LV_OBJ_FLAG_CLICKABLE")
event = literal("LV_EVENT_" + LV_EVENT_MAP[event[3:].upper()])
await add_trigger(conf, w, event) await add_trigger(conf, w, event)
for event, conf in { for event, conf in {
event: conf event: conf for event, conf in config.items() if event in SWIPE_TRIGGERS
for event, conf in w.config.items()
if event in SWIPE_TRIGGERS
}.items(): }.items():
conf = conf[0] conf = conf[0]
dir = event[9:].upper() dir = event[9:].upper()
@@ -77,11 +82,9 @@ async def generate_triggers():
selected = literal( selected = literal(
f"lv_indev_get_gesture_dir(lv_indev_active()) == {dir}" f"lv_indev_get_gesture_dir(lv_indev_active()) == {dir}"
) )
await add_trigger( await add_trigger(conf, w, "GESTURE", is_selected=selected)
conf, w, literal("LV_EVENT_GESTURE"), is_selected=selected
)
for conf in w.config.get(CONF_ON_VALUE, ()): for conf in config.get(CONF_ON_VALUE, ()):
await add_trigger( await add_trigger(
conf, conf,
w, w,
@@ -90,7 +93,7 @@ async def generate_triggers():
UPDATE_EVENT, UPDATE_EVENT,
) )
await add_on_boot_triggers(w.config.get(CONF_ON_BOOT, ())) await add_on_boot_triggers(config.get(CONF_ON_BOOT, ()))
async def generate_align_tos(config: dict): async def generate_align_tos(config: dict):
@@ -119,6 +122,17 @@ async def generate_align_tos(config: dict):
await register_component(var, {}) await register_component(var, {})
TRIGGER_MAP = LV_EVENT_MAP | LV_DISPLAY_EVENT_MAP | LV_SCREEN_EVENT_MAP
DISPLAY_TRIGGERS = set(LV_DISPLAY_EVENT_TRIGGERS)
def _get_event_literal(trigger: str | MockObj) -> MockObj:
if isinstance(trigger, MockObj):
return trigger
trigger = trigger.removeprefix("on_")
return literal("LV_EVENT_" + TRIGGER_MAP[trigger.upper()])
async def add_trigger(conf, w, *events, is_selected=None): async def add_trigger(conf, w, *events, is_selected=None):
is_selected = is_selected or w.is_selected() is_selected = is_selected or w.is_selected()
tid = conf[CONF_TRIGGER_ID] tid = conf[CONF_TRIGGER_ID]
@@ -129,4 +143,14 @@ async def add_trigger(conf, w, *events, is_selected=None):
async with LambdaContext(EVENT_ARG, where=tid) as context: async with LambdaContext(EVENT_ARG, where=tid) as context:
with LvConditional(is_selected): with LvConditional(is_selected):
lv_add(trigger.trigger(*value, literal("event"))) lv_add(trigger.trigger(*value, literal("event")))
lv_add(lvgl_static.add_event_cb(w.obj, await context.get_lambda(), *events)) callback = await context.get_lambda()
event_literals = [_get_event_literal(event) for event in events]
if isinstance(events[0], str) and events[0] in DISPLAY_TRIGGERS:
assert len(events) == 1
lv.display_add_event_cb(
lv_expr.obj_get_display(w.obj), callback, event_literals[0], nullptr
)
else:
lv_add(
lvgl_static.add_event_cb(w.obj, await context.get_lambda(), *event_literals)
)
+38 -38
View File
@@ -49,6 +49,44 @@ lvgl:
id: meter_arc_indicator id: meter_arc_indicator
start_value: 0 start_value: 0
end_value: 180 end_value: 180
on_invalidate_area:
logger.log: Invalidate area
on_resolution_change:
logger.log: Resolution changed
on_color_format_change:
logger.log: Color format changed
on_refr_request:
logger.log: Refresh request
on_refr_start:
logger.log: Refresh start
on_refr_ready:
logger.log: Refresh ready
on_render_start:
logger.log: Render start
on_render_ready:
logger.log: Render ready
on_flush_start:
logger.log: Flush start
on_flush_finish:
logger.log: Flush finish
on_flush_wait_start:
logger.log: Flush wait start
on_flush_wait_finish:
logger.log: Flush wait finish
on_update_layout_complete:
logger.log: Update layout complete
on_vsync:
logger.log: Vsync
on_vsync_request:
logger.log: Vsync request
on_screen_load_start:
logger.log: Screen load start
on_screen_load:
logger.log: Screen loaded
on_screen_unload:
logger.log: Screen unloaded
on_screen_unload_start:
logger.log: Screen unload start
bg_color: light_blue bg_color: light_blue
bottom_layer: bottom_layer:
widgets: widgets:
@@ -660,14 +698,6 @@ lvgl:
logger.log: Child created logger.log: Child created
on_child_delete: on_child_delete:
logger.log: Child deleted logger.log: Child deleted
on_screen_unload_start:
logger.log: Screen unload start
on_screen_load_start:
logger.log: Screen load start
on_screen_load:
logger.log: Screen loaded
on_screen_unload:
logger.log: Screen unloaded
on_size_change: on_size_change:
logger.log: Size changed logger.log: Size changed
on_style_change: on_style_change:
@@ -676,36 +706,6 @@ lvgl:
logger.log: Layout changed logger.log: Layout changed
on_get_self_size: on_get_self_size:
logger.log: Get self size logger.log: Get self size
on_invalidate_area:
logger.log: Invalidate area
on_resolution_change:
logger.log: Resolution changed
on_color_format_change:
logger.log: Color format changed
on_refr_request:
logger.log: Refresh request
on_refr_start:
logger.log: Refresh start
on_refr_ready:
logger.log: Refresh ready
on_render_start:
logger.log: Render start
on_render_ready:
logger.log: Render ready
on_flush_start:
logger.log: Flush start
on_flush_finish:
logger.log: Flush finish
on_flush_wait_start:
logger.log: Flush wait start
on_flush_wait_finish:
logger.log: Flush wait finish
on_update_layout_complete:
logger.log: Update layout complete
on_vsync:
logger.log: Vsync
on_vsync_request:
logger.log: Vsync request
- led: - led:
id: lv_led id: lv_led
color: 0x00FF00 color: 0x00FF00