1
0
mirror of https://github.com/esphome/esphome.git synced 2025-09-26 15:12:21 +01:00

Merge remote-tracking branch 'upstream/dev' into core_api_no_allocate

This commit is contained in:
J. Nick Koston
2025-09-23 11:19:47 -05:00
11 changed files with 195 additions and 78 deletions

View File

@@ -15,7 +15,10 @@ from esphome.const import (
CONF_TYPE_ID, CONF_TYPE_ID,
CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL,
) )
from esphome.core import ID
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor from esphome.schema_extractors import SCHEMA_EXTRACT, schema_extractor
from esphome.types import ConfigType
from esphome.util import Registry from esphome.util import Registry
@@ -49,11 +52,11 @@ def maybe_conf(conf, *validators):
return validate return validate
def register_action(name, action_type, schema): def register_action(name: str, action_type: MockObjClass, schema: cv.Schema):
return ACTION_REGISTRY.register(name, action_type, schema) return ACTION_REGISTRY.register(name, action_type, schema)
def register_condition(name, condition_type, schema): def register_condition(name: str, condition_type: MockObjClass, schema: cv.Schema):
return CONDITION_REGISTRY.register(name, condition_type, schema) return CONDITION_REGISTRY.register(name, condition_type, schema)
@@ -164,43 +167,78 @@ XorCondition = cg.esphome_ns.class_("XorCondition", Condition)
@register_condition("and", AndCondition, validate_condition_list) @register_condition("and", AndCondition, validate_condition_list)
async def and_condition_to_code(config, condition_id, template_arg, args): async def and_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args) conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, conditions) return cg.new_Pvariable(condition_id, template_arg, conditions)
@register_condition("or", OrCondition, validate_condition_list) @register_condition("or", OrCondition, validate_condition_list)
async def or_condition_to_code(config, condition_id, template_arg, args): async def or_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args) conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, conditions) return cg.new_Pvariable(condition_id, template_arg, conditions)
@register_condition("all", AndCondition, validate_condition_list) @register_condition("all", AndCondition, validate_condition_list)
async def all_condition_to_code(config, condition_id, template_arg, args): async def all_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args) conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, conditions) return cg.new_Pvariable(condition_id, template_arg, conditions)
@register_condition("any", OrCondition, validate_condition_list) @register_condition("any", OrCondition, validate_condition_list)
async def any_condition_to_code(config, condition_id, template_arg, args): async def any_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args) conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, conditions) return cg.new_Pvariable(condition_id, template_arg, conditions)
@register_condition("not", NotCondition, validate_potentially_and_condition) @register_condition("not", NotCondition, validate_potentially_and_condition)
async def not_condition_to_code(config, condition_id, template_arg, args): async def not_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
condition = await build_condition(config, template_arg, args) condition = await build_condition(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, condition) return cg.new_Pvariable(condition_id, template_arg, condition)
@register_condition("xor", XorCondition, validate_condition_list) @register_condition("xor", XorCondition, validate_condition_list)
async def xor_condition_to_code(config, condition_id, template_arg, args): async def xor_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
conditions = await build_condition_list(config, template_arg, args) conditions = await build_condition_list(config, template_arg, args)
return cg.new_Pvariable(condition_id, template_arg, conditions) return cg.new_Pvariable(condition_id, template_arg, conditions)
@register_condition("lambda", LambdaCondition, cv.returning_lambda) @register_condition("lambda", LambdaCondition, cv.returning_lambda)
async def lambda_condition_to_code(config, condition_id, template_arg, args): async def lambda_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
lambda_ = await cg.process_lambda(config, args, return_type=bool) lambda_ = await cg.process_lambda(config, args, return_type=bool)
return cg.new_Pvariable(condition_id, template_arg, lambda_) return cg.new_Pvariable(condition_id, template_arg, lambda_)
@@ -217,7 +255,12 @@ async def lambda_condition_to_code(config, condition_id, template_arg, args):
} }
).extend(cv.COMPONENT_SCHEMA), ).extend(cv.COMPONENT_SCHEMA),
) )
async def for_condition_to_code(config, condition_id, template_arg, args): async def for_condition_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
condition = await build_condition( condition = await build_condition(
config[CONF_CONDITION], cg.TemplateArguments(), [] config[CONF_CONDITION], cg.TemplateArguments(), []
) )
@@ -231,7 +274,12 @@ async def for_condition_to_code(config, condition_id, template_arg, args):
@register_action( @register_action(
"delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds) "delay", DelayAction, cv.templatable(cv.positive_time_period_milliseconds)
) )
async def delay_action_to_code(config, action_id, template_arg, args): async def delay_action_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)
await cg.register_component(var, {}) await cg.register_component(var, {})
template_ = await cg.templatable(config, args, cg.uint32) template_ = await cg.templatable(config, args, cg.uint32)
@@ -256,10 +304,15 @@ async def delay_action_to_code(config, action_id, template_arg, args):
cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL), cv.has_at_least_one_key(CONF_CONDITION, CONF_ANY, CONF_ALL),
), ),
) )
async def if_action_to_code(config, action_id, template_arg, args): async def if_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION)) cond_conf = next(el for el in config if el in (CONF_ANY, CONF_ALL, CONF_CONDITION))
conditions = await build_condition(config[cond_conf], template_arg, args) condition = await build_condition(config[cond_conf], template_arg, args)
var = cg.new_Pvariable(action_id, template_arg, conditions) var = cg.new_Pvariable(action_id, template_arg, condition)
if CONF_THEN in config: if CONF_THEN in config:
actions = await build_action_list(config[CONF_THEN], template_arg, args) actions = await build_action_list(config[CONF_THEN], template_arg, args)
cg.add(var.add_then(actions)) cg.add(var.add_then(actions))
@@ -279,9 +332,14 @@ async def if_action_to_code(config, action_id, template_arg, args):
} }
), ),
) )
async def while_action_to_code(config, action_id, template_arg, args): async def while_action_to_code(
conditions = await build_condition(config[CONF_CONDITION], template_arg, args) config: ConfigType,
var = cg.new_Pvariable(action_id, template_arg, conditions) action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
var = cg.new_Pvariable(action_id, template_arg, condition)
actions = await build_action_list(config[CONF_THEN], template_arg, args) actions = await build_action_list(config[CONF_THEN], template_arg, args)
cg.add(var.add_then(actions)) cg.add(var.add_then(actions))
return var return var
@@ -297,7 +355,12 @@ async def while_action_to_code(config, action_id, template_arg, args):
} }
), ),
) )
async def repeat_action_to_code(config, action_id, template_arg, args): async def repeat_action_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)
count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32) count_template = await cg.templatable(config[CONF_COUNT], args, cg.uint32)
cg.add(var.set_count(count_template)) cg.add(var.set_count(count_template))
@@ -320,9 +383,14 @@ _validate_wait_until = cv.maybe_simple_value(
@register_action("wait_until", WaitUntilAction, _validate_wait_until) @register_action("wait_until", WaitUntilAction, _validate_wait_until)
async def wait_until_action_to_code(config, action_id, template_arg, args): async def wait_until_action_to_code(
conditions = await build_condition(config[CONF_CONDITION], template_arg, args) config: ConfigType,
var = cg.new_Pvariable(action_id, template_arg, conditions) action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
condition = await build_condition(config[CONF_CONDITION], template_arg, args)
var = cg.new_Pvariable(action_id, template_arg, condition)
if CONF_TIMEOUT in config: if CONF_TIMEOUT in config:
template_ = await cg.templatable(config[CONF_TIMEOUT], args, cg.uint32) template_ = await cg.templatable(config[CONF_TIMEOUT], args, cg.uint32)
cg.add(var.set_timeout_value(template_)) cg.add(var.set_timeout_value(template_))
@@ -331,7 +399,12 @@ async def wait_until_action_to_code(config, action_id, template_arg, args):
@register_action("lambda", LambdaAction, cv.lambda_) @register_action("lambda", LambdaAction, cv.lambda_)
async def lambda_action_to_code(config, action_id, template_arg, args): async def lambda_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
lambda_ = await cg.process_lambda(config, args, return_type=cg.void) lambda_ = await cg.process_lambda(config, args, return_type=cg.void)
return cg.new_Pvariable(action_id, template_arg, lambda_) return cg.new_Pvariable(action_id, template_arg, lambda_)
@@ -345,7 +418,12 @@ async def lambda_action_to_code(config, action_id, template_arg, args):
} }
), ),
) )
async def component_update_action_to_code(config, action_id, template_arg, args): async def component_update_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
comp = await cg.get_variable(config[CONF_ID]) comp = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, comp) return cg.new_Pvariable(action_id, template_arg, comp)
@@ -359,7 +437,12 @@ async def component_update_action_to_code(config, action_id, template_arg, args)
} }
), ),
) )
async def component_suspend_action_to_code(config, action_id, template_arg, args): async def component_suspend_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
comp = await cg.get_variable(config[CONF_ID]) comp = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, comp) return cg.new_Pvariable(action_id, template_arg, comp)
@@ -376,7 +459,12 @@ async def component_suspend_action_to_code(config, action_id, template_arg, args
} }
), ),
) )
async def component_resume_action_to_code(config, action_id, template_arg, args): async def component_resume_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
comp = await cg.get_variable(config[CONF_ID]) comp = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg, comp) var = cg.new_Pvariable(action_id, template_arg, comp)
if CONF_UPDATE_INTERVAL in config: if CONF_UPDATE_INTERVAL in config:
@@ -385,7 +473,9 @@ async def component_resume_action_to_code(config, action_id, template_arg, args)
return var return var
async def build_action(full_config, template_arg, args): async def build_action(
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
) -> MockObj:
registry_entry, config = cg.extract_registry_entry_config( registry_entry, config = cg.extract_registry_entry_config(
ACTION_REGISTRY, full_config ACTION_REGISTRY, full_config
) )
@@ -394,15 +484,19 @@ async def build_action(full_config, template_arg, args):
return await builder(config, action_id, template_arg, args) return await builder(config, action_id, template_arg, args)
async def build_action_list(config, templ, arg_type): async def build_action_list(
actions = [] config: list[ConfigType], templ: cg.TemplateArguments, arg_type: TemplateArgsType
) -> list[MockObj]:
actions: list[MockObj] = []
for conf in config: for conf in config:
action = await build_action(conf, templ, arg_type) action = await build_action(conf, templ, arg_type)
actions.append(action) actions.append(action)
return actions return actions
async def build_condition(full_config, template_arg, args): async def build_condition(
full_config: ConfigType, template_arg: cg.TemplateArguments, args: TemplateArgsType
) -> MockObj:
registry_entry, config = cg.extract_registry_entry_config( registry_entry, config = cg.extract_registry_entry_config(
CONDITION_REGISTRY, full_config CONDITION_REGISTRY, full_config
) )
@@ -411,15 +505,19 @@ async def build_condition(full_config, template_arg, args):
return await builder(config, action_id, template_arg, args) return await builder(config, action_id, template_arg, args)
async def build_condition_list(config, templ, args): async def build_condition_list(
conditions = [] config: ConfigType, templ: cg.TemplateArguments, args: TemplateArgsType
) -> list[MockObj]:
conditions: list[MockObj] = []
for conf in config: for conf in config:
condition = await build_condition(conf, templ, args) condition = await build_condition(conf, templ, args)
conditions.append(condition) conditions.append(condition)
return conditions return conditions
async def build_automation(trigger, args, config): async def build_automation(
trigger: MockObj, args: TemplateArgsType, config: ConfigType
) -> MockObj:
arg_types = [arg[0] for arg in args] arg_types = [arg[0] for arg in args]
templ = cg.TemplateArguments(*arg_types) templ = cg.TemplateArguments(*arg_types)
obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger) obj = cg.new_Pvariable(config[CONF_AUTOMATION_ID], templ, trigger)

