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

Merge branch 'retiny_includes' into integration

This commit is contained in:
J. Nick Koston
2025-07-17 20:19:47 -10:00
17 changed files with 405 additions and 43 deletions

View File

@@ -39,7 +39,7 @@ import esphome.final_validate as fv
from esphome.helpers import copy_file_if_changed, mkdir_p, write_file_if_changed
from esphome.types import ConfigType
from .boards import BOARDS
from .boards import BOARDS, STANDARD_BOARDS
from .const import ( # noqa
KEY_BOARD,
KEY_COMPONENTS,
@@ -487,25 +487,32 @@ def _platform_is_platformio(value):
def _detect_variant(value):
board = value[CONF_BOARD]
if board in BOARDS:
variant = BOARDS[board][KEY_VARIANT]
if CONF_VARIANT in value and variant != value[CONF_VARIANT]:
board = value.get(CONF_BOARD)
variant = value.get(CONF_VARIANT)
if variant and board is None:
# If variant is set, we can derive the board from it
# variant has already been validated against the known set
value = value.copy()
value[CONF_BOARD] = STANDARD_BOARDS[variant]
elif board in BOARDS:
variant = variant or BOARDS[board][KEY_VARIANT]
if variant != BOARDS[board][KEY_VARIANT]:
raise cv.Invalid(
f"Option '{CONF_VARIANT}' does not match selected board.",
path=[CONF_VARIANT],
)
value = value.copy()
value[CONF_VARIANT] = variant
elif not variant:
raise cv.Invalid(
"This board is unknown, if you are sure you want to compile with this board selection, "
f"override with option '{CONF_VARIANT}'",
path=[CONF_BOARD],
)
else:
if CONF_VARIANT not in value:
raise cv.Invalid(
"This board is unknown, if you are sure you want to compile with this board selection, "
f"override with option '{CONF_VARIANT}'",
path=[CONF_BOARD],
)
_LOGGER.warning(
"This board is unknown. Make sure the chosen chip component is correct.",
"This board is unknown; the specified variant '%s' will be used but this may not work as expected.",
variant,
)
return value
@@ -676,7 +683,7 @@ CONF_PARTITIONS = "partitions"
CONFIG_SCHEMA = cv.All(
cv.Schema(
{
cv.Required(CONF_BOARD): cv.string_strict,
cv.Optional(CONF_BOARD): cv.string_strict,
cv.Optional(CONF_CPU_FREQUENCY): cv.one_of(
*FULL_CPU_FREQUENCIES, upper=True
),
@@ -691,6 +698,7 @@ CONFIG_SCHEMA = cv.All(
_detect_variant,
_set_default_framework,
set_core_data,
cv.has_at_least_one_key(CONF_BOARD, CONF_VARIANT),
)

View File

@@ -2,13 +2,30 @@ from .const import (
VARIANT_ESP32,
VARIANT_ESP32C2,
VARIANT_ESP32C3,
VARIANT_ESP32C5,
VARIANT_ESP32C6,
VARIANT_ESP32H2,
VARIANT_ESP32P4,
VARIANT_ESP32S2,
VARIANT_ESP32S3,
VARIANTS,
)
STANDARD_BOARDS = {
VARIANT_ESP32: "esp32dev",
VARIANT_ESP32C2: "esp32-c2-devkitm-1",
VARIANT_ESP32C3: "esp32-c3-devkitm-1",
VARIANT_ESP32C5: "esp32-c5-devkitc-1",
VARIANT_ESP32C6: "esp32-c6-devkitm-1",
VARIANT_ESP32H2: "esp32-h2-devkitm-1",
VARIANT_ESP32P4: "esp32-p4-evboard",
VARIANT_ESP32S2: "esp32-s2-kaluga-1",
VARIANT_ESP32S3: "esp32-s3-devkitc-1",
}
# Make sure not missed here if a new variant added.
assert all(v in STANDARD_BOARDS for v in VARIANTS)
ESP32_BASE_PINS = {
"TX": 1,
"RX": 3,

View File

@@ -1,3 +1,5 @@
import logging
from esphome import automation, pins
import esphome.codegen as cg
from esphome.components import i2c
@@ -8,6 +10,7 @@ from esphome.const import (
CONF_CONTRAST,
CONF_DATA_PINS,
CONF_FREQUENCY,
CONF_I2C,
CONF_I2C_ID,
CONF_ID,
CONF_PIN,
@@ -20,6 +23,9 @@ from esphome.const import (
)
from esphome.core import CORE
from esphome.core.entity_helpers import setup_entity
import esphome.final_validate as fv
_LOGGER = logging.getLogger(__name__)
DEPENDENCIES = ["esp32"]
@@ -250,6 +256,22 @@ CONFIG_SCHEMA = cv.All(
cv.has_exactly_one_key(CONF_I2C_PINS, CONF_I2C_ID),
)
def _final_validate(config):
if CONF_I2C_PINS not in config:
return
fconf = fv.full_config.get()
if fconf.get(CONF_I2C):
raise cv.Invalid(
"The `i2c_pins:` config option is incompatible with an dedicated `i2c:` block, use `i2c_id` instead"
)
_LOGGER.warning(
"The `i2c_pins:` config option is deprecated. Use `i2c_id:` with a dedicated `i2c:` definition instead."
)
FINAL_VALIDATE_SCHEMA = _final_validate
SETTERS = {
# pin assignment
CONF_DATA_PINS: "set_data_pins",

View File

@@ -193,7 +193,7 @@ def validate_local_no_higher_than_global(value):
Logger = logger_ns.class_("Logger", cg.Component)
LoggerMessageTrigger = logger_ns.class_(
"LoggerMessageTrigger",
automation.Trigger.template(cg.int_, cg.const_char_ptr, cg.const_char_ptr),
automation.Trigger.template(cg.uint8, cg.const_char_ptr, cg.const_char_ptr),
)
@@ -390,7 +390,7 @@ async def to_code(config):
await automation.build_automation(
trigger,
[
(cg.int_, "level"),
(cg.uint8, "level"),
(cg.const_char_ptr, "tag"),
(cg.const_char_ptr, "message"),
],

View File

@@ -14,6 +14,7 @@ from esphome.const import (
CONF_VALUE,
CONF_WIDTH,
)
from esphome.cpp_generator import IntLiteral
from ..automation import action_to_code
from ..defines import (
@@ -188,6 +189,8 @@ class MeterType(WidgetType):
rotation = 90 + (360 - scale_conf[CONF_ANGLE_RANGE]) / 2
if CONF_ROTATION in scale_conf:
rotation = await lv_angle.process(scale_conf[CONF_ROTATION])
if isinstance(rotation, IntLiteral):
rotation = int(str(rotation)) // 10
with LocalVariable(
"meter_var", "lv_meter_scale_t", lv_expr.meter_add_scale(var)
) as meter_var:

View File

@@ -158,14 +158,14 @@ template<typename... Ts> class DelayAction : public Action<Ts...>, public Compon
void play_complex(Ts... x) override {
auto f = std::bind(&DelayAction<Ts...>::play_next_, this, x...);
this->num_running_++;
this->set_timeout(this->delay_.value(x...), f);
this->set_timeout("delay", this->delay_.value(x...), f);
}
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void play(Ts... x) override { /* ignore - see play_complex */
}
void stop() override { this->cancel_timeout(""); }
void stop() override { this->cancel_timeout("delay"); }
};
template<typename... Ts> class LambdaAction : public Action<Ts...> {

View File

@@ -255,10 +255,10 @@ void Component::defer(const char *name, std::function<void()> &&f) { // NOLINT
App.scheduler.set_timeout(this, name, 0, std::move(f));
}
void Component::set_timeout(uint32_t timeout, std::function<void()> &&f) { // NOLINT
App.scheduler.set_timeout(this, "", timeout, std::move(f));
App.scheduler.set_timeout(this, static_cast<const char *>(nullptr), timeout, std::move(f));
}
void Component::set_interval(uint32_t interval, std::function<void()> &&f) { // NOLINT
App.scheduler.set_interval(this, "", interval, std::move(f));
App.scheduler.set_interval(this, static_cast<const char *>(nullptr), interval, std::move(f));
}
void Component::set_retry(uint32_t initial_wait_time, uint8_t max_attempts, std::function<RetryResult(uint8_t)> &&f,
float backoff_increase_factor) { // NOLINT

View File

@@ -1,6 +1,6 @@
#pragma once
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
#if defined(USE_ESP32)
#include <atomic>
#include <cstddef>
@@ -78,4 +78,4 @@ template<class T, uint8_t SIZE> class EventPool {
} // namespace esphome
#endif // defined(USE_ESP32) || defined(USE_LIBRETINY)
#endif // defined(USE_ESP32)

View File

@@ -1,17 +1,12 @@
#pragma once
#if defined(USE_ESP32) || defined(USE_LIBRETINY)
#if defined(USE_ESP32)
#include <atomic>
#include <cstddef>
#if defined(USE_ESP32)
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#elif defined(USE_LIBRETINY)
#include <FreeRTOS.h>
#include <task.h>
#endif
/*
* Lock-free queue for single-producer single-consumer scenarios.
@@ -148,4 +143,4 @@ template<class T, uint8_t SIZE> class NotifyingLockFreeQueue : public LockFreeQu
} // namespace esphome
#endif // defined(USE_ESP32) || defined(USE_LIBRETINY)
#endif // defined(USE_ESP32)

View File

@@ -8,6 +8,7 @@
#include <algorithm>
#include <cinttypes>
#include <cstring>
#include <limits>
namespace esphome {
@@ -15,7 +16,7 @@ static const char *const TAG = "scheduler";
static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10;
// Half the 32-bit range - used to detect rollovers vs normal time progression
static const uint32_t HALF_MAX_UINT32 = 0x80000000UL;
static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
// Uncomment to debug scheduler
// #define ESPHOME_DEBUG_SCHEDULER
@@ -452,7 +453,7 @@ bool HOT Scheduler::cancel_item_(Component *component, bool is_static_string, co
// Helper to cancel items by name - must be called with lock held
bool HOT Scheduler::cancel_item_locked_(Component *component, const char *name_cstr, SchedulerItem::Type type) {
// Early return if name is invalid - no items to cancel
if (name_cstr == nullptr || name_cstr[0] == '\0') {
if (name_cstr == nullptr) {
return false;
}
@@ -518,8 +519,8 @@ uint64_t Scheduler::millis_64_(uint32_t now) {
// This covers any reasonable scheduler delays or thread preemption
static const uint32_t ROLLOVER_WINDOW = 10000; // 10 seconds in milliseconds
// Check if we're near the rollover boundary (close to 0xFFFFFFFF or just past 0)
bool near_rollover = (last > (0xFFFFFFFF - ROLLOVER_WINDOW)) || (now < ROLLOVER_WINDOW);
// Check if we're near the rollover boundary (close to std::numeric_limits<uint32_t>::max() or just past 0)
bool near_rollover = (last > (std::numeric_limits<uint32_t>::max() - ROLLOVER_WINDOW)) || (now < ROLLOVER_WINDOW);
if (near_rollover || (now < last && (last - now) > HALF_MAX_UINT32)) {
// Near rollover or detected a rollover - need lock for safety

View File

@@ -121,16 +121,17 @@ class Scheduler {
name_is_dynamic = false;
}
if (!name || !name[0]) {
if (!name) {
// nullptr case - no name provided
name_.static_name = nullptr;
} else if (make_copy) {
// Make a copy for dynamic strings
// Make a copy for dynamic strings (including empty strings)
size_t len = strlen(name);
name_.dynamic_name = new char[len + 1];
memcpy(name_.dynamic_name, name, len + 1);
name_is_dynamic = true;
} else {
// Use static string directly
// Use static string directly (including empty strings)
name_.static_name = name;
}
}
@@ -217,8 +218,7 @@ class Scheduler {
// Platforms without atomic support or single-threaded platforms
uint32_t last_millis_{0};
#endif
// millis_major_ is protected by lock when incrementing, volatile ensures
// reads outside the lock see fresh values (not cached in registers)
// millis_major_ is protected by lock when incrementing
uint16_t millis_major_{0};
uint32_t to_remove_{0};
};