mirror of
https://github.com/esphome/esphome.git
synced 2025-11-16 14:55:50 +00:00
Compare commits
10 Commits
template_a
...
switch_to_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae343a94ca | ||
|
|
d7892f2289 | ||
|
|
b7f6013378 | ||
|
|
fb9e7028a0 | ||
|
|
1df996601d | ||
|
|
c32891ec02 | ||
|
|
2bf6d48fcf | ||
|
|
e49a943cf7 | ||
|
|
67524e14ee | ||
|
|
2290eb0dd2 |
4
.github/workflows/codeql.yml
vendored
4
.github/workflows/codeql.yml
vendored
@@ -58,7 +58,7 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
|
||||
uses: github/codeql-action/init@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ matrix.build-mode }}
|
||||
@@ -86,6 +86,6 @@ jobs:
|
||||
exit 1
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@0499de31b99561a6d14a36a5f662c2a54f91beee # v4.31.2
|
||||
uses: github/codeql-action/analyze@014f16e7ab1402f30e7c3329d33797e7948572db # v4.31.3
|
||||
with:
|
||||
category: "/language:${{matrix.language}}"
|
||||
|
||||
@@ -11,7 +11,7 @@ ci:
|
||||
repos:
|
||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
# Ruff version.
|
||||
rev: v0.14.4
|
||||
rev: v0.14.5
|
||||
hooks:
|
||||
# Run the linter.
|
||||
- id: ruff
|
||||
|
||||
@@ -51,13 +51,14 @@ template<typename... Ts> class UserServiceBase : public UserServiceDescriptor {
|
||||
return false;
|
||||
if (req.args.size() != sizeof...(Ts))
|
||||
return false;
|
||||
this->execute_(req.args, typename gens<sizeof...(Ts)>::type());
|
||||
this->execute_(req.args, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void execute(Ts... x) = 0;
|
||||
template<typename ArgsContainer, int... S> void execute_(const ArgsContainer &args, seq<S...> type) {
|
||||
template<typename ArgsContainer, size_t... S>
|
||||
void execute_(const ArgsContainer &args, std::index_sequence<S...> type) {
|
||||
this->execute((get_execute_arg_value<Ts>(args[S]))...);
|
||||
}
|
||||
|
||||
@@ -95,13 +96,14 @@ template<typename... Ts> class UserServiceDynamic : public UserServiceDescriptor
|
||||
return false;
|
||||
if (req.args.size() != sizeof...(Ts))
|
||||
return false;
|
||||
this->execute_(req.args, typename gens<sizeof...(Ts)>::type());
|
||||
this->execute_(req.args, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void execute(Ts... x) = 0;
|
||||
template<typename ArgsContainer, int... S> void execute_(const ArgsContainer &args, seq<S...> type) {
|
||||
template<typename ArgsContainer, size_t... S>
|
||||
void execute_(const ArgsContainer &args, std::index_sequence<S...> type) {
|
||||
this->execute((get_execute_arg_value<Ts>(args[S]))...);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,8 +52,10 @@ static void log_invalid_parameter(const char *name, const LogString *message) {
|
||||
}
|
||||
|
||||
static const LogString *color_mode_to_human(ColorMode color_mode) {
|
||||
if (color_mode == ColorMode::UNKNOWN)
|
||||
return LOG_STR("Unknown");
|
||||
if (color_mode == ColorMode::ON_OFF)
|
||||
return LOG_STR("On/Off");
|
||||
if (color_mode == ColorMode::BRIGHTNESS)
|
||||
return LOG_STR("Brightness");
|
||||
if (color_mode == ColorMode::WHITE)
|
||||
return LOG_STR("White");
|
||||
if (color_mode == ColorMode::COLOR_TEMPERATURE)
|
||||
@@ -68,7 +70,7 @@ static const LogString *color_mode_to_human(ColorMode color_mode) {
|
||||
return LOG_STR("RGB + cold/warm white");
|
||||
if (color_mode == ColorMode::RGB_COLOR_TEMPERATURE)
|
||||
return LOG_STR("RGB + color temperature");
|
||||
return LOG_STR("");
|
||||
return LOG_STR("Unknown");
|
||||
}
|
||||
|
||||
// Helper to log percentage values
|
||||
|
||||
@@ -46,14 +46,14 @@ template<typename... Ts> class Script : public ScriptLogger, public Trigger<Ts..
|
||||
|
||||
// execute this script using a tuple that contains the arguments
|
||||
void execute_tuple(const std::tuple<Ts...> &tuple) {
|
||||
this->execute_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
|
||||
this->execute_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
// Internal function to give scripts readable names.
|
||||
void set_name(const LogString *name) { name_ = name; }
|
||||
|
||||
protected:
|
||||
template<int... S> void execute_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> void execute_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
this->execute(std::get<S>(tuple)...);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ template<typename... Ts> class QueueingScript : public Script<Ts...>, public Com
|
||||
const size_t queue_capacity = static_cast<size_t>(this->max_runs_ - 1);
|
||||
auto tuple_ptr = std::move(this->var_queue_[this->queue_front_]);
|
||||
this->queue_front_ = (this->queue_front_ + 1) % queue_capacity;
|
||||
this->trigger_tuple_(*tuple_ptr, typename gens<sizeof...(Ts)>::type());
|
||||
this->trigger_tuple_(*tuple_ptr, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ template<typename... Ts> class QueueingScript : public Script<Ts...>, public Com
|
||||
}
|
||||
}
|
||||
|
||||
template<int... S> void trigger_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> void trigger_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
this->trigger(std::get<S>(tuple)...);
|
||||
}
|
||||
|
||||
@@ -305,7 +305,7 @@ template<class C, typename... Ts> class ScriptWaitAction : public Action<Ts...>,
|
||||
|
||||
while (!this->param_queue_.empty()) {
|
||||
auto ¶ms = this->param_queue_.front();
|
||||
this->play_next_tuple_(params, typename gens<sizeof...(Ts)>::type());
|
||||
this->play_next_tuple_(params, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
this->param_queue_.pop_front();
|
||||
}
|
||||
// Queue is now empty - disable loop until next play_complex
|
||||
@@ -321,7 +321,7 @@ template<class C, typename... Ts> class ScriptWaitAction : public Action<Ts...>,
|
||||
}
|
||||
|
||||
protected:
|
||||
template<int... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
this->play_next_(std::get<S>(tuple)...);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
from logging import getLogger
|
||||
import math
|
||||
import re
|
||||
|
||||
@@ -35,6 +36,8 @@ from esphome.core import CORE, ID
|
||||
import esphome.final_validate as fv
|
||||
from esphome.yaml_util import make_data_base
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
uart_ns = cg.esphome_ns.namespace("uart")
|
||||
UARTComponent = uart_ns.class_("UARTComponent")
|
||||
@@ -130,6 +133,21 @@ def validate_host_config(config):
|
||||
return config
|
||||
|
||||
|
||||
def validate_rx_buffer_size(config):
|
||||
if CORE.is_esp32:
|
||||
# ESP32 UART hardware FIFO is 128 bytes (LP UART is 16 bytes, but we use 128 as safe minimum)
|
||||
# rx_buffer_size must be greater than the hardware FIFO length
|
||||
min_buffer_size = 128
|
||||
if config[CONF_RX_BUFFER_SIZE] <= min_buffer_size:
|
||||
_LOGGER.warning(
|
||||
"UART rx_buffer_size (%d bytes) is too small and must be greater than the hardware "
|
||||
"FIFO size (%d bytes). The buffer size will be automatically adjusted at runtime.",
|
||||
config[CONF_RX_BUFFER_SIZE],
|
||||
min_buffer_size,
|
||||
)
|
||||
return config
|
||||
|
||||
|
||||
def _uart_declare_type(value):
|
||||
if CORE.is_esp8266:
|
||||
return cv.declare_id(ESP8266UartComponent)(value)
|
||||
@@ -247,6 +265,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN, CONF_PORT),
|
||||
validate_host_config,
|
||||
validate_rx_buffer_size,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -91,6 +91,16 @@ void IDFUARTComponent::setup() {
|
||||
this->uart_num_ = static_cast<uart_port_t>(next_uart_num++);
|
||||
this->lock_ = xSemaphoreCreateMutex();
|
||||
|
||||
#if (SOC_UART_LP_NUM >= 1)
|
||||
size_t fifo_len = ((this->uart_num_ < SOC_UART_HP_NUM) ? SOC_UART_FIFO_LEN : SOC_LP_UART_FIFO_LEN);
|
||||
#else
|
||||
size_t fifo_len = SOC_UART_FIFO_LEN;
|
||||
#endif
|
||||
if (this->rx_buffer_size_ <= fifo_len) {
|
||||
ESP_LOGW(TAG, "rx_buffer_size is too small, must be greater than %zu", fifo_len);
|
||||
this->rx_buffer_size_ = fifo_len * 2;
|
||||
}
|
||||
|
||||
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
||||
|
||||
this->load_settings(false);
|
||||
@@ -237,8 +247,12 @@ void IDFUARTComponent::set_rx_timeout(size_t rx_timeout) {
|
||||
|
||||
void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
|
||||
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
||||
uart_write_bytes(this->uart_num_, data, len);
|
||||
int32_t write_len = uart_write_bytes(this->uart_num_, data, len);
|
||||
xSemaphoreGive(this->lock_);
|
||||
if (write_len != (int32_t) len) {
|
||||
ESP_LOGW(TAG, "uart_write_bytes failed: %d != %zu", write_len, len);
|
||||
this->mark_failed();
|
||||
}
|
||||
#ifdef USE_UART_DEBUGGER
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
|
||||
@@ -267,6 +281,7 @@ bool IDFUARTComponent::peek_byte(uint8_t *data) {
|
||||
|
||||
bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
|
||||
size_t length_to_read = len;
|
||||
int32_t read_len = 0;
|
||||
if (!this->check_read_timeout_(len))
|
||||
return false;
|
||||
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
||||
@@ -277,25 +292,31 @@ bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
|
||||
this->has_peek_ = false;
|
||||
}
|
||||
if (length_to_read > 0)
|
||||
uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
|
||||
read_len = uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
|
||||
xSemaphoreGive(this->lock_);
|
||||
#ifdef USE_UART_DEBUGGER
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
return read_len == (int32_t) length_to_read;
|
||||
}
|
||||
|
||||
int IDFUARTComponent::available() {
|
||||
size_t available;
|
||||
size_t available = 0;
|
||||
esp_err_t err;
|
||||
|
||||
xSemaphoreTake(this->lock_, portMAX_DELAY);
|
||||
uart_get_buffered_data_len(this->uart_num_, &available);
|
||||
if (this->has_peek_)
|
||||
available++;
|
||||
err = uart_get_buffered_data_len(this->uart_num_, &available);
|
||||
xSemaphoreGive(this->lock_);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGW(TAG, "uart_get_buffered_data_len failed: %s", esp_err_to_name(err));
|
||||
this->mark_failed();
|
||||
}
|
||||
if (this->has_peek_) {
|
||||
available++;
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ from esphome.components.network import (
|
||||
from esphome.components.psram import is_guaranteed as psram_is_guaranteed
|
||||
from esphome.config_helpers import filter_source_files_from_platform
|
||||
import esphome.config_validation as cv
|
||||
from esphome.config_validation import only_with_esp_idf
|
||||
from esphome.const import (
|
||||
CONF_AP,
|
||||
CONF_BSSID,
|
||||
@@ -352,7 +351,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
single=True
|
||||
),
|
||||
cv.Optional(CONF_USE_PSRAM): cv.All(
|
||||
only_with_esp_idf, cv.requires_component("psram"), cv.boolean
|
||||
cv.only_on_esp32, cv.requires_component("psram"), cv.boolean
|
||||
),
|
||||
}
|
||||
),
|
||||
|
||||
@@ -11,10 +11,26 @@
|
||||
|
||||
namespace esphome {
|
||||
|
||||
// C++20 std::index_sequence is now used for tuple unpacking
|
||||
// Legacy seq<>/gens<> pattern deprecated but kept for backwards compatibility
|
||||
// https://stackoverflow.com/questions/7858817/unpacking-a-tuple-to-call-a-matching-function-pointer/7858971#7858971
|
||||
template<int...> struct seq {}; // NOLINT
|
||||
template<int N, int... S> struct gens : gens<N - 1, N - 1, S...> {}; // NOLINT
|
||||
template<int... S> struct gens<0, S...> { using type = seq<S...>; }; // NOLINT
|
||||
// Remove before 2026.6.0
|
||||
// NOLINTBEGIN(readability-identifier-naming)
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
template<int...> struct ESPDEPRECATED("Use std::index_sequence instead. Removed in 2026.6.0", "2025.12.0") seq {};
|
||||
template<int N, int... S>
|
||||
struct ESPDEPRECATED("Use std::make_index_sequence instead. Removed in 2026.6.0", "2025.12.0") gens
|
||||
: gens<N - 1, N - 1, S...> {};
|
||||
template<int... S> struct gens<0, S...> { using type = seq<S...>; };
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
// NOLINTEND(readability-identifier-naming)
|
||||
|
||||
#define TEMPLATABLE_VALUE_(type, name) \
|
||||
protected: \
|
||||
@@ -152,11 +168,11 @@ template<typename... Ts> class Condition {
|
||||
|
||||
/// Call check with a tuple of values as parameter.
|
||||
bool check_tuple(const std::tuple<Ts...> &tuple) {
|
||||
return this->check_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
|
||||
return this->check_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
protected:
|
||||
template<int... S> bool check_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> bool check_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
return this->check(std::get<S>(tuple)...);
|
||||
}
|
||||
};
|
||||
@@ -231,11 +247,11 @@ template<typename... Ts> class Action {
|
||||
}
|
||||
}
|
||||
}
|
||||
template<int... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> void play_next_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
this->play_next_(std::get<S>(tuple)...);
|
||||
}
|
||||
void play_next_tuple_(const std::tuple<Ts...> &tuple) {
|
||||
this->play_next_tuple_(tuple, typename gens<sizeof...(Ts)>::type());
|
||||
this->play_next_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
|
||||
virtual void stop() {}
|
||||
@@ -277,7 +293,9 @@ template<typename... Ts> class ActionList {
|
||||
if (this->actions_begin_ != nullptr)
|
||||
this->actions_begin_->play_complex(x...);
|
||||
}
|
||||
void play_tuple(const std::tuple<Ts...> &tuple) { this->play_tuple_(tuple, typename gens<sizeof...(Ts)>::type()); }
|
||||
void play_tuple(const std::tuple<Ts...> &tuple) {
|
||||
this->play_tuple_(tuple, std::make_index_sequence<sizeof...(Ts)>{});
|
||||
}
|
||||
void stop() {
|
||||
if (this->actions_begin_ != nullptr)
|
||||
this->actions_begin_->stop_complex();
|
||||
@@ -298,7 +316,7 @@ template<typename... Ts> class ActionList {
|
||||
}
|
||||
|
||||
protected:
|
||||
template<int... S> void play_tuple_(const std::tuple<Ts...> &tuple, seq<S...> /*unused*/) {
|
||||
template<size_t... S> void play_tuple_(const std::tuple<Ts...> &tuple, std::index_sequence<S...> /*unused*/) {
|
||||
this->play(std::get<S>(tuple)...);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
pylint==4.0.2
|
||||
pylint==4.0.3
|
||||
flake8==7.3.0 # also change in .pre-commit-config.yaml when updating
|
||||
ruff==0.14.4 # also change in .pre-commit-config.yaml when updating
|
||||
ruff==0.14.5 # also change in .pre-commit-config.yaml when updating
|
||||
pyupgrade==3.21.1 # also change in .pre-commit-config.yaml when updating
|
||||
pre-commit
|
||||
|
||||
|
||||
Reference in New Issue
Block a user