View File

@@ -2,7 +2,6 @@ import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component from esphome.components.esp32 import add_idf_component
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE from esphome.const import CONF_BUFFER_SIZE, CONF_ID, CONF_TYPE
from esphome.core import CORE
from esphome.types import ConfigType from esphome.types import ConfigType
CODEOWNERS = ["@DT-art1"] CODEOWNERS = ["@DT-art1"]
@@ -51,9 +50,8 @@ async def to_code(config: ConfigType) -> None:
buffer = cg.new_Pvariable(config[CONF_ENCODER_BUFFER_ID]) buffer = cg.new_Pvariable(config[CONF_ENCODER_BUFFER_ID])
cg.add(buffer.set_buffer_size(config[CONF_BUFFER_SIZE])) cg.add(buffer.set_buffer_size(config[CONF_BUFFER_SIZE]))
if config[CONF_TYPE] == ESP32_CAMERA_ENCODER: if config[CONF_TYPE] == ESP32_CAMERA_ENCODER:
if CORE.using_esp_idf: add_idf_component(name="espressif/esp32-camera", ref="2.1.1")
add_idf_component(name="espressif/esp32-camera", ref="2.1.0") cg.add_define("USE_ESP32_CAMERA_JPEG_ENCODER")
cg.add_build_flag("-DUSE_ESP32_CAMERA_JPEG_ENCODER")
var = cg.new_Pvariable( var = cg.new_Pvariable(
config[CONF_ID], config[CONF_ID],
config[CONF_QUALITY], config[CONF_QUALITY],

View File

@@ -1,3 +1,5 @@
#include "esphome/core/defines.h"
#ifdef USE_ESP32_CAMERA_JPEG_ENCODER #ifdef USE_ESP32_CAMERA_JPEG_ENCODER
#include "esp32_camera_jpeg_encoder.h" #include "esp32_camera_jpeg_encoder.h"
@@ -15,7 +17,7 @@ camera::EncoderError ESP32CameraJPEGEncoder::encode_pixels(camera::CameraImageSp
this->bytes_written_ = 0; this->bytes_written_ = 0;
this->out_of_output_memory_ = false; this->out_of_output_memory_ = false;
bool success = fmt2jpg_cb(pixels->get_data_buffer(), pixels->get_data_length(), spec->width, spec->height, bool success = fmt2jpg_cb(pixels->get_data_buffer(), pixels->get_data_length(), spec->width, spec->height,
to_internal_(spec->format), this->quality_, callback_, this); to_internal_(spec->format), this->quality_, callback, this);
if (!success) if (!success)
return camera::ENCODER_ERROR_CONFIGURATION; return camera::ENCODER_ERROR_CONFIGURATION;
@@ -49,7 +51,7 @@ void ESP32CameraJPEGEncoder::dump_config() {
this->output_->get_max_size(), this->quality_, this->buffer_expand_size_); this->output_->get_max_size(), this->quality_, this->buffer_expand_size_);
} }
size_t ESP32CameraJPEGEncoder::callback_(void *arg, size_t index, const void *data, size_t len) { size_t ESP32CameraJPEGEncoder::callback(void *arg, size_t index, const void *data, size_t len) {
ESP32CameraJPEGEncoder *that = reinterpret_cast<ESP32CameraJPEGEncoder *>(arg); ESP32CameraJPEGEncoder *that = reinterpret_cast<ESP32CameraJPEGEncoder *>(arg);
uint8_t *buffer = that->output_->get_data(); uint8_t *buffer = that->output_->get_data();
size_t buffer_length = that->output_->get_max_size(); size_t buffer_length = that->output_->get_max_size();

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "esphome/core/defines.h"
#ifdef USE_ESP32_CAMERA_JPEG_ENCODER #ifdef USE_ESP32_CAMERA_JPEG_ENCODER
#include <esp_camera.h> #include <esp_camera.h>
@@ -24,7 +26,7 @@ class ESP32CameraJPEGEncoder : public camera::Encoder {
void dump_config() override; void dump_config() override;
// ------------------------- // -------------------------
protected: protected:
static size_t callback_(void *arg, size_t index, const void *data, size_t len); static size_t callback(void *arg, size_t index, const void *data, size_t len);
pixformat_t to_internal_(camera::PixelFormat format); pixformat_t to_internal_(camera::PixelFormat format);
camera::EncoderBuffer *output_{}; camera::EncoderBuffer *output_{};

View File

@@ -128,4 +128,4 @@ async def to_code(config):
cg.add_library("tonia/HeatpumpIR", "1.0.37") cg.add_library("tonia/HeatpumpIR", "1.0.37")
if CORE.is_libretiny or CORE.is_esp32: if CORE.is_libretiny or CORE.is_esp32:
CORE.add_platformio_option("lib_ignore", "IRremoteESP8266") CORE.add_platformio_option("lib_ignore", ["IRremoteESP8266"])

View File

@@ -40,5 +40,7 @@ async def to_code(config):
cg.add_library("Update", None) cg.add_library("Update", None)
if CORE.is_esp8266: if CORE.is_esp8266:
cg.add_library("ESP8266WiFi", None) cg.add_library("ESP8266WiFi", None)
if CORE.is_libretiny:
CORE.add_platformio_option("lib_ignore", ["ESPAsyncTCP", "RPAsyncTCP"])
# https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json # https://github.com/ESP32Async/ESPAsyncWebServer/blob/main/library.json
cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.10") cg.add_library("ESP32Async/ESPAsyncWebServer", "3.7.10")

View File

@@ -396,7 +396,7 @@ async def add_includes(includes: list[str]) -> None:
async def _add_platformio_options(pio_options): async def _add_platformio_options(pio_options):
# Add includes at the very end, so that they override everything # Add includes at the very end, so that they override everything
for key, val in pio_options.items(): for key, val in pio_options.items():
if key == "build_flags" and not isinstance(val, list): if key in ["build_flags", "lib_ignore"] and not isinstance(val, list):
val = [val] val = [val]
cg.add_platformio_option(key, val) cg.add_platformio_option(key, val)

View File

@@ -157,6 +157,7 @@
#define USE_ESP32_BLE_SERVER #define USE_ESP32_BLE_SERVER
#define USE_ESP32_BLE_UUID #define USE_ESP32_BLE_UUID
#define USE_ESP32_BLE_ADVERTISING #define USE_ESP32_BLE_ADVERTISING
#define USE_ESP32_CAMERA_JPEG_ENCODER
#define USE_I2C #define USE_I2C
#define USE_IMPROV #define USE_IMPROV
#define USE_MICROPHONE #define USE_MICROPHONE

View File

@@ -1,5 +1,5 @@
import abc import abc
from collections.abc import Callable, Sequence from collections.abc import Callable
import inspect import inspect
import math import math
import re import re
@@ -13,7 +13,6 @@ from esphome.core import (
HexInt, HexInt,
Lambda, Lambda,
Library, Library,
TimePeriod,
TimePeriodMicroseconds, TimePeriodMicroseconds,
TimePeriodMilliseconds, TimePeriodMilliseconds,
TimePeriodMinutes, TimePeriodMinutes,
@@ -21,35 +20,11 @@ from esphome.core import (
TimePeriodSeconds, TimePeriodSeconds,
) )
from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last from esphome.helpers import cpp_string_escape, indent_all_but_first_and_last
from esphome.types import Expression, SafeExpType, TemplateArgsType
from esphome.util import OrderedDict from esphome.util import OrderedDict
from esphome.yaml_util import ESPHomeDataBase from esphome.yaml_util import ESPHomeDataBase
class Expression(abc.ABC):
__slots__ = ()
@abc.abstractmethod
def __str__(self):
"""
Convert expression into C++ code
"""
SafeExpType = (
Expression
| bool
| str
| str
| int
| float
| TimePeriod
| type[bool]
| type[int]
| type[float]
| Sequence[Any]
)
class RawExpression(Expression): class RawExpression(Expression):
__slots__ = ("text",) __slots__ = ("text",)
@@ -575,7 +550,7 @@ def Pvariable(id_: ID, rhs: SafeExpType, type_: "MockObj" = None) -> "MockObj":
return obj return obj
def new_Pvariable(id_: ID, *args: SafeExpType) -> Pvariable: def new_Pvariable(id_: ID, *args: SafeExpType) -> "MockObj":
"""Declare a new pointer variable in the code generation by calling it's constructor """Declare a new pointer variable in the code generation by calling it's constructor
with the given arguments. with the given arguments.
@@ -681,7 +656,7 @@ async def get_variable_with_full_id(id_: ID) -> tuple[ID, "MockObj"]:
async def process_lambda( async def process_lambda(
value: Lambda, value: Lambda,
parameters: list[tuple[SafeExpType, str]], parameters: TemplateArgsType,
capture: str = "=", capture: str = "=",
return_type: SafeExpType = None, return_type: SafeExpType = None,
) -> LambdaExpression | None: ) -> LambdaExpression | None:

View File

@@ -1,8 +1,10 @@
"""This helper module tracks commonly used types in the esphome python codebase.""" """This helper module tracks commonly used types in the esphome python codebase."""
from typing import TypedDict import abc
from collections.abc import Sequence
from typing import Any, TypedDict
from esphome.core import ID, EsphomeCore, Lambda from esphome.core import ID, EsphomeCore, Lambda, TimePeriod
ConfigFragmentType = ( ConfigFragmentType = (
str str
@@ -20,6 +22,32 @@ CoreType = EsphomeCore
ConfigPathType = str | int ConfigPathType = str | int
class Expression(abc.ABC):
__slots__ = ()
@abc.abstractmethod
def __str__(self):
"""
Convert expression into C++ code
"""
SafeExpType = (
Expression
| bool
| str
| int
| float
| TimePeriod
| type[bool]
| type[int]
| type[float]
| Sequence[Any]
)
TemplateArgsType = list[tuple[SafeExpType, str]]
class EntityMetadata(TypedDict): class EntityMetadata(TypedDict):
"""Metadata stored for each entity to help with duplicate detection.""" """Metadata stored for each entity to help with duplicate detection."""

View File

@@ -1,19 +1,30 @@
import collections import collections
from collections.abc import Callable
import io import io
import logging import logging
from pathlib import Path from pathlib import Path
import re import re
import subprocess import subprocess
import sys import sys
from typing import Any from typing import TYPE_CHECKING, Any
from esphome import const from esphome import const
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
if TYPE_CHECKING:
from esphome.config_validation import Schema
from esphome.cpp_generator import MockObjClass
class RegistryEntry: class RegistryEntry:
def __init__(self, name, fun, type_id, schema): def __init__(
self,
name: str,
fun: Callable[..., Any],
type_id: "MockObjClass",
schema: "Schema",
):
self.name = name self.name = name
self.fun = fun self.fun = fun
self.type_id = type_id self.type_id = type_id
@@ -38,8 +49,8 @@ class Registry(dict[str, RegistryEntry]):
self.base_schema = base_schema or {} self.base_schema = base_schema or {}
self.type_id_key = type_id_key self.type_id_key = type_id_key
def register(self, name, type_id, schema): def register(self, name: str, type_id: "MockObjClass", schema: "Schema"):
def decorator(fun): def decorator(fun: Callable[..., Any]):
self[name] = RegistryEntry(name, fun, type_id, schema) self[name] = RegistryEntry(name, fun, type_id, schema)
return fun return fun
@@ -47,8 +58,8 @@ class Registry(dict[str, RegistryEntry]):
class SimpleRegistry(dict): class SimpleRegistry(dict):
def register(self, name, data): def register(self, name: str, data: Any):
def decorator(fun): def decorator(fun: Callable[..., Any]):
self[name] = (fun, data) self[name] = (fun, data)
return fun return fun