mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
[lvgl] Add direct use of mapping (#15863)
This commit is contained in:
@@ -739,6 +739,7 @@ CONF_GRID_ROWS = "grid_rows"
|
||||
CONF_HEADER_BUTTONS = "header_buttons"
|
||||
CONF_HEADER_MODE = "header_mode"
|
||||
CONF_HOME = "home"
|
||||
CONF_IMAGE = "image"
|
||||
CONF_INDICATORS = "indicators"
|
||||
CONF_INITIAL_FOCUS = "initial_focus"
|
||||
CONF_SELECTED_DIGIT = "selected_digit"
|
||||
@@ -752,6 +753,7 @@ CONF_LONG_PRESS_REPEAT_TIME = "long_press_repeat_time"
|
||||
CONF_LVGL_ID = "lvgl_id"
|
||||
CONF_LONG_MODE = "long_mode"
|
||||
CONF_MAJOR_TICKS_STYLE = "major_ticks_style"
|
||||
CONF_MAPPING = "mapping"
|
||||
CONF_MSGBOXES = "msgboxes"
|
||||
CONF_OBJ = "obj"
|
||||
CONF_ONE_CHECKED = "one_checked"
|
||||
|
||||
@@ -22,9 +22,12 @@ from esphome.helpers import cpp_string_escape
|
||||
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
|
||||
from esphome.types import Expression, SafeExpType
|
||||
|
||||
from ..mapping import INDEX_TYPES, get_mapping_metadata
|
||||
from . import types as ty
|
||||
from .defines import (
|
||||
CONF_END_VALUE,
|
||||
CONF_IMAGE,
|
||||
CONF_MAPPING,
|
||||
CONF_START_VALUE,
|
||||
CONF_TIME_FORMAT,
|
||||
LV_FONTS,
|
||||
@@ -375,21 +378,54 @@ def stop_value(value):
|
||||
return cv.int_range(0, 255)(value)
|
||||
|
||||
|
||||
def image_validator(value):
|
||||
value = cv.requires_component("image")(value)
|
||||
def _image_validator(value):
|
||||
if isinstance(value, dict) and CONF_MAPPING in value:
|
||||
from .schemas import MAPPING_IMAGE_SCHEMA
|
||||
|
||||
return MAPPING_IMAGE_SCHEMA(value)
|
||||
value = cv.use_id(Image_)(value)
|
||||
get_lv_images_used().add(value)
|
||||
add_lv_use("label")
|
||||
return value
|
||||
|
||||
|
||||
lv_image = LValidator(
|
||||
image_validator,
|
||||
image.Image_.operator("ptr"),
|
||||
requires="image",
|
||||
)
|
||||
class ImageValidator(LValidator):
|
||||
def __init__(self):
|
||||
super().__init__(
|
||||
validator=_image_validator,
|
||||
rtype=image.Image_.operator("ptr"),
|
||||
requires=CONF_IMAGE,
|
||||
)
|
||||
|
||||
async def process(
|
||||
self, value: Any, args: list[tuple[SafeExpType, str]] | None = None
|
||||
) -> Expression:
|
||||
# Local import to avoid circular import at module level
|
||||
from .lvcode import get_lambda_context_args
|
||||
|
||||
args = args or get_lambda_context_args()
|
||||
if isinstance(value, dict) and CONF_MAPPING in value:
|
||||
mapping_id = value[CONF_MAPPING]
|
||||
mapping_var = await cg.get_variable(mapping_id)
|
||||
metadata = get_mapping_metadata(mapping_id.id)
|
||||
index = value[CONF_VALUE]
|
||||
if isinstance(index, Lambda):
|
||||
index = call_lambda(
|
||||
await cg.process_lambda(
|
||||
index, args, return_type=metadata.from_.data_type
|
||||
)
|
||||
)
|
||||
else:
|
||||
index = await metadata.from_.convert_value(index)
|
||||
return mapping_var.get(index)
|
||||
|
||||
return await super().process(value, args)
|
||||
|
||||
|
||||
lv_image = ImageValidator()
|
||||
|
||||
lv_image_list = LValidator(
|
||||
cv.ensure_list(image_validator),
|
||||
cv.ensure_list(_image_validator),
|
||||
cg.std_vector.template(image.Image_.operator("ptr")),
|
||||
requires="image",
|
||||
)
|
||||
@@ -440,6 +476,24 @@ class TextValidator(LValidator):
|
||||
f"(std::isfinite({arg_expr}) ? {sprintf_str} : {nanval})"
|
||||
)
|
||||
return literal(sprintf_str)
|
||||
if mapping_id := value.get(CONF_MAPPING):
|
||||
mapping_var = await cg.get_variable(mapping_id)
|
||||
metadata = get_mapping_metadata(mapping_id.id)
|
||||
if metadata.to_ != INDEX_TYPES["string"]:
|
||||
raise ValueError(
|
||||
f"Mapping {mapping_id} does not map to strings, cannot use in text"
|
||||
)
|
||||
index = value[CONF_VALUE]
|
||||
if isinstance(index, Lambda):
|
||||
index = call_lambda(
|
||||
await cg.process_lambda(
|
||||
index, args, return_type=metadata.from_.data_type
|
||||
)
|
||||
)
|
||||
else:
|
||||
index = await metadata.from_.convert_value(index)
|
||||
return mapping_var.get(index).c_str()
|
||||
|
||||
if time_format := value.get(CONF_TIME_FORMAT):
|
||||
source = value[CONF_TIME]
|
||||
if isinstance(source, Lambda):
|
||||
|
||||
@@ -3,6 +3,7 @@ from typing import Any
|
||||
|
||||
from esphome import config_validation as cv
|
||||
from esphome.automation import Trigger, validate_automation
|
||||
from esphome.components.mapping import mapping_class
|
||||
from esphome.components.time import RealTimeClock
|
||||
from esphome.config_validation import prepend_path
|
||||
from esphome.const import (
|
||||
@@ -17,6 +18,7 @@ from esphome.const import (
|
||||
CONF_TEXT,
|
||||
CONF_TIME,
|
||||
CONF_TRIGGER_ID,
|
||||
CONF_VALUE,
|
||||
CONF_X,
|
||||
CONF_Y,
|
||||
)
|
||||
@@ -31,6 +33,7 @@ from esphome.schema_extractors import (
|
||||
from . import defines as df, lv_validation as lvalid
|
||||
from .defines import (
|
||||
CONF_EXT_CLICK_AREA,
|
||||
CONF_MAPPING,
|
||||
CONF_SCROLL_DIR,
|
||||
CONF_SCROLL_SNAP_X,
|
||||
CONF_SCROLL_SNAP_Y,
|
||||
@@ -89,6 +92,20 @@ PRINTF_TEXT_SCHEMA = cv.All(
|
||||
validate_printf,
|
||||
)
|
||||
|
||||
MAPPING_TEXT_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MAPPING): cv.use_id(mapping_class),
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.string),
|
||||
}
|
||||
)
|
||||
|
||||
MAPPING_IMAGE_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_MAPPING): cv.use_id(mapping_class),
|
||||
cv.Required(CONF_VALUE): cv.templatable(cv.string),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _validate_text(value):
|
||||
"""
|
||||
@@ -100,6 +117,8 @@ def _validate_text(value):
|
||||
if isinstance(value, dict):
|
||||
if CONF_TIME_FORMAT in value:
|
||||
return TIME_TEXT_SCHEMA(value)
|
||||
if CONF_MAPPING in value:
|
||||
return MAPPING_TEXT_SCHEMA(value)
|
||||
return PRINTF_TEXT_SCHEMA(value)
|
||||
|
||||
return cv.templatable(cv.string)(value)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from esphome.components.image import INSTANCE_TYPE as IMAGE_TYPE
|
||||
from esphome.components.mapping import get_mapping_metadata
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_ANGLE,
|
||||
@@ -9,7 +11,9 @@ from esphome.const import (
|
||||
|
||||
from ..defines import (
|
||||
CONF_ANTIALIAS,
|
||||
CONF_IMAGE,
|
||||
CONF_MAIN,
|
||||
CONF_MAPPING,
|
||||
CONF_PIVOT_X,
|
||||
CONF_PIVOT_Y,
|
||||
CONF_SCALE,
|
||||
@@ -21,8 +25,6 @@ from ..types import lv_image_t
|
||||
from . import Widget, WidgetType
|
||||
from .label import CONF_LABEL
|
||||
|
||||
CONF_IMAGE = "image"
|
||||
|
||||
BASE_IMG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Optional(CONF_PIVOT_X): size,
|
||||
@@ -69,5 +71,16 @@ class ImgType(WidgetType):
|
||||
for prop, validator in BASE_IMG_SCHEMA.schema.items():
|
||||
await w.set_property(prop, config, processor=validator)
|
||||
|
||||
def final_validate(self, widget, update_config, widget_config, path):
|
||||
src = update_config.get(CONF_SRC)
|
||||
if isinstance(src, dict) and CONF_MAPPING in src:
|
||||
mapping_id = src[CONF_MAPPING]
|
||||
metadata = get_mapping_metadata(mapping_id.id)
|
||||
if str(metadata.to_.data_type) != str(IMAGE_TYPE):
|
||||
raise cv.Invalid(
|
||||
f"Mapping '{mapping_id}' does not map to an image type, but '{metadata.to_.data_type}'",
|
||||
path=path + [CONF_SRC, CONF_MAPPING],
|
||||
)
|
||||
|
||||
|
||||
img_spec = ImgType()
|
||||
|
||||
@@ -91,8 +91,8 @@ binary_sensor:
|
||||
animation: move_right
|
||||
time: 600ms
|
||||
- platform: lvgl
|
||||
id: button_checker
|
||||
name: LVGL button
|
||||
id: common_button_checker
|
||||
name: Common button
|
||||
widget: spin_up
|
||||
on_state:
|
||||
then:
|
||||
|
||||
@@ -263,6 +263,9 @@ lvgl:
|
||||
bg_opa: !lambda return 0.5;
|
||||
- lvgl.image.update:
|
||||
id: lv_image
|
||||
src:
|
||||
mapping: image_map
|
||||
value: !lambda return round(1.0);
|
||||
scale: !lambda return 512;
|
||||
rotation: !lambda return 100;
|
||||
pivot_x: !lambda return 20;
|
||||
@@ -388,9 +391,16 @@ lvgl:
|
||||
text_font: montserrat_40
|
||||
border_post: true
|
||||
on_press:
|
||||
lvgl.label.update:
|
||||
id: hello_label
|
||||
text: Goodbye
|
||||
- lvgl.label.update:
|
||||
id: hello_label
|
||||
text:
|
||||
mapping: lvgl_string_map
|
||||
value: !lambda return 2;
|
||||
- lvgl.label.update:
|
||||
id: hello_label
|
||||
text:
|
||||
mapping: lvgl_string_map
|
||||
value: 2
|
||||
on_click:
|
||||
then:
|
||||
- lvgl.animimg.stop: anim_img
|
||||
@@ -1496,6 +1506,21 @@ image:
|
||||
invert_alpha: true
|
||||
transparency: alpha_channel
|
||||
|
||||
mapping:
|
||||
- id: image_map
|
||||
from: int
|
||||
to: image
|
||||
entries:
|
||||
0: cat_image
|
||||
1: dog_image
|
||||
- id: lvgl_string_map
|
||||
from: int
|
||||
to: string
|
||||
entries:
|
||||
0: "First"
|
||||
1: "Second"
|
||||
2: "Third"
|
||||
|
||||
color:
|
||||
- id: light_blue
|
||||
hex: "3340FF"
|
||||
|
||||
Reference in New Issue
Block a user