Merge pull request #12513 from esphome/bump-2025.12.0b4

2025.12.0b4
This commit is contained in:
Jonathan Swoboda
2025-12-15 19:01:02 -05:00
committed by GitHub
7 changed files with 36 additions and 14 deletions

View File

@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
# could be handy for archiving the generated documentation or if some version
# control system is used.
PROJECT_NUMBER = 2025.12.0b3
PROJECT_NUMBER = 2025.12.0b4
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a

View File

@@ -4,6 +4,7 @@ import itertools
import logging
import os
from pathlib import Path
import re
from esphome import yaml_util
import esphome.codegen as cg
@@ -616,10 +617,13 @@ def require_vfs_dir() -> None:
def _parse_idf_component(value: str) -> ConfigType:
"""Parse IDF component shorthand syntax like 'owner/component^version'"""
if "^" not in value:
raise cv.Invalid(f"Invalid IDF component shorthand '{value}'")
name, ref = value.split("^", 1)
return {CONF_NAME: name, CONF_REF: ref}
# Match operator followed by version-like string (digit or *)
if match := re.search(r"(~=|>=|<=|==|!=|>|<|\^|~)(\d|\*)", value):
return {CONF_NAME: value[: match.start()], CONF_REF: value[match.start() :]}
raise cv.Invalid(
f"Invalid IDF component shorthand '{value}'. "
f"Expected format: 'owner/component<op>version' where <op> is one of: ^, ~, ~=, ==, !=, >=, >, <=, <"
)
def _validate_idf_component(config: ConfigType) -> ConfigType:

View File

@@ -255,6 +255,9 @@ template<typename... Ts> class HttpRequestSendAction : public Action<Ts...> {
size_t read_index = 0;
while (container->get_bytes_read() < max_length) {
int read = container->read(buf + read_index, std::min<size_t>(max_length - read_index, 512));
if (read <= 0) {
break;
}
App.feed_wdt();
yield();
read_index += read;

View File

@@ -132,11 +132,18 @@ uint8_t OtaHttpRequestComponent::do_ota_() {
App.feed_wdt();
yield();
if (bufsize < 0) {
ESP_LOGE(TAG, "Stream closed");
this->cleanup_(std::move(backend), container);
return OTA_CONNECTION_ERROR;
} else if (bufsize > 0 && bufsize <= OtaHttpRequestComponent::HTTP_RECV_BUFFER) {
// Exit loop if no data available (stream closed or end of data)
if (bufsize <= 0) {
if (bufsize < 0) {
ESP_LOGE(TAG, "Stream closed with error");
this->cleanup_(std::move(backend), container);
return OTA_CONNECTION_ERROR;
}
// bufsize == 0: no more data available, exit loop
break;
}
if (bufsize <= OtaHttpRequestComponent::HTTP_RECV_BUFFER) {
// add read bytes to MD5
md5_receive.add(buf, bufsize);
@@ -247,6 +254,9 @@ bool OtaHttpRequestComponent::http_get_md5_() {
int read_len = 0;
while (container->get_bytes_read() < MD5_SIZE) {
read_len = container->read((uint8_t *) this->md5_expected_.data(), MD5_SIZE);
if (read_len <= 0) {
break;
}
App.feed_wdt();
yield();
}

View File

@@ -76,6 +76,11 @@ void HttpRequestUpdate::update_task(void *params) {
yield();
if (read_bytes <= 0) {
// Network error or connection closed - break to avoid infinite loop
break;
}
read_index += read_bytes;
}

View File

@@ -232,10 +232,10 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
data.set_message_id(this->message_id_.value(x...));
data.auto_message_id = this->auto_message_id_.value(x...);
std::vector<uint8_t> data_vec;
if (this->len_ >= 0) {
if (this->len_ > 0) {
// Static mode: copy from flash to vector
data_vec.assign(this->data_.data, this->data_.data + this->len_);
} else {
} else if (this->len_ < 0) {
// Template mode: call function
data_vec = this->data_.func(x...);
}
@@ -245,7 +245,7 @@ template<typename... Ts> class ABBWelcomeAction : public RemoteTransmitterAction
}
protected:
ssize_t len_{-1}; // -1 = template mode, >=0 = static mode with length
ssize_t len_{0}; // <0 = template mode, >=0 = static mode with length
union Data {
std::vector<uint8_t> (*func)(Ts...); // Function pointer (stateless lambdas)
const uint8_t *data; // Pointer to static data in flash

View File

@@ -4,7 +4,7 @@ from enum import Enum
from esphome.enum import StrEnum
__version__ = "2025.12.0b3"
__version__ = "2025.12.0b4"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
VALID_SUBSTITUTIONS_CHARACTERS = (