Include model-driven display schemas in the language schema dump (#16872)

This commit is contained in:
J. Nick Koston
2026-06-07 17:30:43 -05:00
committed by GitHub
parent 64fc09646c
commit cbc3770b11
7 changed files with 87 additions and 1 deletions
+6 -1
View File
@@ -5,7 +5,11 @@ from esphome import core, pins
import esphome.codegen as cg
from esphome.components import display, spi
from esphome.components.display import CONF_SHOW_TEST_CARD, validate_rotation
from esphome.components.mipi import flatten_sequence, map_sequence
from esphome.components.mipi import (
flatten_sequence,
map_sequence,
model_schema_extractor,
)
import esphome.config_validation as cv
from esphome.config_validation import update_interval
from esphome.const import (
@@ -111,6 +115,7 @@ def model_schema(config):
)
@model_schema_extractor(MODELS, model_schema)
def customise_schema(config):
"""
Create a customised config schema for a specific model and validate the configuration.
+54
View File
@@ -2,8 +2,12 @@
# Various configuration constants for MIPI displays
# Various utility functions for MIPI DBI configuration
from collections.abc import Callable
import functools
from typing import Any, Self
import voluptuous as vol
from esphome.components.const import CONF_COLOR_DEPTH
from esphome.components.display import CONF_SHOW_TEST_CARD, display_ns
import esphome.config_validation as cv
@@ -18,6 +22,7 @@ from esphome.const import (
CONF_LAMBDA,
CONF_MIRROR_X,
CONF_MIRROR_Y,
CONF_MODEL,
CONF_OFFSET_HEIGHT,
CONF_OFFSET_WIDTH,
CONF_PAGES,
@@ -27,6 +32,7 @@ from esphome.const import (
CONF_WIDTH,
)
from esphome.core import TimePeriod
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
LOGGER = cv.logging.getLogger(__name__)
@@ -239,6 +245,54 @@ def delay(ms):
return DELAY_FLAG, ms
# Generic placeholder model present in every DriverChip registry; skipped when
# choosing a representative model for schema extraction.
_CUSTOM_MODEL = "CUSTOM"
def model_schema_extractor(
models: dict[str, Any],
model_schema: Callable[[dict[str, Any]], Any],
extra: dict[str, Any] | None = None,
) -> Callable[[Callable[[Any], Any]], Callable[[Any], Any]]:
"""
Decorate a model-driven display CONFIG_SCHEMA so the language-schema dumper
can extract it.
The schema is generated per ``model`` at validation time, so the static
dumper has nothing to walk. When the dumper passes SCHEMA_EXTRACT, resolve a
representative schema for a real model (the generic "CUSTOM" placeholder
over-constrains fields like init_sequence) plus any *extra* keys the model
needs, e.g. a bus mode, and hand that back; runtime validation is untouched.
"""
def decorate(config_schema: Callable[[Any], Any]) -> Callable[[Any], Any]:
@schema_extractor("schema")
@functools.wraps(config_schema)
def wrapper(config: Any) -> Any:
if config is not SCHEMA_EXTRACT:
return config_schema(config)
names = sorted(models)
representative = next((n for n in names if n != _CUSTOM_MODEL), names[0])
schema = model_schema({CONF_MODEL: representative, **(extra or {})})
if isinstance(schema, vol.All):
schema = next(
(v for v in schema.validators if isinstance(v, vol.Schema)),
schema,
)
if isinstance(schema, vol.Schema):
# The resolved schema pins ``model`` to the representative; expose
# the full model list so the dumped enum offers every model.
schema = schema.extend(
{cv.Required(CONF_MODEL): cv.one_of(*names, upper=True)}
)
return schema
return wrapper
return decorate
class DriverChip:
"""
A class representing a MIPI DBI driver chip model.
+2
View File
@@ -32,6 +32,7 @@ from esphome.components.mipi import (
dimension_schema,
get_color_depth,
map_sequence,
model_schema_extractor,
power_of_two,
requires_buffer,
)
@@ -161,6 +162,7 @@ def model_schema(config):
)
@model_schema_extractor(MODELS, model_schema)
def _config_schema(config):
config = cv.Schema(
{
+2
View File
@@ -30,6 +30,7 @@ from esphome.components.mipi import (
DriverChip,
dimension_schema,
map_sequence,
model_schema_extractor,
power_of_two,
requires_buffer,
)
@@ -219,6 +220,7 @@ def model_schema(config):
return schema
@model_schema_extractor(MODELS, model_schema)
def _config_schema(config):
config = cv.Schema(
{
+2
View File
@@ -22,6 +22,7 @@ from esphome.components.mipi import (
dimension_schema,
get_color_depth,
map_sequence,
model_schema_extractor,
power_of_two,
requires_buffer,
)
@@ -227,6 +228,7 @@ def model_schema(config):
return schema
@model_schema_extractor(MODELS, model_schema, extra={CONF_BUS_MODE: TYPE_SINGLE})
def customise_schema(config):
"""
Create a customised config schema for a specific model and validate the configuration.