From 950299e52bb40bb6c82ed7844f4e006023659df5 Mon Sep 17 00:00:00 2001 From: Oliver Kleinecke Date: Fri, 29 Aug 2025 02:53:54 +0200 Subject: [PATCH 1/9] Update mcp4461.cpp (#10479) --- esphome/components/mcp4461/mcp4461.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esphome/components/mcp4461/mcp4461.cpp b/esphome/components/mcp4461/mcp4461.cpp index 55ce9b7899..191fbae366 100644 --- a/esphome/components/mcp4461/mcp4461.cpp +++ b/esphome/components/mcp4461/mcp4461.cpp @@ -198,7 +198,7 @@ uint16_t Mcp4461Component::get_wiper_level_(Mcp4461WiperIdx wiper) { uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) { uint8_t addr = this->get_wiper_address_(wiper_idx); - uint8_t reg = addr | static_cast(Mcp4461Commands::INCREMENT); + uint8_t reg = addr | static_cast(Mcp4461Commands::READ); if (wiper_idx > 3) { if (!this->is_eeprom_ready_for_writing_(true)) { return 0; From de998f2f39b7f90bdd3538e5a587be55dcd0887f Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 31 Aug 2025 20:01:15 -0500 Subject: [PATCH 2/9] Fix incorrect entity count due to undefined execution order with globals (#10497) --- esphome/core/config.py | 2 +- tests/unit_tests/core/test_config.py | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/esphome/core/config.py b/esphome/core/config.py index 90768a4b09..b6ff1d8afd 100644 --- a/esphome/core/config.py +++ b/esphome/core/config.py @@ -423,7 +423,7 @@ async def _add_automations(config): DATETIME_SUBTYPES = {"date", "time", "datetime"} -@coroutine_with_priority(-100.0) +@coroutine_with_priority(-1000.0) async def _add_platform_defines() -> None: # Generate compile-time defines for platforms that have actual entities # Only add USE_* and count defines when there are entities diff --git a/tests/unit_tests/core/test_config.py b/tests/unit_tests/core/test_config.py index 46e3b513d7..f5ba5221ed 100644 --- a/tests/unit_tests/core/test_config.py +++ b/tests/unit_tests/core/test_config.py @@ -8,6 +8,7 @@ import pytest from esphome import config_validation as cv, core from esphome.const import CONF_AREA, CONF_AREAS, CONF_DEVICES +from esphome.core import config from esphome.core.config import Area, validate_area_config from .common import load_config_from_fixture @@ -223,3 +224,24 @@ def test_device_duplicate_id( # Check for the specific error message from IDPassValidationStep captured = capsys.readouterr() assert "ID duplicate_device redefined!" in captured.out + + +def test_add_platform_defines_priority() -> None: + """Test that _add_platform_defines runs after globals. + + This ensures the fix for issue #10431 where sensor counts were incorrect + when lambdas were present. The function must run at a lower priority than + globals (-100.0) to ensure all components (including those using globals + in lambdas) have registered their entities before the count defines are + generated. + + Regression test for https://github.com/esphome/esphome/issues/10431 + """ + # Import globals to check its priority + from esphome.components.globals import to_code as globals_to_code + + # _add_platform_defines must run AFTER globals (lower priority number = runs later) + assert config._add_platform_defines.priority < globals_to_code.priority, ( + f"_add_platform_defines priority ({config._add_platform_defines.priority}) must be lower than " + f"globals priority ({globals_to_code.priority}) to fix issue #10431 (sensor count bug with lambdas)" + ) From c55bc93f70dc788341b33ea258abb719e78740a2 Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:51:31 +1000 Subject: [PATCH 3/9] [mipi_dsi] Fix config for Guition screen (#10464) --- esphome/components/mipi_dsi/models/guition.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esphome/components/mipi_dsi/models/guition.py b/esphome/components/mipi_dsi/models/guition.py index fd3fbf6160..5f7db4ebda 100644 --- a/esphome/components/mipi_dsi/models/guition.py +++ b/esphome/components/mipi_dsi/models/guition.py @@ -16,7 +16,6 @@ DriverChip( lane_bit_rate="750Mbps", swap_xy=cv.UNDEFINED, color_order="RGB", - reset_pin=27, initsequence=[ (0x30, 0x00), (0xF7, 0x49, 0x61, 0x02, 0x00), (0x30, 0x01), (0x04, 0x0C), (0x05, 0x00), (0x06, 0x00), (0x0B, 0x11), (0x17, 0x00), (0x20, 0x04), (0x1F, 0x05), (0x23, 0x00), (0x25, 0x19), (0x28, 0x18), (0x29, 0x04), (0x2A, 0x01), From a1a336783e2739239bdb4ed95bbd459d15e3fdcc Mon Sep 17 00:00:00 2001 From: Clyde Stubbs <2366188+clydebarrow@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:53:03 +1000 Subject: [PATCH 4/9] [mcp4461] Fix read transaction (#10465) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> --- esphome/components/mcp4461/mcp4461.cpp | 22 ++++++++++++++++++---- esphome/components/mcp4461/mcp4461.h | 1 + 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/esphome/components/mcp4461/mcp4461.cpp b/esphome/components/mcp4461/mcp4461.cpp index 191fbae366..2f2c75e05a 100644 --- a/esphome/components/mcp4461/mcp4461.cpp +++ b/esphome/components/mcp4461/mcp4461.cpp @@ -122,7 +122,7 @@ uint8_t Mcp4461Component::get_status_register_() { uint8_t addr = static_cast(Mcp4461Addresses::MCP4461_STATUS); uint8_t reg = addr | static_cast(Mcp4461Commands::READ); uint16_t buf; - if (!this->read_byte_16(reg, &buf)) { + if (!this->read_16_(reg, &buf)) { this->error_code_ = MCP4461_STATUS_REGISTER_ERROR; this->mark_failed(); return 0; @@ -148,6 +148,20 @@ void Mcp4461Component::read_status_register_to_log() { ((status_register_value >> 3) & 0x01), ((status_register_value >> 2) & 0x01), ((status_register_value >> 1) & 0x01), ((status_register_value >> 0) & 0x01)); } +bool Mcp4461Component::read_16_(uint8_t address, uint16_t *buf) { + // read 16 bits and convert from big endian to host, + // Do this as two separate operations to ensure a stop condition between the write and read + i2c::ErrorCode err = this->write(&address, 1); + if (err != i2c::ERROR_OK) { + return false; + } + err = this->read(reinterpret_cast(buf), 2); + if (err != i2c::ERROR_OK) { + return false; + } + *buf = convert_big_endian(*buf); + return true; +} uint8_t Mcp4461Component::get_wiper_address_(uint8_t wiper) { uint8_t addr; @@ -205,7 +219,7 @@ uint16_t Mcp4461Component::read_wiper_level_(uint8_t wiper_idx) { } } uint16_t buf = 0; - if (!(this->read_byte_16(reg, &buf))) { + if (!(this->read_16_(reg, &buf))) { this->error_code_ = MCP4461_STATUS_I2C_ERROR; this->status_set_warning(); ESP_LOGW(TAG, "Error fetching %swiper %u value", (wiper_idx > 3) ? "nonvolatile " : "", wiper_idx); @@ -392,7 +406,7 @@ uint8_t Mcp4461Component::get_terminal_register_(Mcp4461TerminalIdx terminal_con : static_cast(Mcp4461Addresses::MCP4461_TCON1); reg |= static_cast(Mcp4461Commands::READ); uint16_t buf; - if (this->read_byte_16(reg, &buf)) { + if (this->read_16_(reg, &buf)) { return static_cast(buf & 0x00ff); } else { this->error_code_ = MCP4461_STATUS_I2C_ERROR; @@ -517,7 +531,7 @@ uint16_t Mcp4461Component::get_eeprom_value(Mcp4461EepromLocation location) { if (!this->is_eeprom_ready_for_writing_(true)) { return 0; } - if (!this->read_byte_16(reg, &buf)) { + if (!this->read_16_(reg, &buf)) { this->error_code_ = MCP4461_STATUS_I2C_ERROR; this->status_set_warning(); ESP_LOGW(TAG, "Error fetching EEPROM location value"); diff --git a/esphome/components/mcp4461/mcp4461.h b/esphome/components/mcp4461/mcp4461.h index 9b7f60f201..59f6358a56 100644 --- a/esphome/components/mcp4461/mcp4461.h +++ b/esphome/components/mcp4461/mcp4461.h @@ -96,6 +96,7 @@ class Mcp4461Component : public Component, public i2c::I2CDevice { protected: friend class Mcp4461Wiper; + bool read_16_(uint8_t address, uint16_t *buf); void update_write_protection_status_(); uint8_t get_wiper_address_(uint8_t wiper); uint16_t read_wiper_level_(uint8_t wiper); From 6f188d128491782ca9b4f8071eca871a11609c8d Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 3 Sep 2025 11:47:51 -0400 Subject: [PATCH 5/9] [esp32] Rebuild when idf_component.yml changes (#10540) --- esphome/components/esp32/__init__.py | 7 ++++++- esphome/writer.py | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index ac236f4eb3..ca10f36c1b 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -40,6 +40,7 @@ from esphome.cpp_generator import RawExpression 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 esphome.writer import clean_cmake_cache from .boards import BOARDS, STANDARD_BOARDS from .const import ( # noqa @@ -1079,7 +1080,11 @@ def _write_idf_component_yml(): contents = yaml_util.dump({"dependencies": dependencies}) else: contents = "" - write_file_if_changed(yml_path, contents) + if write_file_if_changed(yml_path, contents): + dependencies_lock = CORE.relative_build_path("dependencies.lock") + if os.path.isfile(dependencies_lock): + os.remove(dependencies_lock) + clean_cmake_cache() # Called by writer.py diff --git a/esphome/writer.py b/esphome/writer.py index 4b25a25f7e..b8fe44abdd 100644 --- a/esphome/writer.py +++ b/esphome/writer.py @@ -310,6 +310,10 @@ def clean_build(): if os.path.isdir(piolibdeps): _LOGGER.info("Deleting %s", piolibdeps) shutil.rmtree(piolibdeps) + dependencies_lock = CORE.relative_build_path("dependencies.lock") + if os.path.isfile(dependencies_lock): + _LOGGER.info("Deleting %s", dependencies_lock) + os.remove(dependencies_lock) GITIGNORE_CONTENT = """# Gitignore settings for ESPHome From 1b8978a89a3c8f79f12f7139d1de29faa8779b6d Mon Sep 17 00:00:00 2001 From: Anton Viktorov Date: Wed, 3 Sep 2025 19:18:26 +0200 Subject: [PATCH 6/9] [i2c] Fix bug write_register16 (#10547) --- esphome/components/i2c/i2c.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/esphome/components/i2c/i2c.cpp b/esphome/components/i2c/i2c.cpp index e66ab8ba73..48e1cf8aca 100644 --- a/esphome/components/i2c/i2c.cpp +++ b/esphome/components/i2c/i2c.cpp @@ -47,9 +47,9 @@ ErrorCode I2CDevice::write_register(uint8_t a_register, const uint8_t *data, siz ErrorCode I2CDevice::write_register16(uint16_t a_register, const uint8_t *data, size_t len) const { std::vector v(len + 2); - v.push_back(a_register >> 8); - v.push_back(a_register); - v.insert(v.end(), data, data + len); + v[0] = a_register >> 8; + v[1] = a_register; + std::copy(data, data + len, v.begin() + 2); return bus_->write_readv(this->address_, v.data(), v.size(), nullptr, 0); } From 9fe94f1201899ba5b414848029cd96cdb60d69a7 Mon Sep 17 00:00:00 2001 From: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Date: Wed, 3 Sep 2025 15:59:47 -0400 Subject: [PATCH 7/9] [esp32] Clear IDF environment variables (#10527) Co-authored-by: J. Nick Koston --- esphome/components/esp32/__init__.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index ca10f36c1b..e2359a8470 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -841,6 +841,9 @@ async def to_code(config): if conf[CONF_ADVANCED][CONF_IGNORE_EFUSE_CUSTOM_MAC]: cg.add_define("USE_ESP32_IGNORE_EFUSE_CUSTOM_MAC") + for clean_var in ("IDF_PATH", "IDF_TOOLS_PATH"): + os.environ.pop(clean_var, None) + add_extra_script( "post", "post_build.py", From a29fef166bc5daa7b139d39b15af9be1bf0fa144 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 3 Sep 2025 15:07:13 -0500 Subject: [PATCH 8/9] [api] Fix VERY_VERBOSE logging compilation error with bool arrays (#10539) --- esphome/components/api/api_pb2_dump.cpp | 2 +- script/api_protobuf/api_protobuf.py | 4 +++- tests/integration/fixtures/parallel_script_delays.yaml | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index 7af322f96d..e5008c93d8 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -1135,7 +1135,7 @@ void ExecuteServiceArgument::dump_to(std::string &out) const { dump_field(out, "string_", this->string_); dump_field(out, "int_", this->int_); for (const auto it : this->bool_array) { - dump_field(out, "bool_array", it, 4); + dump_field(out, "bool_array", static_cast(it), 4); } for (const auto &it : this->int_array) { dump_field(out, "int_array", it, 4); diff --git a/script/api_protobuf/api_protobuf.py b/script/api_protobuf/api_protobuf.py index 3396e5ad05..53180b13c3 100755 --- a/script/api_protobuf/api_protobuf.py +++ b/script/api_protobuf/api_protobuf.py @@ -1059,7 +1059,9 @@ def _generate_array_dump_content( # Check if underlying type can use dump_field if ti.can_use_dump_field(): # For types that have dump_field overloads, use them with extra indent - o += f' dump_field(out, "{name}", {ti.dump_field_value("it")}, 4);\n' + # std::vector iterators return proxy objects, need explicit cast + value_expr = "static_cast(it)" if is_bool else ti.dump_field_value("it") + o += f' dump_field(out, "{name}", {value_expr}, 4);\n' else: # For complex types (messages, bytes), use the old pattern o += f' out.append(" {name}: ");\n' diff --git a/tests/integration/fixtures/parallel_script_delays.yaml b/tests/integration/fixtures/parallel_script_delays.yaml index 6887045913..71d5b904e9 100644 --- a/tests/integration/fixtures/parallel_script_delays.yaml +++ b/tests/integration/fixtures/parallel_script_delays.yaml @@ -4,7 +4,7 @@ esphome: host: logger: - level: DEBUG + level: VERY_VERBOSE api: actions: From 2d3cdf60bab17fce88ab6ba1a606d920acf9f597 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 4 Sep 2025 09:06:00 +1200 Subject: [PATCH 9/9] Bump version to 2025.8.3 --- Doxyfile | 2 +- esphome/const.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index 6e0a1a42e8..ab6a0e8252 100644 --- a/Doxyfile +++ b/Doxyfile @@ -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.8.2 +PROJECT_NUMBER = 2025.8.3 # 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 diff --git a/esphome/const.py b/esphome/const.py index e0e72a6758..5ed9092454 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -4,7 +4,7 @@ from enum import Enum from esphome.enum import StrEnum -__version__ = "2025.8.2" +__version__ = "2025.8.3" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = (