[core] Add type annotations to component Python (2/11) (#18339)

Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
Jesse Hills
2026-08-20 14:26:16 +00:00
committed by GitHub
co-authored by Jonathan Swoboda
parent 347a6155f8
commit ecca240eef
40 changed files with 220 additions and 125 deletions
+10 -2
View File
@@ -13,6 +13,9 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_PARTS_PER_MILLION, UNIT_PARTS_PER_MILLION,
) )
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
CODEOWNERS = ["@andrewjswan"] CODEOWNERS = ["@andrewjswan"]
@@ -44,7 +47,7 @@ CONFIG_SCHEMA = (
) )
async def to_code(config) -> None: async def to_code(config: ConfigType) -> None:
"""Code generation entry point.""" """Code generation entry point."""
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
@@ -67,7 +70,12 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
CALIBRATION_ACTION_SCHEMA, CALIBRATION_ACTION_SCHEMA,
synchronous=True, synchronous=True,
) )
async def cm1106_calibration_to_code(config, action_id, template_arg, args) -> None: async def cm1106_calibration_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
"""Service code generation entry point.""" """Service code generation entry point."""
paren = await cg.get_variable(config[CONF_ID]) paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren) return cg.new_Pvariable(action_id, template_arg, paren)
+16 -6
View File
@@ -1,9 +1,14 @@
from typing import Any
from esphome.automation import Action, register_action from esphome.automation import Action, register_action
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import VARIANT_ESP32P4, only_on_variant from esphome.components.esp32 import VARIANT_ESP32P4, only_on_variant
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_CHANNEL, CONF_ID, CONF_VOLTAGE from esphome.const import CONF_CHANNEL, CONF_ID, CONF_VOLTAGE
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
CODEOWNERS = ["@clydebarrow"] CODEOWNERS = ["@clydebarrow"]
@@ -22,7 +27,7 @@ CONF_PASSTHROUGH = "passthrough"
adjusted_ids = set() adjusted_ids = set()
def validate_ldo_voltage(value): def validate_ldo_voltage(value: Any) -> str | float:
if isinstance(value, str) and value.lower() == CONF_PASSTHROUGH: if isinstance(value, str) and value.lower() == CONF_PASSTHROUGH:
return CONF_PASSTHROUGH return CONF_PASSTHROUGH
value = cv.voltage(value) value = cv.voltage(value)
@@ -33,7 +38,7 @@ def validate_ldo_voltage(value):
) )
def validate_ldo_config(config): def validate_ldo_config(config: ConfigType) -> ConfigType:
channel = config[CONF_CHANNEL] channel = config[CONF_CHANNEL]
allow_internal = config[CONF_ALLOW_INTERNAL_CHANNEL] allow_internal = config[CONF_ALLOW_INTERNAL_CHANNEL]
if allow_internal and channel not in CHANNELS_INTERNAL: if allow_internal and channel not in CHANNELS_INTERNAL:
@@ -77,7 +82,7 @@ CONFIG_SCHEMA = cv.All(
) )
async def to_code(configs): async def to_code(configs: list[ConfigType]) -> None:
for config in configs: for config in configs:
var = cg.new_Pvariable(config[CONF_ID], config[CONF_CHANNEL]) var = cg.new_Pvariable(config[CONF_ID], config[CONF_CHANNEL])
await cg.register_component(var, config) await cg.register_component(var, config)
@@ -89,7 +94,7 @@ async def to_code(configs):
cg.add(var.set_adjustable(config[CONF_ADJUSTABLE])) cg.add(var.set_adjustable(config[CONF_ADJUSTABLE]))
def final_validate(configs): def final_validate(configs: list[ConfigType]) -> None:
for channel in CHANNELS: for channel in CHANNELS:
used = [config for config in configs if config[CONF_CHANNEL] == channel] used = [config for config in configs if config[CONF_CHANNEL] == channel]
if len(used) > 1: if len(used) > 1:
@@ -112,7 +117,7 @@ def final_validate(configs):
FINAL_VALIDATE_SCHEMA = final_validate FINAL_VALIDATE_SCHEMA = final_validate
def adjusted_ldo_id(value): def adjusted_ldo_id(value: Any) -> ID:
value = cv.use_id(EspLdo)(value) value = cv.use_id(EspLdo)(value)
adjusted_ids.add(value) adjusted_ids.add(value)
return value return value
@@ -131,7 +136,12 @@ def adjusted_ldo_id(value):
), ),
synchronous=True, synchronous=True,
) )
async def ldo_voltage_adjust_to_code(config, action_id, template_arg, args): async def ldo_voltage_adjust_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
parent = await cg.get_variable(config[CONF_ID]) parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, parent) var = cg.new_Pvariable(action_id, template_arg, parent)
template_ = await cg.templatable(config[CONF_VOLTAGE], args, cg.float_) template_ = await cg.templatable(config[CONF_VOLTAGE], args, cg.float_)
+7 -6
View File
@@ -31,6 +31,7 @@ from esphome.const import (
) )
from esphome.core import CORE, HexInt from esphome.core import CORE, HexInt
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
DEPENDENCIES = ["spi"] DEPENDENCIES = ["spi"]
@@ -91,7 +92,7 @@ CONF_INVERT_DISPLAY = "invert_display"
CONF_PIXEL_MODE = "pixel_mode" CONF_PIXEL_MODE = "pixel_mode"
def cmd(c, *args): def cmd(c: int, *args: int) -> list[int]:
""" """
Create a command sequence Create a command sequence
:param c: The command (8 bit) :param c: The command (8 bit)
@@ -101,7 +102,7 @@ def cmd(c, *args):
return [c, len(args)] + list(args) return [c, len(args)] + list(args)
def map_sequence(value): def map_sequence(value: list[int]) -> list[int]:
""" """
An initialisation sequence is a literal array of data bytes. An initialisation sequence is a literal array of data bytes.
The format is a repeated sequence of [CMD, <data>] The format is a repeated sequence of [CMD, <data>]
@@ -111,7 +112,7 @@ def map_sequence(value):
return cmd(*value) return cmd(*value)
def _validate(config): def _validate(config: ConfigType) -> ConfigType:
if ( if (
config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE" config.get(CONF_COLOR_PALETTE) == "IMAGE_ADAPTIVE"
and CONF_COLOR_PALETTE_IMAGES not in config and CONF_COLOR_PALETTE_IMAGES not in config
@@ -196,7 +197,7 @@ CONFIG_SCHEMA = cv.All(
) )
def final_validate(config): def final_validate(config: ConfigType) -> None:
global_config = full_config.get() global_config = full_config.get()
# Ideally would calculate buffer size here, but that info is not available on the Python side # Ideally would calculate buffer size here, but that info is not available on the Python side
needs_buffer = ( needs_buffer = (
@@ -218,7 +219,7 @@ def final_validate(config):
FINAL_VALIDATE_SCHEMA = final_validate FINAL_VALIDATE_SCHEMA = final_validate
async def to_code(config): async def to_code(config: ConfigType) -> None:
LOGGER.warning( LOGGER.warning(
"The 'ili9xxx' component is deprecated, it is recommended to use 'mipi_spi' instead." "The 'ili9xxx' component is deprecated, it is recommended to use 'mipi_spi' instead."
) )
@@ -278,7 +279,7 @@ async def to_code(config):
cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED)) cg.add(var.set_buffer_color_mode(ILI9XXXColorMode.BITS_8_INDEXED))
from PIL import Image from PIL import Image
def load_image(filename): def load_image(filename: str) -> Image.Image:
path = CORE.relative_config_path(filename) path = CORE.relative_config_path(filename)
try: try:
return Image.open(path) return Image.open(path)
+22 -10
View File
@@ -2,6 +2,9 @@
ESPHome configuration for the IT8951 e-paper controller. ESPHome configuration for the IT8951 e-paper controller.
""" """
from collections.abc import Callable
from typing import Any
from esphome import automation, core, pins from esphome import automation, core, pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import display, spi from esphome.components import display, spi
@@ -33,8 +36,10 @@ from esphome.const import (
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.cpp_generator import RawExpression from esphome.core import ID
from esphome.cpp_generator import MockObj, RawExpression, TemplateArgsType
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
AUTO_LOAD = ["split_buffer"] AUTO_LOAD = ["split_buffer"]
DEPENDENCIES = ["spi"] DEPENDENCIES = ["spi"]
@@ -97,16 +102,16 @@ class IT8951Model:
models: dict[str, "IT8951Model"] = {} models: dict[str, "IT8951Model"] = {}
def __init__(self, name: str, **defaults): def __init__(self, name: str, **defaults: Any) -> None:
name = name.upper() name = name.upper()
self.name = name self.name = name
self.defaults = defaults self.defaults = defaults
IT8951Model.models[name] = self IT8951Model.models[name] = self
def get_default(self, key, fallback=None): def get_default(self, key: str, fallback: Any = None) -> Any:
return self.defaults.get(key, fallback) return self.defaults.get(key, fallback)
def get_dimensions(self, config) -> tuple[int, int]: def get_dimensions(self, config: ConfigType) -> tuple[int, int]:
# If dimensions are in config, use them; otherwise fall back to model defaults. # If dimensions are in config, use them; otherwise fall back to model defaults.
if CONF_DIMENSIONS in config: if CONF_DIMENSIONS in config:
dimensions = config[CONF_DIMENSIONS] dimensions = config[CONF_DIMENSIONS]
@@ -181,14 +186,16 @@ DIMENSION_SCHEMA = cv.Schema(
) )
def _model_pin_option(model, key, schema): def _model_pin_option(
model: IT8951Model, key: str, schema: Callable[[Any], Any]
) -> tuple[cv.Optional | cv.Required, Callable[[Any], Any]]:
default = model.get_default(key) default = model.get_default(key)
if default is None: if default is None:
return cv.Required(key), schema return cv.Required(key), schema
return cv.Optional(key, default=default), schema return cv.Optional(key, default=default), schema
def _model_schema(config): def _model_schema(config: ConfigType) -> cv.Schema:
model = IT8951Model.models[config[CONF_MODEL]] model = IT8951Model.models[config[CONF_MODEL]]
has_default_dimensions = ( has_default_dimensions = (
model.get_default(CONF_WIDTH) is not None model.get_default(CONF_WIDTH) is not None
@@ -293,7 +300,7 @@ def _model_schema(config):
return schema.extend(pin_extra) return schema.extend(pin_extra)
def _customise_schema(config): def _customise_schema(config: ConfigType) -> ConfigType:
config = cv.Schema( config = cv.Schema(
{ {
cv.Required(CONF_MODEL): cv.one_of( cv.Required(CONF_MODEL): cv.one_of(
@@ -336,7 +343,7 @@ def _customise_schema(config):
CONFIG_SCHEMA = _customise_schema CONFIG_SCHEMA = _customise_schema
def _final_validate(config) -> None: def _final_validate(config: ConfigType) -> None:
# IT8951 reads from SPI (DevInfo, VCOM, register reads) so MISO is required. # IT8951 reads from SPI (DevInfo, VCOM, register reads) so MISO is required.
spi.final_validate_device_schema("it8951", require_miso=True, require_mosi=True)( spi.final_validate_device_schema("it8951", require_miso=True, require_mosi=True)(
config config
@@ -356,7 +363,7 @@ def _final_validate(config) -> None:
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config: ConfigType) -> None:
model = IT8951Model.models[config[CONF_MODEL]] model = IT8951Model.models[config[CONF_MODEL]]
width, height = model.get_dimensions(config) width, height = model.get_dimensions(config)
@@ -423,7 +430,12 @@ async def to_code(config):
), ),
synchronous=True, synchronous=True,
) )
async def it8951_update_action_to_code(config, action_id, template_arg, args): async def it8951_update_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
display_var = await cg.get_variable(config[CONF_ID]) display_var = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, display_var) var = cg.new_Pvariable(action_id, template_arg, display_var)
if mode := config.get(CONF_MODE): if mode := config.get(CONF_MODE):
+11 -6
View File
@@ -1,5 +1,6 @@
from collections.abc import Callable from collections.abc import Callable
import difflib import difflib
from typing import Any
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.const import KEY_METADATA from esphome.components.const import KEY_METADATA
@@ -13,6 +14,7 @@ from esphome.cpp_generator import (
add_global, add_global,
) )
from esphome.loader import get_component from esphome.loader import get_component
from esphome.types import ConfigType
CODEOWNERS = ["@clydebarrow"] CODEOWNERS = ["@clydebarrow"]
MULTI_CONF = True MULTI_CONF = True
@@ -32,13 +34,16 @@ class IndexType:
""" """
def __init__( def __init__(
self, validator: Callable, data_type: MockObj, conversion: Callable = None self,
validator: Callable,
data_type: MockObj,
conversion: Callable | None = None,
) -> None: ) -> None:
self.validator = validator self.validator = validator
self.data_type = data_type self.data_type = data_type
self.conversion = conversion self.conversion = conversion
async def convert_value(self, value): async def convert_value(self, value: Any) -> Any:
if self.conversion: if self.conversion:
return self.conversion(value) return self.conversion(value)
return await cg.get_variable(value) return await cg.get_variable(value)
@@ -60,7 +65,7 @@ class MappingMetaData:
self.to_ = to_ self.to_ = to_
def to_schema(value): def to_schema(value: Any) -> str:
""" """
Generate a schema for the 'to' field of a map. This can be either one of the index types or a class name. Generate a schema for the 'to' field of a map. This can be either one of the index types or a class name.
:param value: :param value:
@@ -82,7 +87,7 @@ BASE_SCHEMA = cv.Schema(
) )
def get_object_type(to_) -> MockObjClass | None: def get_object_type(to_: str) -> MockObjClass | None:
""" """
Get the object type from a string. Possible formats: Get the object type from a string. Possible formats:
xxx The name of a component which defines INSTANCE_TYPE xxx The name of a component which defines INSTANCE_TYPE
@@ -121,7 +126,7 @@ def add_metadata(
get_all_mapping_metadata()[mapping_id.id] = MappingMetaData(from_, to_) get_all_mapping_metadata()[mapping_id.id] = MappingMetaData(from_, to_)
def map_schema(config): def map_schema(config: ConfigType) -> ConfigType:
config = BASE_SCHEMA(config) config = BASE_SCHEMA(config)
if CONF_ENTRIES not in config or not isinstance(config[CONF_ENTRIES], dict): if CONF_ENTRIES not in config or not isinstance(config[CONF_ENTRIES], dict):
raise cv.Invalid("an entries dictionary is required for a mapping") raise cv.Invalid("an entries dictionary is required for a mapping")
@@ -163,7 +168,7 @@ def map_schema(config):
CONFIG_SCHEMA = map_schema CONFIG_SCHEMA = map_schema
async def to_code(config): async def to_code(config: ConfigType) -> MockObj:
varid = config[CONF_ID] varid = config[CONF_ID]
metadata = get_mapping_metadata(varid.id) metadata = get_mapping_metadata(varid.id)
entries = { entries = {
+5 -4
View File
@@ -53,6 +53,7 @@ from esphome.const import (
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
from . import mipi_dsi_ns, models from . import mipi_dsi_ns, models
from .models import DsiDriverChip from .models import DsiDriverChip
@@ -85,7 +86,7 @@ COLOR_DEPTHS = {
} }
def model_schema(config): def model_schema(config: ConfigType) -> cv.All:
model = MODELS[config[CONF_MODEL].upper()] model = MODELS[config[CONF_MODEL].upper()]
transform = model.transform_schema() transform = model.transform_schema()
# CUSTOM model will need to provide a custom init sequence # CUSTOM model will need to provide a custom init sequence
@@ -148,7 +149,7 @@ def model_schema(config):
@model_schema_extractor(MODELS, model_schema) @model_schema_extractor(MODELS, model_schema)
def _config_schema(config): def _config_schema(config: ConfigType) -> ConfigType:
config = cv.Schema( config = cv.Schema(
{ {
cv.Required(CONF_MODEL): cv.one_of(*MODELS, upper=True), cv.Required(CONF_MODEL): cv.one_of(*MODELS, upper=True),
@@ -175,7 +176,7 @@ def _config_schema(config):
return config return config
def _final_validate(config) -> None: def _final_validate(config: ConfigType) -> None:
global_config = full_config.get() global_config = full_config.get()
from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN
@@ -189,7 +190,7 @@ CONFIG_SCHEMA = _config_schema
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config: ConfigType) -> None:
model = MODELS[config[CONF_MODEL].upper()] model = MODELS[config[CONF_MODEL].upper()]
color_depth = COLOR_DEPTHS[get_color_depth(config)] color_depth = COLOR_DEPTHS[get_color_depth(config)]
pixel_mode = int(config[CONF_PIXEL_MODE].removesuffix("bit")) pixel_mode = int(config[CONF_PIXEL_MODE].removesuffix("bit"))
+8 -6
View File
@@ -1,5 +1,6 @@
import importlib import importlib
import pkgutil import pkgutil
from typing import Any
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
@@ -72,6 +73,7 @@ from esphome.const import (
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
from . import models from . import models
from .models import RgbDriverChip from .models import RgbDriverChip
@@ -97,7 +99,7 @@ for module_info in pkgutil.iter_modules(models.__path__):
MODELS = DriverChip.get_models() MODELS = DriverChip.get_models()
def data_pin_validate(value): def data_pin_validate(value: Any) -> ConfigType:
""" """
It is safe to use strapping pins as RGB output data bits, as they are outputs only, It is safe to use strapping pins as RGB output data bits, as they are outputs only,
and not initialised until after boot. and not initialised until after boot.
@@ -112,14 +114,14 @@ def data_pin_validate(value):
return DATA_PIN_SCHEMA(value) return DATA_PIN_SCHEMA(value)
def data_pin_set(length): def data_pin_set(length: int) -> cv.All:
return cv.All( return cv.All(
[data_pin_validate], [data_pin_validate],
cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"), cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"),
) )
def model_schema(config): def model_schema(config: ConfigType) -> cv.Schema:
model = MODELS[config[CONF_MODEL].upper()] model = MODELS[config[CONF_MODEL].upper()]
transform = model.transform_schema() transform = model.transform_schema()
# RPI model does not use an init sequence, indicates with empty list # RPI model does not use an init sequence, indicates with empty list
@@ -213,7 +215,7 @@ def model_schema(config):
@model_schema_extractor(MODELS, model_schema) @model_schema_extractor(MODELS, model_schema)
def _config_schema(config): def _config_schema(config: ConfigType) -> ConfigType:
config = cv.Schema( config = cv.Schema(
{ {
cv.Required(CONF_MODEL): cv.one_of(*MODELS, upper=True), cv.Required(CONF_MODEL): cv.one_of(*MODELS, upper=True),
@@ -248,7 +250,7 @@ def _config_schema(config):
CONFIG_SCHEMA = _config_schema CONFIG_SCHEMA = _config_schema
def _final_validate(config) -> None: def _final_validate(config: ConfigType) -> None:
global_config = full_config.get() global_config = full_config.get()
from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN from esphome.components.lvgl import DOMAIN as LVGL_DOMAIN
@@ -265,7 +267,7 @@ def _final_validate(config) -> None:
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config: ConfigType) -> None:
model = MODELS[config[CONF_MODEL].upper()] model = MODELS[config[CONF_MODEL].upper()]
width, height, _offset_width, _offset_height, _pad_width, _pad_height = ( width, height, _offset_width, _offset_height, _pad_width, _pad_height = (
model.get_dimensions(config) model.get_dimensions(config)
@@ -8,7 +8,7 @@ SDIR_CMD = 0xC7
class ST7701S(RgbDriverChip): class ST7701S(RgbDriverChip):
# The ST7701s does not use the standard MADCTL bits for x/y mirroring # The ST7701s does not use the standard MADCTL bits for x/y mirroring
def add_madctl(self, sequence: list, config: dict): def add_madctl(self, sequence: list, config: dict) -> int:
transform = self.get_transform(config) transform = self.get_transform(config)
madctl = 0x00 madctl = 0x00
if config[CONF_COLOR_ORDER] == MODE_BGR: if config[CONF_COLOR_ORDER] == MODE_BGR:
+8 -7
View File
@@ -53,8 +53,9 @@ from esphome.const import (
CONF_TRANSFORM, CONF_TRANSFORM,
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.cpp_generator import TemplateArguments from esphome.cpp_generator import MockObjClass, TemplateArguments
from esphome.final_validate import full_config from esphome.final_validate import full_config
from esphome.types import ConfigType
from . import CONF_BUS_MODE, CONF_SPI_16, DOMAIN, models from . import CONF_BUS_MODE, CONF_SPI_16, DOMAIN, models
@@ -110,7 +111,7 @@ DISPLAY_PIXEL_MODES = {
} }
def denominator(config): def denominator(config: ConfigType) -> int:
""" """
Calculate the best denominator for a buffer size fraction. Calculate the best denominator for a buffer size fraction.
The denominator should be a number between 2 and 16 that divides the display height evenly, The denominator should be a number between 2 and 16 that divides the display height evenly,
@@ -132,7 +133,7 @@ def denominator(config):
return next(x for x in range(2, 17) if frac >= 1 / x) return next(x for x in range(2, 17) if frac >= 1 / x)
def model_schema(config): def model_schema(config: ConfigType) -> cv.All | cv.Schema:
model = MODELS[config[CONF_MODEL]] model = MODELS[config[CONF_MODEL]]
bus_mode = config[CONF_BUS_MODE] bus_mode = config[CONF_BUS_MODE]
transform = model.transform_schema() transform = model.transform_schema()
@@ -238,7 +239,7 @@ def model_schema(config):
@model_schema_extractor(MODELS, model_schema, extra={CONF_BUS_MODE: TYPE_SINGLE}) @model_schema_extractor(MODELS, model_schema, extra={CONF_BUS_MODE: TYPE_SINGLE})
def customise_schema(config): def customise_schema(config: ConfigType) -> ConfigType:
""" """
Create a customised config schema for a specific model and validate the configuration. Create a customised config schema for a specific model and validate the configuration.
:param config: The configuration dictionary to validate :param config: The configuration dictionary to validate
@@ -305,7 +306,7 @@ def customise_schema(config):
CONFIG_SCHEMA = customise_schema CONFIG_SCHEMA = customise_schema
def _final_validate(config): def _final_validate(config: ConfigType) -> None:
global_config = full_config.get() global_config = full_config.get()
model = MODELS[config[CONF_MODEL]] model = MODELS[config[CONF_MODEL]]
@@ -341,7 +342,7 @@ def _final_validate(config):
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
def get_instance(config): def get_instance(config: ConfigType) -> tuple[MockObjClass, list]:
""" """
Get the type of MipiSpi instance to create based on the configuration, Get the type of MipiSpi instance to create based on the configuration,
and the template arguments. and the template arguments.
@@ -394,7 +395,7 @@ def get_instance(config):
return MipiSpi, templateargs return MipiSpi, templateargs
async def to_code(config): async def to_code(config: ConfigType) -> None:
model = MODELS[config[CONF_MODEL]] model = MODELS[config[CONF_MODEL]]
var_id = config[CONF_ID] var_id = config[CONF_ID]
init_sequence = model.get_sequence(config, add_madctl=False, add_reset=True) init_sequence = model.get_sequence(config, add_madctl=False, add_reset=True)
+8 -2
View File
@@ -6,7 +6,8 @@ from esphome.components.http_request import CONF_HTTP_REQUEST_ID, HttpRequestCom
from esphome.components.image import CONF_TRANSPARENCY, add_metadata from esphome.components.image import CONF_TRANSPARENCY, add_metadata
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_ON_ERROR, CONF_TYPE, CONF_URL from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_ON_ERROR, CONF_TYPE, CONF_URL
from esphome.core import Lambda from esphome.core import ID, Lambda
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType from esphome.types import ConfigType
AUTO_LOAD = ["runtime_image"] AUTO_LOAD = ["runtime_image"]
@@ -89,7 +90,12 @@ RELEASE_IMAGE_SCHEMA = automation.maybe_simple_id(
RELEASE_IMAGE_SCHEMA, RELEASE_IMAGE_SCHEMA,
synchronous=True, synchronous=True,
) )
async def online_image_action_to_code(config, action_id, template_arg, args): async def online_image_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID]) paren = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, paren) var = cg.new_Pvariable(action_id, template_arg, paren)
+15 -12
View File
@@ -1,7 +1,9 @@
"""ESPHome packet transport component.""" """ESPHome packet transport component."""
from collections.abc import Callable, Iterator
import hashlib import hashlib
import logging import logging
from typing import Any
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.binary_sensor import BinarySensor from esphome.components.binary_sensor import BinarySensor
@@ -17,8 +19,9 @@ from esphome.const import (
CONF_PLATFORM, CONF_PLATFORM,
CONF_SENSORS, CONF_SENSORS,
) )
from esphome.core import CORE from esphome.core import CORE, ID
from esphome.cpp_generator import MockObjClass from esphome.cpp_generator import MockObj, MockObjClass
from esphome.types import ConfigType
CODEOWNERS = ["@clydebarrow"] CODEOWNERS = ["@clydebarrow"]
AUTO_LOAD = ["xxtea"] AUTO_LOAD = ["xxtea"]
@@ -43,7 +46,7 @@ CONF_TRANSPORT_ID = "transport_id"
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
def sensor_validation(cls: MockObjClass): def sensor_validation(cls: MockObjClass) -> Callable[[Any], Any]:
return cv.maybe_simple_value( return cv.maybe_simple_value(
cv.Schema( cv.Schema(
{ {
@@ -55,7 +58,7 @@ def sensor_validation(cls: MockObjClass):
) )
def provider_name_validate(value): def provider_name_validate(value: Any) -> str:
value = cv.valid_name(value) value = cv.valid_name(value)
if "_" in value: if "_" in value:
_LOGGER.warning( _LOGGER.warning(
@@ -83,7 +86,7 @@ PROVIDER_SCHEMA = cv.Schema(
).extend(ENCRYPTION_SCHEMA) ).extend(ENCRYPTION_SCHEMA)
def validate_(config): def validate_(config: ConfigType) -> ConfigType:
if CONF_ENCRYPTION in config: if CONF_ENCRYPTION in config:
if CONF_SENSORS not in config and CONF_BINARY_SENSORS not in config: if CONF_SENSORS not in config and CONF_BINARY_SENSORS not in config:
raise cv.Invalid("No sensors or binary sensors to encrypt") raise cv.Invalid("No sensors or binary sensors to encrypt")
@@ -117,11 +120,11 @@ TRANSPORT_SCHEMA = (
) )
def transport_schema(cls): def transport_schema(cls: MockObjClass) -> cv.Schema:
return TRANSPORT_SCHEMA.extend({cv.GenerateID(): cv.declare_id(cls)}) return TRANSPORT_SCHEMA.extend({cv.GenerateID(): cv.declare_id(cls)})
def get_sensors(transport_id): def get_sensors(transport_id: ID) -> Iterator[ConfigType]:
"""Return the list of sensors for this platform.""" """Return the list of sensors for this platform."""
return ( return (
sensor sensor
@@ -130,7 +133,7 @@ def get_sensors(transport_id):
) )
def validate_packet_transport_sensor(config): def validate_packet_transport_sensor(config: ConfigType) -> ConfigType:
if CONF_NAME in config and CONF_INTERNAL not in config: if CONF_NAME in config and CONF_INTERNAL not in config:
raise cv.Invalid("Must provide internal: config when using name:") raise cv.Invalid("Must provide internal: config when using name:")
conf_sensors = CORE.data.setdefault(DOMAIN, {}).setdefault(CONF_SENSORS, []) conf_sensors = CORE.data.setdefault(DOMAIN, {}).setdefault(CONF_SENSORS, [])
@@ -138,7 +141,7 @@ def validate_packet_transport_sensor(config):
return config return config
def packet_transport_sensor_schema(base_schema): def packet_transport_sensor_schema(base_schema: cv.Schema) -> cv.Schema:
return cv.All( return cv.All(
base_schema.extend( base_schema.extend(
{ {
@@ -152,11 +155,11 @@ def packet_transport_sensor_schema(base_schema):
) )
def hash_encryption_key(config: dict): def hash_encryption_key(config: dict) -> list[int]:
return list(hashlib.sha256(config[CONF_KEY].encode()).digest()) return list(hashlib.sha256(config[CONF_KEY].encode()).digest())
async def register_packet_transport(var, config): async def register_packet_transport(var: MockObj, config: ConfigType) -> set[str]:
var = await cg.register_component(var, config) var = await cg.register_component(var, config)
cg.add(var.set_rolling_code_enable(config[CONF_ROLLING_CODE_ENABLE])) cg.add(var.set_rolling_code_enable(config[CONF_ROLLING_CODE_ENABLE]))
cg.add(var.set_ping_pong_enable(config[CONF_PING_PONG_ENABLE])) cg.add(var.set_ping_pong_enable(config[CONF_PING_PONG_ENABLE]))
@@ -203,7 +206,7 @@ async def register_packet_transport(var, config):
return providers return providers
async def new_packet_transport(config): async def new_packet_transport(config: ConfigType) -> tuple[MockObj, set[str]]:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_platform_name(config[CONF_PLATFORM])) cg.add(var.set_platform_name(config[CONF_PLATFORM]))
providers = await register_packet_transport(var, config) providers = await register_packet_transport(var, config)
@@ -11,6 +11,7 @@ from esphome.const import (
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
) )
import esphome.final_validate as fv import esphome.final_validate as fv
from esphome.types import ConfigType
from . import ( from . import (
CONF_ENCRYPTION, CONF_ENCRYPTION,
@@ -44,7 +45,7 @@ CONFIG_SCHEMA = cv.typed_schema(
) )
def _final_validate(config) -> None: def _final_validate(config: ConfigType) -> None:
if config[CONF_TYPE] != CONF_STATUS: if config[CONF_TYPE] != CONF_STATUS:
# Only run this validation if a status sensor is being configured # Only run this validation if a status sensor is being configured
return return
@@ -65,7 +66,7 @@ def _final_validate(config) -> None:
FINAL_VALIDATE_SCHEMA = _final_validate FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = await binary_sensor.new_binary_sensor(config) var = await binary_sensor.new_binary_sensor(config)
comp = await cg.get_variable(config[CONF_TRANSPORT_ID]) comp = await cg.get_variable(config[CONF_TRANSPORT_ID])
if config[CONF_TYPE] == CONF_STATUS: if config[CONF_TYPE] == CONF_STATUS:
@@ -1,6 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.sensor import new_sensor, sensor_schema from esphome.components.sensor import new_sensor, sensor_schema
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.types import ConfigType
from . import ( from . import (
CONF_PROVIDER, CONF_PROVIDER,
@@ -12,7 +13,7 @@ from . import (
CONFIG_SCHEMA = packet_transport_sensor_schema(sensor_schema()) CONFIG_SCHEMA = packet_transport_sensor_schema(sensor_schema())
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = await new_sensor(config) var = await new_sensor(config)
comp = await cg.get_variable(config[CONF_TRANSPORT_ID]) comp = await cg.get_variable(config[CONF_TRANSPORT_ID])
remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID)) remote_id = str(config.get(CONF_REMOTE_ID) or config.get(CONF_ID))
+8 -4
View File
@@ -11,6 +11,8 @@ from esphome.const import (
CONF_NUMBER, CONF_NUMBER,
CONF_OUTPUT, CONF_OUTPUT,
) )
from esphome.cpp_generator import MockObj
from esphome.types import ConfigType
CODEOWNERS = ["@hwstar", "@clydebarrow", "@bdraco"] CODEOWNERS = ["@hwstar", "@clydebarrow", "@bdraco"]
AUTO_LOAD = ["gpio_expander"] AUTO_LOAD = ["gpio_expander"]
@@ -40,7 +42,7 @@ CONFIG_SCHEMA = (
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_pin_count(config[CONF_PIN_COUNT])) cg.add(var.set_pin_count(config[CONF_PIN_COUNT]))
await cg.register_component(var, config) await cg.register_component(var, config)
@@ -49,7 +51,7 @@ async def to_code(config):
cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin))) cg.add(var.set_interrupt_pin(await cg.gpio_pin_expression(interrupt_pin)))
def validate_mode(value): def validate_mode(value: ConfigType) -> ConfigType:
if not (value[CONF_INPUT] or value[CONF_OUTPUT]): if not (value[CONF_INPUT] or value[CONF_OUTPUT]):
raise cv.Invalid("Mode must be either input or output") raise cv.Invalid("Mode must be either input or output")
if value[CONF_INPUT] and value[CONF_OUTPUT]: if value[CONF_INPUT] and value[CONF_OUTPUT]:
@@ -69,7 +71,9 @@ PCA9554_PIN_SCHEMA = pins.gpio_base_schema(
) )
def pca9554_pin_final_validate(pin_config, parent_config): def pca9554_pin_final_validate(
pin_config: ConfigType, parent_config: ConfigType
) -> None:
count = parent_config[CONF_PIN_COUNT] count = parent_config[CONF_PIN_COUNT]
if pin_config[CONF_NUMBER] >= count: if pin_config[CONF_NUMBER] >= count:
raise cv.Invalid(f"Pin number must be in range 0-{count - 1}") raise cv.Invalid(f"Pin number must be in range 0-{count - 1}")
@@ -78,7 +82,7 @@ def pca9554_pin_final_validate(pin_config, parent_config):
@pins.PIN_SCHEMA_REGISTRY.register( @pins.PIN_SCHEMA_REGISTRY.register(
CONF_PCA9554, PCA9554_PIN_SCHEMA, pca9554_pin_final_validate CONF_PCA9554, PCA9554_PIN_SCHEMA, pca9554_pin_final_validate
) )
async def pca9554_pin_to_code(config): async def pca9554_pin_to_code(config: ConfigType) -> MockObj:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
parent = await cg.get_variable(config[CONF_PCA9554]) parent = await cg.get_variable(config[CONF_PCA9554])
+9 -7
View File
@@ -1,4 +1,5 @@
import logging import logging
from typing import Any
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
@@ -26,6 +27,7 @@ from esphome.const import (
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.core import TimePeriod from esphome.core import TimePeriod
from esphome.types import ConfigType
from . import CONF_DRAW_FROM_ORIGIN from . import CONF_DRAW_FROM_ORIGIN
from .models import DriverChip from .models import DriverChip
@@ -49,14 +51,14 @@ DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema
DELAY_FLAG = 0xFF DELAY_FLAG = 0xFF
def validate_dimension(value): def validate_dimension(value: Any) -> int:
value = cv.positive_int(value) value = cv.positive_int(value)
if value % 2 != 0: if value % 2 != 0:
raise cv.Invalid("Width/height/offset must be divisible by 2") raise cv.Invalid("Width/height/offset must be divisible by 2")
return value return value
def map_sequence(value): def map_sequence(value: Any) -> list[int]:
""" """
The format is a repeated sequence of [CMD, <data>] where <data> is s a sequence of bytes. The length is inferred The format is a repeated sequence of [CMD, <data>] where <data> is s a sequence of bytes. The length is inferred
from the length of the sequence and should not be explicit. from the length of the sequence and should not be explicit.
@@ -74,14 +76,14 @@ def map_sequence(value):
return [value[0], len(params)] + list(params) return [value[0], len(params)] + list(params)
def _validate(config): def _validate(config: ConfigType) -> ConfigType:
chip = DriverChip.chips[config[CONF_MODEL]] chip = DriverChip.chips[config[CONF_MODEL]]
if not chip.initsequence and CONF_INIT_SEQUENCE not in config: if not chip.initsequence and CONF_INIT_SEQUENCE not in config:
raise cv.Invalid(f"{chip.name} model requires init_sequence") raise cv.Invalid(f"{chip.name} model requires init_sequence")
return config return config
def power_of_two(value): def power_of_two(value: Any) -> int:
value = cv.int_range(1, 128)(value) value = cv.int_range(1, 128)(value)
if value & (value - 1) != 0: if value & (value - 1) != 0:
raise cv.Invalid("value must be a power of two") raise cv.Invalid("value must be a power of two")
@@ -122,11 +124,11 @@ BASE_SCHEMA = display.FULL_DISPLAY_SCHEMA.extend(
) )
def model_property(name, defaults, fallback): def model_property(name: str, defaults: dict[str, Any], fallback: Any) -> cv.Optional:
return cv.Optional(name, default=defaults.get(name, fallback)) return cv.Optional(name, default=defaults.get(name, fallback))
def model_schema(defaults): def model_schema(defaults: dict[str, Any]) -> cv.Schema:
transform = cv.Schema( transform = cv.Schema(
{ {
cv.Optional(CONF_MIRROR_X, default=False): cv.boolean, cv.Optional(CONF_MIRROR_X, default=False): cv.boolean,
@@ -162,7 +164,7 @@ CONFIG_SCHEMA = cv.All(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
LOGGER.warning( LOGGER.warning(
"The 'qspi_dbi' component is deprecated, it is recommended to use 'mipi_spi' instead." "The 'qspi_dbi' component is deprecated, it is recommended to use 'mipi_spi' instead."
) )
+6 -4
View File
@@ -1,4 +1,6 @@
# Commands # Commands
from typing import Any
from esphome.components.const import CONF_DRAW_ROUNDING from esphome.components.const import CONF_DRAW_ROUNDING
from esphome.const import CONF_INVERT_COLORS, CONF_SWAP_XY from esphome.const import CONF_INVERT_COLORS, CONF_SWAP_XY
@@ -26,16 +28,16 @@ PAGESEL = 0xFE
class DriverChip: class DriverChip:
chips = {} chips: dict[str, "DriverChip"] = {}
def __init__(self, name: str, defaults=None): def __init__(self, name: str, defaults: dict[str, Any] | None = None) -> None:
name = name.upper() name = name.upper()
self.name = name self.name = name
self.chips[name] = self self.chips[name] = self
self.initsequence = [] self.initsequence = []
self.defaults = defaults or {} self.defaults = defaults or {}
def cmd(self, c, *args): def cmd(self, c: int, *args: int) -> None:
""" """
Add a command sequence to the init sequence Add a command sequence to the init sequence
:param c: The command (8 bit) :param c: The command (8 bit)
@@ -43,7 +45,7 @@ class DriverChip:
""" """
self.initsequence.extend([c, len(args)] + list(args)) self.initsequence.extend([c, len(args)] + list(args))
def delay(self, ms): def delay(self, ms: int) -> None:
self.initsequence.extend([ms, 0xFF]) self.initsequence.extend([ms, 0xFF])
+6 -3
View File
@@ -1,4 +1,6 @@
from collections.abc import Callable
import logging import logging
from typing import Any
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
@@ -38,6 +40,7 @@ from esphome.const import (
CONF_VSYNC_PIN, CONF_VSYNC_PIN,
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.types import ConfigType
DEPENDENCIES = ["esp32"] DEPENDENCIES = ["esp32"]
LOGGER = logging.getLogger(__name__) LOGGER = logging.getLogger(__name__)
@@ -53,7 +56,7 @@ COLOR_ORDERS = {
DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema
def data_pin_validate(value): def data_pin_validate(value: Any) -> ConfigType:
""" """
It is safe to use strapping pins as RGB output data bits, as they are outputs only, It is safe to use strapping pins as RGB output data bits, as they are outputs only,
and not initialised until after boot. and not initialised until after boot.
@@ -68,7 +71,7 @@ def data_pin_validate(value):
return DATA_PIN_SCHEMA(value) return DATA_PIN_SCHEMA(value)
def data_pin_set(length): def data_pin_set(length: int) -> Callable[[Any], Any]:
return cv.All( return cv.All(
[data_pin_validate], [data_pin_validate],
cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"), cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"),
@@ -128,7 +131,7 @@ CONFIG_SCHEMA = cv.All(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
LOGGER.warning( LOGGER.warning(
"The 'rpi_dpi_rgb' component is deprecated, it is recommended to use 'mipi_rgb' instead." "The 'rpi_dpi_rgb' component is deprecated, it is recommended to use 'mipi_rgb' instead."
) )
+2 -1
View File
@@ -5,6 +5,7 @@ import esphome.config_validation as cv
from esphome.const import CONF_KEY from esphome.const import CONF_KEY
from esphome.core import Lambda from esphome.core import Lambda
from esphome.cpp_generator import ExpressionStatement, RawExpression from esphome.cpp_generator import ExpressionStatement, RawExpression
from esphome.types import ConfigType
from .display import CONF_SDL_ID, Sdl from .display import CONF_SDL_ID, Sdl
@@ -275,7 +276,7 @@ CONFIG_SCHEMA = (
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = await binary_sensor.new_binary_sensor(config) var = await binary_sensor.new_binary_sensor(config)
parent = await cg.get_variable(config[CONF_SDL_ID]) parent = await cg.get_variable(config[CONF_SDL_ID])
listener = Lambda( listener = Lambda(
+6 -3
View File
@@ -1,4 +1,6 @@
from collections.abc import Callable
import subprocess import subprocess
from typing import Any
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import display from esphome.components import display
@@ -14,6 +16,7 @@ from esphome.const import (
CONF_Y, CONF_Y,
PLATFORM_HOST, PLATFORM_HOST,
) )
from esphome.types import ConfigType
sdl_ns = cg.esphome_ns.namespace("sdl") sdl_ns = cg.esphome_ns.namespace("sdl")
Sdl = sdl_ns.class_("Sdl", display.Display, cg.Component) Sdl = sdl_ns.class_("Sdl", display.Display, cg.Component)
@@ -35,7 +38,7 @@ WINDOW_OPTIONS = (
SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000 SDL_WINDOWPOS_CENTERED_MASK = 0x2FFF0000
def get_sdl_options(value): def get_sdl_options(value: str) -> str:
if value != "": if value != "":
return value return value
try: try:
@@ -46,7 +49,7 @@ def get_sdl_options(value):
raise cv.Invalid("Unable to run sdl2-config - have you installed sdl2?") from e raise cv.Invalid("Unable to run sdl2-config - have you installed sdl2?") from e
def get_window_options(): def get_window_options() -> dict[cv.Optional, Callable[[Any], Any]]:
return {cv.Optional(option, default=False): cv.boolean for option in WINDOW_OPTIONS} return {cv.Optional(option, default=False): cv.boolean for option in WINDOW_OPTIONS}
@@ -100,7 +103,7 @@ CONFIG_SCHEMA = cv.All(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
for option in config[CONF_SDL_OPTIONS].split(): for option in config[CONF_SDL_OPTIONS].split():
cg.add_build_flag(option) cg.add_build_flag(option)
cg.add_build_flag("-DSDL_BYTEORDER=4321") cg.add_build_flag("-DSDL_BYTEORDER=4321")
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import touchscreen from esphome.components import touchscreen
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.types import ConfigType
from ..display import CONF_SDL_ID, Sdl, sdl_ns from ..display import CONF_SDL_ID, Sdl, sdl_ns
@@ -16,7 +17,7 @@ CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_parented(var, config[CONF_SDL_ID]) await cg.register_parented(var, config[CONF_SDL_ID])
await touchscreen.register_touchscreen(var, config) await touchscreen.register_touchscreen(var, config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import uart from esphome.components import uart
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.types import ConfigType
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
# is the code owner of the relevant code base # is the code owner of the relevant code base
@@ -43,7 +44,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
# The async def keyword is used to define a concurrent function. # The async def keyword is used to define a concurrent function.
# Concurrent functions are special functions designed to work with Python's asyncio library to support asynchronous I/O operations. # Concurrent functions are special functions designed to work with Python's asyncio library to support asynchronous I/O operations.
async def to_code(config): async def to_code(config: ConfigType) -> None:
# This line of code creates a new Pvariable (a Python object representing a C++ variable) with the variable's ID taken from the configuration. # This line of code creates a new Pvariable (a Python object representing a C++ variable) with the variable's ID taken from the configuration.
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
# This line of code registers the newly created Pvariable as a component so that ESPHome can manage it at runtime. # This line of code registers the newly created Pvariable as a component so that ESPHome can manage it at runtime.
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import binary_sensor from esphome.components import binary_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_HAS_TARGET, DEVICE_CLASS_OCCUPANCY from esphome.const import CONF_HAS_TARGET, DEVICE_CLASS_OCCUPANCY
from esphome.types import ConfigType
from . import CONF_MR24HPC1_ID, MR24HPC1Component from . import CONF_MR24HPC1_ID, MR24HPC1Component
@@ -13,7 +14,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if has_target_config := config.get(CONF_HAS_TARGET): if has_target_config := config.get(CONF_HAS_TARGET):
sens = await binary_sensor.new_binary_sensor(has_target_config) sens = await binary_sensor.new_binary_sensor(has_target_config)
@@ -7,6 +7,7 @@ from esphome.const import (
ENTITY_CATEGORY_CONFIG, ENTITY_CATEGORY_CONFIG,
ICON_RESTART_ALERT, ICON_RESTART_ALERT,
) )
from esphome.types import ConfigType
from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns
@@ -31,7 +32,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if restart_config := config.get(CONF_RESTART): if restart_config := config.get(CONF_RESTART):
b = await button.new_button(restart_config) b = await button.new_button(restart_config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import number from esphome.components import number
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns
@@ -63,7 +64,7 @@ CONFIG_SCHEMA = cv.Schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if sensitivity_config := config.get(CONF_SENSITIVITY): if sensitivity_config := config.get(CONF_SENSITIVITY):
n = await number.new_number( n = await number.new_number(
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import select from esphome.components import select
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_CONFIG from esphome.const import ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns
@@ -38,7 +39,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if scenemode_config := config.get(CONF_SCENE_MODE): if scenemode_config := config.get(CONF_SCENE_MODE):
s = await select.new_select( s = await select.new_select(
+2 -1
View File
@@ -8,6 +8,7 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT, STATE_CLASS_MEASUREMENT,
UNIT_METER, UNIT_METER,
) )
from esphome.types import ConfigType
from . import CONF_MR24HPC1_ID, MR24HPC1Component from . import CONF_MR24HPC1_ID, MR24HPC1Component
@@ -60,7 +61,7 @@ CONFIG_SCHEMA = cv.Schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if custompresenceofdetection_config := config.get( if custompresenceofdetection_config := config.get(
CONF_CUSTOM_PRESENCE_OF_DETECTION CONF_CUSTOM_PRESENCE_OF_DETECTION
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import switch from esphome.components import switch
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns
@@ -22,7 +23,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if underlying_open_function_config := config.get(CONF_UNDERLYING_OPEN_FUNCTION): if underlying_open_function_config := config.get(CONF_UNDERLYING_OPEN_FUNCTION):
s = await switch.new_switch(underlying_open_function_config) s = await switch.new_switch(underlying_open_function_config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import text_sensor from esphome.components import text_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC from esphome.const import ENTITY_CATEGORY_DIAGNOSTIC
from esphome.types import ConfigType
from . import CONF_MR24HPC1_ID, MR24HPC1Component from . import CONF_MR24HPC1_ID, MR24HPC1Component
@@ -47,7 +48,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID]) mr24hpc1_component = await cg.get_variable(config[CONF_MR24HPC1_ID])
if heartbeat_config := config.get(CONF_HEART_BEAT): if heartbeat_config := config.get(CONF_HEART_BEAT):
sens = await text_sensor.new_text_sensor(heartbeat_config) sens = await text_sensor.new_text_sensor(heartbeat_config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import uart from esphome.components import uart
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.types import ConfigType
CODEOWNERS = ["@limengdu"] CODEOWNERS = ["@limengdu"]
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
@@ -35,7 +36,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
await uart.register_uart_device(var, config) await uart.register_uart_device(var, config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import binary_sensor from esphome.components import binary_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_HAS_TARGET, DEVICE_CLASS_OCCUPANCY from esphome.const import CONF_HAS_TARGET, DEVICE_CLASS_OCCUPANCY
from esphome.types import ConfigType
from . import CONF_MR60BHA2_ID, MR60BHA2Component from . import CONF_MR60BHA2_ID, MR60BHA2Component
@@ -15,7 +16,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID]) mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID])
if has_target_config := config.get(CONF_HAS_TARGET): if has_target_config := config.get(CONF_HAS_TARGET):
+2 -1
View File
@@ -12,6 +12,7 @@ from esphome.const import (
UNIT_BEATS_PER_MINUTE, UNIT_BEATS_PER_MINUTE,
UNIT_CENTIMETER, UNIT_CENTIMETER,
) )
from esphome.types import ConfigType
from . import CONF_MR60BHA2_ID, MR60BHA2Component from . import CONF_MR60BHA2_ID, MR60BHA2Component
@@ -49,7 +50,7 @@ CONFIG_SCHEMA = cv.Schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID]) mr60bha2_component = await cg.get_variable(config[CONF_MR60BHA2_ID])
if breath_rate_config := config.get(CONF_BREATH_RATE): if breath_rate_config := config.get(CONF_BREATH_RATE):
sens = await sensor.new_sensor(breath_rate_config) sens = await sensor.new_sensor(breath_rate_config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import uart from esphome.components import uart
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ID from esphome.const import CONF_ID
from esphome.types import ConfigType
CODEOWNERS = ["@limengdu"] CODEOWNERS = ["@limengdu"]
DEPENDENCIES = ["uart"] DEPENDENCIES = ["uart"]
@@ -35,7 +36,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
await uart.register_uart_device(var, config) await uart.register_uart_device(var, config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import binary_sensor from esphome.components import binary_sensor
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_SAFETY from esphome.const import DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_SAFETY
from esphome.types import ConfigType
from . import CONF_MR60FDA2_ID, MR60FDA2Component from . import CONF_MR60FDA2_ID, MR60FDA2Component
@@ -21,7 +22,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID])
if people_exist_config := config.get(CONF_PEOPLE_EXIST): if people_exist_config := config.get(CONF_PEOPLE_EXIST):
@@ -8,6 +8,7 @@ from esphome.const import (
ENTITY_CATEGORY_DIAGNOSTIC, ENTITY_CATEGORY_DIAGNOSTIC,
ENTITY_CATEGORY_NONE, ENTITY_CATEGORY_NONE,
) )
from esphome.types import ConfigType
from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns
@@ -33,7 +34,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID])
if get_radar_parameters_config := config.get(CONF_GET_RADAR_PARAMETERS): if get_radar_parameters_config := config.get(CONF_GET_RADAR_PARAMETERS):
b = await button.new_button(get_radar_parameters_config) b = await button.new_button(get_radar_parameters_config)
@@ -2,6 +2,7 @@ import esphome.codegen as cg
from esphome.components import select from esphome.components import select
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG, ICON_ACCELERATION_Z from esphome.const import CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG, ICON_ACCELERATION_Z
from esphome.types import ConfigType
from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns
@@ -33,7 +34,7 @@ CONFIG_SCHEMA = {
} }
async def to_code(config): async def to_code(config: ConfigType) -> None:
mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID]) mr60fda2_component = await cg.get_variable(config[CONF_MR60FDA2_ID])
if install_height_config := config.get(CONF_INSTALL_HEIGHT): if install_height_config := config.get(CONF_INSTALL_HEIGHT):
s = await select.new_select( s = await select.new_select(
+7 -4
View File
@@ -1,3 +1,5 @@
from typing import Any
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import display, spi from esphome.components import display, spi
@@ -41,6 +43,7 @@ from esphome.const import (
CONF_WIDTH, CONF_WIDTH,
) )
from esphome.core import TimePeriod from esphome.core import TimePeriod
from esphome.types import ConfigType
from .init_sequences import ST7701S_INITS, cmd from .init_sequences import ST7701S_INITS, cmd
@@ -58,7 +61,7 @@ COLOR_ORDERS = {
DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema DATA_PIN_SCHEMA = pins.internal_gpio_output_pin_schema
def data_pin_validate(value): def data_pin_validate(value: Any) -> ConfigType:
""" """
It is safe to use strapping pins as RGB output data bits, as they are outputs only, It is safe to use strapping pins as RGB output data bits, as they are outputs only,
and not initialised until after boot. and not initialised until after boot.
@@ -73,14 +76,14 @@ def data_pin_validate(value):
return DATA_PIN_SCHEMA(value) return DATA_PIN_SCHEMA(value)
def data_pin_set(length): def data_pin_set(length: int) -> cv.Schema:
return cv.All( return cv.All(
[data_pin_validate], [data_pin_validate],
cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"), cv.Length(min=length, max=length, msg=f"Exactly {length} data pins required"),
) )
def map_sequence(value): def map_sequence(value: Any) -> list:
""" """
An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py, An initialisation sequence can be selected from one of the pre-defined sequences in init_sequences.py,
or can be a literal array of data bytes. or can be a literal array of data bytes.
@@ -170,7 +173,7 @@ FINAL_VALIDATE_SCHEMA = spi.final_validate_device_schema(
) )
async def to_code(config): async def to_code(config: ConfigType) -> None:
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await display.register_display(var, config) await display.register_display(var, config)
await spi.register_spi_device(var, config, write_only=True) await spi.register_spi_device(var, config, write_only=True)
+1 -1
View File
@@ -1,7 +1,7 @@
# These are initialisation sequences for ST7701S displays. The contents are somewhat arcane. # These are initialisation sequences for ST7701S displays. The contents are somewhat arcane.
def cmd(c, *args): def cmd(c: int, *args: int) -> list[int]:
""" """
Create a command sequence Create a command sequence
:param c: The command (8 bit) :param c: The command (8 bit)
+15 -7
View File
@@ -1,3 +1,6 @@
from collections.abc import Callable
from typing import Any, NoReturn
from esphome import automation from esphome import automation
from esphome.automation import Trigger from esphome.automation import Trigger
import esphome.codegen as cg import esphome.codegen as cg
@@ -13,7 +16,7 @@ from esphome.components.packet_transport import (
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_DATA, CONF_ID, CONF_PORT, CONF_TRIGGER_ID from esphome.const import CONF_DATA, CONF_ID, CONF_PORT, CONF_TRIGGER_ID
from esphome.core import ID from esphome.core import ID
from esphome.cpp_generator import MockObj from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType from esphome.types import ConfigType
CODEOWNERS = ["@clydebarrow"] CODEOWNERS = ["@clydebarrow"]
@@ -45,8 +48,8 @@ UDP_SCHEMA = cv.Schema(
) )
def is_relocated(option): def is_relocated(option: str) -> Callable[[Any], NoReturn]:
def validator(value): def validator(value: Any) -> NoReturn:
raise cv.Invalid( raise cv.Invalid(
f"The '{option}' option should now be configured in the 'packet_transport' component" f"The '{option}' option should now be configured in the 'packet_transport' component"
) )
@@ -109,13 +112,13 @@ CONFIG_SCHEMA = cv.All(
) )
async def register_udp_client(var, config): async def register_udp_client(var: MockObj, config: ConfigType) -> MockObj:
udp_var = await cg.get_variable(config[CONF_UDP_ID]) udp_var = await cg.get_variable(config[CONF_UDP_ID])
cg.add(var.set_parent(udp_var)) cg.add(var.set_parent(udp_var))
return udp_var return udp_var
async def to_code(config): async def to_code(config: ConfigType) -> None:
cg.add_define("USE_UDP") cg.add_define("USE_UDP")
cg.add_global(udp_ns.using) cg.add_global(udp_ns.using)
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
@@ -147,7 +150,7 @@ async def to_code(config):
cg.add(var.set_should_listen()) cg.add(var.set_should_listen())
def validate_raw_data(value): def validate_raw_data(value: Any) -> bytes | list[int]:
if isinstance(value, str): if isinstance(value, str):
return value.encode("utf-8") return value.encode("utf-8")
if isinstance(value, str): if isinstance(value, str):
@@ -171,7 +174,12 @@ def validate_raw_data(value):
), ),
synchronous=True, synchronous=True,
) )
async def udp_write_to_code(config, action_id, template_arg, args): async def udp_write_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
udp_var = await cg.get_variable(config[CONF_ID]) udp_var = await cg.get_variable(config[CONF_ID])
await cg.register_parented(var, udp_var) await cg.register_parented(var, udp_var)
@@ -7,6 +7,7 @@ from esphome.components.packet_transport import (
) )
from esphome.const import CONF_BINARY_SENSORS, CONF_ENCRYPTION, CONF_SENSORS from esphome.const import CONF_BINARY_SENSORS, CONF_ENCRYPTION, CONF_SENSORS
from esphome.cpp_types import PollingComponent from esphome.cpp_types import PollingComponent
from esphome.types import ConfigType
from .. import UDP_SCHEMA, register_udp_client, udp_ns from .. import UDP_SCHEMA, register_udp_client, udp_ns
@@ -15,7 +16,7 @@ UDPTransport = udp_ns.class_("UDPTransport", PacketTransport, PollingComponent)
CONFIG_SCHEMA = transport_schema(UDPTransport).extend(UDP_SCHEMA) CONFIG_SCHEMA = transport_schema(UDPTransport).extend(UDP_SCHEMA)
async def to_code(config): async def to_code(config: ConfigType) -> None:
var, providers = await new_packet_transport(config) var, providers = await new_packet_transport(config)
udp_var = await register_udp_client(var, config) udp_var = await register_udp_client(var, config)
if CONF_ENCRYPTION in config or providers: if CONF_ENCRYPTION in config or providers:
+10 -9
View File
@@ -18,6 +18,7 @@ from esphome.const import (
) )
from esphome.core import CORE from esphome.core import CORE
from esphome.cpp_types import Component from esphome.cpp_types import Component
from esphome.types import ConfigType
AUTO_LOAD = ["uart", "usb_host", "bytebuffer"] AUTO_LOAD = ["uart", "usb_host", "bytebuffer"]
CODEOWNERS = ["@clydebarrow"] CODEOWNERS = ["@clydebarrow"]
@@ -48,14 +49,14 @@ DEFAULT_BAUD_RATE = 9600
class Type: class Type:
def __init__( def __init__(
self, self,
name, name: str,
vid, vid: int,
pid, pid: int,
cls, cls: str | None,
max_channels=1, max_channels: int = 1,
baud_rate_required=True, baud_rate_required: bool = True,
max_baud=1_000_000, max_baud: int = 1_000_000,
): ) -> None:
self.name = name self.name = name
cls = cls or name cls = cls or name
self.vid = vid self.vid = vid
@@ -156,7 +157,7 @@ CONFIG_SCHEMA = cv.ensure_list(
) )
async def to_code(config): async def to_code(config: list[ConfigType]) -> None:
# The output chunk pool/queue are compile-time-sized templates shared by all # The output chunk pool/queue are compile-time-sized templates shared by all
# USBUartChannel instances, so use the largest buffer_size across every channel # USBUartChannel instances, so use the largest buffer_size across every channel
# of every device. Add one extra slot because LockFreeQueue<T,N> is a ring # of every device. Add one extra slot because LockFreeQueue<T,N> is a ring