Merge remote-tracking branch 'origin/dev' into ethernet-rp2040-w5500-impl

# Conflicts:
#	esphome/components/ethernet/__init__.py
#	esphome/components/ethernet/ethernet_component.h
This commit is contained in:
J. Nick Koston
2026-03-15 15:21:20 -10:00
30 changed files with 101 additions and 73 deletions
+3 -3
View File
@@ -36,11 +36,11 @@ struct SavedNoisePsk {
} PACKED; // NOLINT
#endif
class APIServer : public Component,
public Controller
class APIServer final : public Component,
public Controller
#ifdef USE_CAMERA
,
public camera::CameraListener
public camera::CameraListener
#endif
{
public:
+1 -1
View File
@@ -37,7 +37,7 @@ class TimeoutFilter : public Filter, public Component {
TemplatableValue<uint32_t> timeout_delay_{};
};
class DelayedOnOffFilter : public Filter, public Component {
class DelayedOnOffFilter final : public Filter, public Component {
public:
optional<bool> new_value(bool value) override;
+4 -2
View File
@@ -612,10 +612,12 @@ def _format_framework_espidf_version(
ext = "tar.xz"
else:
ext = "zip"
# Build version string with dot-separated extra (e.g., "5.5.3.1" not "5.5.3-1")
# Build version string with extra separator based on type:
# numeric extra uses dot (e.g., "5.5.3.1"), string extra uses dash (e.g., "6.0.0-rc1")
ver_str = f"{ver.major}.{ver.minor}.{ver.patch}"
if ver.extra:
ver_str += f".{ver.extra}"
sep = "." if str(ver.extra).isdigit() else "-"
ver_str += f"{sep}{ver.extra}"
if release:
return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{ver_str}.{release}/esp-idf-v{ver_str}.{ext}"
return f"pioarduino/framework-espidf@https://github.com/pioarduino/esp-idf/releases/download/v{ver_str}/esp-idf-v{ver_str}.{ext}"
@@ -39,7 +39,7 @@ class GPIOBinarySensorStore {
Component *component_{nullptr}; // Pointer to the component for enable_loop_soon_any_context()
};
class GPIOBinarySensor : public binary_sensor::BinarySensor, public Component {
class GPIOBinarySensor final : public binary_sensor::BinarySensor, public Component {
public:
// No destructor needed: ESPHome components are created at boot and live forever.
// Interrupts are only detached on reboot when memory is cleared anyway.
+1 -1
View File
@@ -8,7 +8,7 @@
namespace esphome {
namespace gpio {
class GPIOSwitch : public switch_::Switch, public Component {
class GPIOSwitch final : public switch_::Switch, public Component {
public:
void set_pin(GPIOPin *pin) { pin_ = pin; }
@@ -7,7 +7,7 @@
namespace esphome {
namespace homeassistant {
class HomeassistantTime : public time::RealTimeClock {
class HomeassistantTime final : public time::RealTimeClock {
public:
void setup() override;
void update() override;
+2 -1
View File
@@ -3,6 +3,7 @@
#ifdef USE_ESP32
#include <driver/gpio.h>
#include <driver/ledc.h>
#include <cinttypes>
#include <esp_idf_version.h>
@@ -189,7 +190,7 @@ void LEDCOutput::setup() {
this->phase_angle_, hpoint);
ledc_channel_config_t chan_conf{};
chan_conf.gpio_num = this->pin_->get_pin();
chan_conf.gpio_num = static_cast<gpio_num_t>(this->pin_->get_pin());
chan_conf.speed_mode = speed_mode;
chan_conf.channel = chan_num;
chan_conf.intr_type = LEDC_INTR_DISABLE;
+1 -1
View File
@@ -32,7 +32,7 @@
namespace esphome {
namespace md5 {
class MD5Digest : public HashBase {
class MD5Digest final : public HashBase {
public:
MD5Digest() = default;
~MD5Digest() override;
+9 -8
View File
@@ -4,7 +4,8 @@
#include "esphome/core/hal.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esp_lcd_panel_rgb.h"
#include <driver/gpio.h>
#include <esp_lcd_panel_rgb.h>
#include <span>
namespace esphome {
@@ -153,18 +154,18 @@ void MipiRgb::common_setup_() {
config.clk_src = LCD_CLK_SRC_PLL160M;
size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]);
for (size_t i = 0; i != data_pin_count; i++) {
config.data_gpio_nums[i] = this->data_pins_[i]->get_pin();
config.data_gpio_nums[i] = static_cast<gpio_num_t>(this->data_pins_[i]->get_pin());
}
config.data_width = data_pin_count;
config.disp_gpio_num = -1;
config.hsync_gpio_num = this->hsync_pin_->get_pin();
config.vsync_gpio_num = this->vsync_pin_->get_pin();
config.disp_gpio_num = GPIO_NUM_NC;
config.hsync_gpio_num = static_cast<gpio_num_t>(this->hsync_pin_->get_pin());
config.vsync_gpio_num = static_cast<gpio_num_t>(this->vsync_pin_->get_pin());
if (this->de_pin_) {
config.de_gpio_num = this->de_pin_->get_pin();
config.de_gpio_num = static_cast<gpio_num_t>(this->de_pin_->get_pin());
} else {
config.de_gpio_num = -1;
config.de_gpio_num = GPIO_NUM_NC;
}
config.pclk_gpio_num = this->pclk_pin_->get_pin();
config.pclk_gpio_num = static_cast<gpio_num_t>(this->pclk_pin_->get_pin());
esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_);
if (err == ESP_OK)
err = esp_lcd_panel_reset(this->handle_);
+7 -1
View File
@@ -3,7 +3,9 @@ from esphome.automation import Condition
import esphome.codegen as cg
from esphome.components import logger, socket
from esphome.components.esp32 import (
add_idf_component,
add_idf_sdkconfig_option,
idf_version,
include_builtin_idf_component,
)
from esphome.config_helpers import filter_source_files_from_platform
@@ -351,7 +353,11 @@ async def to_code(config):
if CORE.is_esp32:
socket.require_wake_loop_threadsafe()
# Re-enable ESP-IDF's mqtt component (excluded by default to save compile time)
include_builtin_idf_component("mqtt")
# IDF 6.0 moved esp-mqtt to an external component
if idf_version() >= cv.Version(6, 0, 0):
add_idf_component(name="espressif/mqtt", ref="1.0.0")
else:
include_builtin_idf_component("mqtt")
cg.add_define("USE_MQTT")
cg.add_global(mqtt_ns.using)
+1 -1
View File
@@ -6,7 +6,7 @@
namespace esphome {
namespace preferences {
class IntervalSyncer : public Component {
class IntervalSyncer final : public Component {
public:
void set_write_interval(uint32_t write_interval) { this->write_interval_ = write_interval; }
void setup() override {
@@ -2,6 +2,7 @@
#include "esphome/core/log.h"
#ifdef HAS_PCNT
#include <driver/gpio.h>
#include <esp_private/esp_clk.h>
#include <hal/pcnt_ll.h>
#endif
@@ -76,8 +77,8 @@ bool HwPulseCounterStorage::pulse_counter_setup(InternalGPIOPin *pin) {
}
pcnt_chan_config_t chan_config = {
.edge_gpio_num = this->pin->get_pin(),
.level_gpio_num = -1,
.edge_gpio_num = static_cast<gpio_num_t>(this->pin->get_pin()),
.level_gpio_num = GPIO_NUM_NC,
};
error = pcnt_new_channel(this->pcnt_unit, &chan_config, &this->pcnt_channel);
if (error != ESP_OK) {
@@ -6,7 +6,7 @@
namespace esphome {
namespace restart {
class RestartButton : public button::Button, public Component {
class RestartButton final : public button::Button, public Component {
public:
void dump_config() override;
@@ -2,6 +2,7 @@
#include "rpi_dpi_rgb.h"
#include "esphome/core/gpio.h"
#include "esphome/core/log.h"
#include <driver/gpio.h>
namespace esphome {
namespace rpi_dpi_rgb {
@@ -25,14 +26,14 @@ void RpiDpiRgb::setup() {
config.clk_src = LCD_CLK_SRC_PLL160M;
size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]);
for (size_t i = 0; i != data_pin_count; i++) {
config.data_gpio_nums[i] = this->data_pins_[i]->get_pin();
config.data_gpio_nums[i] = static_cast<gpio_num_t>(this->data_pins_[i]->get_pin());
}
config.data_width = data_pin_count;
config.disp_gpio_num = -1;
config.hsync_gpio_num = this->hsync_pin_->get_pin();
config.vsync_gpio_num = this->vsync_pin_->get_pin();
config.de_gpio_num = this->de_pin_->get_pin();
config.pclk_gpio_num = this->pclk_pin_->get_pin();
config.disp_gpio_num = GPIO_NUM_NC;
config.hsync_gpio_num = static_cast<gpio_num_t>(this->hsync_pin_->get_pin());
config.vsync_gpio_num = static_cast<gpio_num_t>(this->vsync_pin_->get_pin());
config.de_gpio_num = static_cast<gpio_num_t>(this->de_pin_->get_pin());
config.pclk_gpio_num = static_cast<gpio_num_t>(this->pclk_pin_->get_pin());
esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_);
if (err != ESP_OK) {
ESP_LOGE(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err));
+3 -3
View File
@@ -68,7 +68,7 @@ void RX8130Component::dump_config() {
void RX8130Component::read_time() {
uint8_t date[7];
if (this->read_register(RX8130_REG_SEC, date, 7) != i2c::ERROR_OK) {
this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
return;
}
ESPTime rtc_time{
@@ -109,7 +109,7 @@ void RX8130Component::write_time() {
buff[6] = dec2bcd(now.year % 100);
this->stop_(true);
if (this->write_register(RX8130_REG_SEC, buff, 7) != i2c::ERROR_OK) {
this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
} else {
ESP_LOGD(TAG, "Wrote UTC time: %04d-%02d-%02d %02d:%02d:%02d", now.year, now.month, now.day_of_month, now.hour,
now.minute, now.second);
@@ -120,7 +120,7 @@ void RX8130Component::write_time() {
void RX8130Component::stop_(bool stop) {
const uint8_t data = stop ? RX8130_BIT_CTRL_STOP : RX8130_CLEAR_FLAGS;
if (this->write_register(RX8130_REG_CTRL0, &data, 1) != i2c::ERROR_OK) {
this->status_set_warning(ESP_LOG_MSG_COMM_FAIL);
this->status_set_warning(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
}
}
@@ -7,7 +7,7 @@
namespace esphome {
namespace safe_mode {
class SafeModeButton : public button::Button, public Component {
class SafeModeButton final : public button::Button, public Component {
public:
void dump_config() override;
void set_safe_mode(SafeModeComponent *safe_mode_component);
+1 -1
View File
@@ -48,7 +48,7 @@ namespace esphome::sha256 {
/// hasher.init();
/// hasher.add(data, len);
/// hasher.calculate();
class SHA256 : public esphome::HashBase {
class SHA256 final : public esphome::HashBase {
public:
SHA256() = default;
~SHA256() override;
+7 -6
View File
@@ -2,6 +2,7 @@
#include "st7701s.h"
#include "esphome/core/gpio.h"
#include "esphome/core/log.h"
#include <driver/gpio.h>
namespace esphome {
namespace st7701s {
@@ -27,14 +28,14 @@ void ST7701S::setup() {
config.clk_src = LCD_CLK_SRC_PLL160M;
size_t data_pin_count = sizeof(this->data_pins_) / sizeof(this->data_pins_[0]);
for (size_t i = 0; i != data_pin_count; i++) {
config.data_gpio_nums[i] = this->data_pins_[i]->get_pin();
config.data_gpio_nums[i] = static_cast<gpio_num_t>(this->data_pins_[i]->get_pin());
}
config.data_width = data_pin_count;
config.disp_gpio_num = -1;
config.hsync_gpio_num = this->hsync_pin_->get_pin();
config.vsync_gpio_num = this->vsync_pin_->get_pin();
config.de_gpio_num = this->de_pin_->get_pin();
config.pclk_gpio_num = this->pclk_pin_->get_pin();
config.disp_gpio_num = GPIO_NUM_NC;
config.hsync_gpio_num = static_cast<gpio_num_t>(this->hsync_pin_->get_pin());
config.vsync_gpio_num = static_cast<gpio_num_t>(this->vsync_pin_->get_pin());
config.de_gpio_num = static_cast<gpio_num_t>(this->de_pin_->get_pin());
config.pclk_gpio_num = static_cast<gpio_num_t>(this->pclk_pin_->get_pin());
esp_err_t err = esp_lcd_new_rgb_panel(&config, &this->handle_);
if (err != ESP_OK) {
esph_log_e(TAG, "lcd_new_rgb_panel failed: %s", esp_err_to_name(err));
+1 -1
View File
@@ -416,7 +416,7 @@ void USBUartTypeCdcAcm::on_connected() {
for (auto *channel : this->channels_) {
if (i == cdc_devs.size()) {
ESP_LOGE(TAG, "No configuration found for channel %d", channel->index_);
this->status_set_warning("No configuration found for channel");
this->status_set_warning(LOG_STR("No configuration found for channel"));
break;
}
channel->cdc_dev_ = cdc_devs[i++];
@@ -5,7 +5,7 @@
namespace esphome::version {
class VersionTextSensor : public text_sensor::TextSensor, public Component {
class VersionTextSensor final : public text_sensor::TextSensor, public Component {
public:
void set_hide_hash(bool hide_hash);
void set_hide_timestamp(bool hide_timestamp);
+1 -1
View File
@@ -399,7 +399,7 @@ class WiFiPowerSaveListener {
};
/// This component is responsible for managing the ESP WiFi interface.
class WiFiComponent : public Component {
class WiFiComponent final : public Component {
public:
/// Construct a WiFiComponent.
WiFiComponent();
@@ -90,7 +90,7 @@ void ZWaveProxy::process_uart_() {
while (this->available()) {
uint8_t byte;
if (!this->read_byte(&byte)) {
this->status_set_warning("UART read failed");
this->status_set_warning(LOG_STR("UART read failed"));
return;
}
if (this->parse_byte_(byte)) {
+1
View File
@@ -392,6 +392,7 @@ bool Component::set_status_flag_(uint8_t flag) {
return true;
}
void Component::status_set_warning() { this->status_set_warning((const LogString *) nullptr); }
void Component::status_set_warning(const char *message) {
if (!this->set_status_flag_(STATUS_LED_WARNING))
return;
+2 -1
View File
@@ -240,7 +240,8 @@ class Component {
bool status_has_error() const { return this->component_state_ & STATUS_LED_ERROR; }
void status_set_warning(const char *message = nullptr);
void status_set_warning(); // Set warning flag without message
void status_set_warning(const char *message);
void status_set_warning(const LogString *message);
void status_set_error(); // Set error flag without message
+4
View File
@@ -37,5 +37,9 @@ dependencies:
version: 0.3.2
rules:
- if: "target in [esp32, esp32s2, esp32s3, esp32c6, esp32p4]"
espressif/mqtt:
version: "1.0.0"
rules:
- if: "idf_version >=6.0.0"
esp32async/asynctcp:
version: 3.4.91
+12 -3
View File
@@ -7,17 +7,26 @@ import subprocess
import sys
import tempfile
from esphome import config_validation as cv
from esphome.components.esp32 import PLATFORM_VERSION_LOOKUP
from esphome.helpers import write_file_if_changed
ver = PLATFORM_VERSION_LOOKUP["recommended"]
version_str = f"{ver.major}.{ver.minor:02d}.{ver.patch:02d}"
root = Path(__file__).parent.parent
boards_file_path = root / "esphome" / "components" / "esp32" / "boards.py"
def get_boards():
with tempfile.TemporaryDirectory() as tempdir:
if isinstance(ver, cv.Version):
branch = f"{ver.major}.{ver.minor:02d}.{ver.patch:02d}"
if ver.extra:
branch += f"-{ver.extra}"
repo = "https://github.com/pioarduino/platform-espressif32"
else:
# URL format: "https://github.com/user/repo.git#branch"
url = str(ver)
repo, branch = url.rsplit("#", 1) if "#" in url else (url, "main")
subprocess.run(
[
"git",
@@ -28,8 +37,8 @@ def get_boards():
"--depth",
"1",
"--branch",
f"{ver.major}.{ver.minor:02d}.{ver.patch:02d}",
"https://github.com/pioarduino/platform-espressif32",
branch,
repo,
tempdir,
],
check=True,
@@ -3,7 +3,7 @@ esphome:
host:
api:
batch_delay: 0ms # Disable batching to receive all state updates
batch_delay: 0ms # Disable batching to receive all state updates
logger:
level: DEBUG
@@ -15,8 +15,8 @@ sensor:
- platform: copy
source_id: source_nan_sensor
name: "Min NaN Sensor"
id: min_nan_sensor
name: "Min NaN"
id: min_nan
filters:
- min:
window_size: 5
@@ -25,8 +25,8 @@ sensor:
- platform: copy
source_id: source_nan_sensor
name: "Max NaN Sensor"
id: max_nan_sensor
name: "Max NaN"
id: max_nan
filters:
- max:
window_size: 5
@@ -42,7 +42,7 @@ script:
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
state: !lambda 'return NAN;'
state: !lambda "return NAN;"
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
@@ -50,7 +50,7 @@ script:
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
state: !lambda 'return NAN;'
state: !lambda "return NAN;"
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
@@ -62,7 +62,7 @@ script:
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
state: !lambda 'return NAN;'
state: !lambda "return NAN;"
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
@@ -74,7 +74,7 @@ script:
- delay: 20ms
- sensor.template.publish:
id: source_nan_sensor
state: !lambda 'return NAN;'
state: !lambda "return NAN;"
button:
- platform: template
@@ -3,7 +3,7 @@ esphome:
host:
api:
batch_delay: 0ms # Disable batching to receive all state updates
batch_delay: 0ms # Disable batching to receive all state updates
logger:
level: DEBUG
@@ -18,8 +18,8 @@ sensor:
# Window of 5, send every 2 values
- platform: copy
source_id: source_sensor
name: "Sliding Min Sensor"
id: sliding_min_sensor
name: "Sliding Min"
id: sliding_min
filters:
- min:
window_size: 5
@@ -28,8 +28,8 @@ sensor:
- platform: copy
source_id: source_sensor
name: "Sliding Max Sensor"
id: sliding_max_sensor
name: "Sliding Max"
id: sliding_max
filters:
- max:
window_size: 5
@@ -38,8 +38,8 @@ sensor:
- platform: copy
source_id: source_sensor
name: "Sliding Median Sensor"
id: sliding_median_sensor
name: "Sliding Median"
id: sliding_median
filters:
- median:
window_size: 5
@@ -48,8 +48,8 @@ sensor:
- platform: copy
source_id: source_sensor
name: "Sliding Moving Avg Sensor"
id: sliding_moving_avg_sensor
name: "Sliding Moving Avg"
id: sliding_moving_avg
filters:
- sliding_window_moving_average:
window_size: 5
@@ -3,20 +3,20 @@ esphome:
host:
api:
batch_delay: 0ms # Disable batching to receive all state updates
batch_delay: 0ms # Disable batching to receive all state updates
logger:
level: DEBUG
sensor:
- platform: template
name: "Source Wraparound Sensor"
name: "Source Wraparound"
id: source_wraparound
accuracy_decimals: 2
- platform: copy
source_id: source_wraparound
name: "Wraparound Min Sensor"
id: wraparound_min_sensor
name: "Wraparound Min"
id: wraparound_min
filters:
- min:
window_size: 3
+2 -2
View File
@@ -88,7 +88,7 @@ def build_key_to_entity_mapping(
Args:
entities: List of entity info objects from the API
entity_names: List of entity names to search for in object_ids
entity_names: List of entity names to match exactly against object_ids
Returns:
Dictionary mapping entity keys to entity names
@@ -97,7 +97,7 @@ def build_key_to_entity_mapping(
for entity in entities:
obj_id = entity.object_id.lower()
for entity_name in entity_names:
if entity_name in obj_id:
if entity_name == obj_id:
key_to_entity[entity.key] = entity_name
break
return key_to_entity