mirror of
https://github.com/esphome/esphome.git
synced 2026-05-28 21:59:59 +08:00
[lvgl] Allow text substitution for NaN (#11712)
This commit is contained in:
@@ -3,6 +3,8 @@ import re
|
|||||||
from esphome import config_validation as cv
|
from esphome import config_validation as cv
|
||||||
from esphome.const import CONF_ARGS, CONF_FORMAT
|
from esphome.const import CONF_ARGS, CONF_FORMAT
|
||||||
|
|
||||||
|
CONF_IF_NAN = "if_nan"
|
||||||
|
|
||||||
lv_uses = {
|
lv_uses = {
|
||||||
"USER_DATA",
|
"USER_DATA",
|
||||||
"LOG",
|
"LOG",
|
||||||
@@ -21,23 +23,48 @@ lv_fonts_used = set()
|
|||||||
esphome_fonts_used = set()
|
esphome_fonts_used = set()
|
||||||
lvgl_components_required = set()
|
lvgl_components_required = set()
|
||||||
|
|
||||||
|
# noqa
|
||||||
def validate_printf(value):
|
f_regex = re.compile(
|
||||||
cfmt = r"""
|
r"""
|
||||||
( # start of capture group 1
|
( # start of capture group 1
|
||||||
% # literal "%"
|
% # literal "%"
|
||||||
(?:[-+0 #]{0,5}) # optional flags
|
[-+0 #]{0,5} # optional flags
|
||||||
|
(?:\d+|\*)? # width
|
||||||
|
(?:\.(?:\d+|\*))? # precision
|
||||||
|
(?:h|l|ll|w|I|I32|I64)? # size
|
||||||
|
f # type
|
||||||
|
)
|
||||||
|
""",
|
||||||
|
flags=re.VERBOSE,
|
||||||
|
)
|
||||||
|
# noqa
|
||||||
|
c_regex = re.compile(
|
||||||
|
r"""
|
||||||
|
( # start of capture group 1
|
||||||
|
% # literal "%"
|
||||||
|
[-+0 #]{0,5} # optional flags
|
||||||
(?:\d+|\*)? # width
|
(?:\d+|\*)? # width
|
||||||
(?:\.(?:\d+|\*))? # precision
|
(?:\.(?:\d+|\*))? # precision
|
||||||
(?:h|l|ll|w|I|I32|I64)? # size
|
(?:h|l|ll|w|I|I32|I64)? # size
|
||||||
[cCdiouxXeEfgGaAnpsSZ] # type
|
[cCdiouxXeEfgGaAnpsSZ] # type
|
||||||
)
|
)
|
||||||
""" # noqa
|
""",
|
||||||
matches = re.findall(cfmt, value[CONF_FORMAT], flags=re.VERBOSE)
|
flags=re.VERBOSE,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_printf(value):
|
||||||
|
format_string = value[CONF_FORMAT]
|
||||||
|
matches = c_regex.findall(format_string)
|
||||||
if len(matches) != len(value[CONF_ARGS]):
|
if len(matches) != len(value[CONF_ARGS]):
|
||||||
raise cv.Invalid(
|
raise cv.Invalid(
|
||||||
f"Found {len(matches)} printf-patterns ({', '.join(matches)}), but {len(value[CONF_ARGS])} args were given!"
|
f"Found {len(matches)} printf-patterns ({', '.join(matches)}), but {len(value[CONF_ARGS])} args were given!"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if value.get(CONF_IF_NAN) and len(f_regex.findall(format_string)) != 1:
|
||||||
|
raise cv.Invalid(
|
||||||
|
"Use of 'if_nan' requires a single valid printf-pattern of type %f"
|
||||||
|
)
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,13 @@ from .defines import (
|
|||||||
call_lambda,
|
call_lambda,
|
||||||
literal,
|
literal,
|
||||||
)
|
)
|
||||||
from .helpers import add_lv_use, esphome_fonts_used, lv_fonts_used, requires_component
|
from .helpers import (
|
||||||
|
CONF_IF_NAN,
|
||||||
|
add_lv_use,
|
||||||
|
esphome_fonts_used,
|
||||||
|
lv_fonts_used,
|
||||||
|
requires_component,
|
||||||
|
)
|
||||||
from .types import lv_font_t, lv_gradient_t
|
from .types import lv_font_t, lv_gradient_t
|
||||||
|
|
||||||
opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
|
opacity_consts = LvConstant("LV_OPA_", "TRANSP", "COVER")
|
||||||
@@ -412,7 +418,13 @@ class TextValidator(LValidator):
|
|||||||
str_args = [str(x) for x in value[CONF_ARGS]]
|
str_args = [str(x) for x in value[CONF_ARGS]]
|
||||||
arg_expr = cg.RawExpression(",".join(str_args))
|
arg_expr = cg.RawExpression(",".join(str_args))
|
||||||
format_str = cpp_string_escape(format_str)
|
format_str = cpp_string_escape(format_str)
|
||||||
return literal(f"str_sprintf({format_str}, {arg_expr}).c_str()")
|
sprintf_str = f"str_sprintf({format_str}, {arg_expr}).c_str()"
|
||||||
|
if nanval := value.get(CONF_IF_NAN):
|
||||||
|
nanval = cpp_string_escape(nanval)
|
||||||
|
return literal(
|
||||||
|
f"(std::isfinite({arg_expr}) ? {sprintf_str} : {nanval})"
|
||||||
|
)
|
||||||
|
return literal(sprintf_str)
|
||||||
if time_format := value.get(CONF_TIME_FORMAT):
|
if time_format := value.get(CONF_TIME_FORMAT):
|
||||||
source = value[CONF_TIME]
|
source = value[CONF_TIME]
|
||||||
if isinstance(source, Lambda):
|
if isinstance(source, Lambda):
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ from esphome.core.config import StartupTrigger
|
|||||||
|
|
||||||
from . import defines as df, lv_validation as lvalid
|
from . import defines as df, lv_validation as lvalid
|
||||||
from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
|
from .defines import CONF_TIME_FORMAT, LV_GRAD_DIR
|
||||||
from .helpers import requires_component, validate_printf
|
from .helpers import CONF_IF_NAN, requires_component, validate_printf
|
||||||
from .layout import (
|
from .layout import (
|
||||||
FLEX_OBJ_SCHEMA,
|
FLEX_OBJ_SCHEMA,
|
||||||
GRID_CELL_SCHEMA,
|
GRID_CELL_SCHEMA,
|
||||||
@@ -54,6 +54,7 @@ PRINTF_TEXT_SCHEMA = cv.All(
|
|||||||
{
|
{
|
||||||
cv.Required(CONF_FORMAT): cv.string,
|
cv.Required(CONF_FORMAT): cv.string,
|
||||||
cv.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_),
|
cv.Optional(CONF_ARGS, default=list): cv.ensure_list(cv.lambda_),
|
||||||
|
cv.Optional(CONF_IF_NAN): cv.string,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
validate_printf,
|
validate_printf,
|
||||||
|
|||||||
@@ -726,6 +726,12 @@ lvgl:
|
|||||||
- logger.log:
|
- logger.log:
|
||||||
format: "Spinbox value is %f"
|
format: "Spinbox value is %f"
|
||||||
args: [x]
|
args: [x]
|
||||||
|
- lvgl.label.update:
|
||||||
|
id: hello_label
|
||||||
|
text:
|
||||||
|
format: "value is %.1f now"
|
||||||
|
args: [x]
|
||||||
|
if_nan: "Value unknown"
|
||||||
- button:
|
- button:
|
||||||
styles: spin_button
|
styles: spin_button
|
||||||
id: spin_down
|
id: spin_down
|
||||||
|
|||||||
Reference in New Issue
Block a user