From 404e679e6636145de2544abdc7d9676ae34346f2 Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Wed, 17 Sep 2025 11:02:12 +1200 Subject: [PATCH 1/6] Bump version to 2025.9.0 --- Doxyfile | 2 +- esphome/const.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index cca1a80137..9cbb8a3b9a 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.9.0b4 +PROJECT_NUMBER = 2025.9.0 # 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 c58104f114..44f0fb3dd6 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -4,7 +4,7 @@ from enum import Enum from esphome.enum import StrEnum -__version__ = "2025.9.0b4" +__version__ = "2025.9.0" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From fd888eaa6863756e398bed3d164bf8e9c0bf97af Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 14:29:58 -0500 Subject: [PATCH 2/6] Bump aioesphomeapi from 40.2.1 to 41.1.0 (#10776) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 296485bdae..e29a926a7c 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ platformio==6.1.18 # When updating platformio, also update /docker/Dockerfile esptool==5.0.2 click==8.1.7 esphome-dashboard==20250904.0 -aioesphomeapi==40.2.1 +aioesphomeapi==41.1.0 zeroconf==0.147.2 puremagic==1.30 ruamel.yaml==0.18.15 # dashboard_import From 11c595bb09a775a674f08fbef16cd15a304a5ffc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 17 Sep 2025 14:38:02 -0500 Subject: [PATCH 3/6] [mqtt] Fix KeyError when MQTT logging configured without explicit level (#10774) --- esphome/__main__.py | 2 +- tests/unit_tests/test_main.py | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/esphome/__main__.py b/esphome/__main__.py index 0147a82530..f54fa8e3c6 100644 --- a/esphome/__main__.py +++ b/esphome/__main__.py @@ -212,7 +212,7 @@ def has_mqtt_logging() -> bool: if CONF_TOPIC not in log_topic: return False - return log_topic[CONF_LEVEL] != "NONE" + return log_topic.get(CONF_LEVEL, None) != "NONE" def has_mqtt() -> bool: diff --git a/tests/unit_tests/test_main.py b/tests/unit_tests/test_main.py index bfebb44545..fff0b2cd48 100644 --- a/tests/unit_tests/test_main.py +++ b/tests/unit_tests/test_main.py @@ -1226,6 +1226,18 @@ def test_has_mqtt_logging_no_log_topic() -> None: setup_core(config={}) assert has_mqtt_logging() is False + # Setup MQTT config with CONF_LOG_TOPIC but no CONF_LEVEL (regression test for #10771) + # This simulates the default configuration created by validate_config in the MQTT component + setup_core( + config={ + CONF_MQTT: { + CONF_BROKER: "mqtt.local", + CONF_LOG_TOPIC: {CONF_TOPIC: "esphome/debug"}, + } + } + ) + assert has_mqtt_logging() is True + def test_has_mqtt() -> None: """Test has_mqtt function.""" From 28541bdb1c54627bee9f8798edb100b48df1b612 Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Wed, 17 Sep 2025 21:38:18 +0200 Subject: [PATCH 4/6] Migrate to SPDX license specifier in pyproject.toml (#10768) --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4943c48eb0..b7b4a48d7e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "esphome" -license = {text = "MIT"} +license = "MIT" description = "ESPHome is a system to configure your microcontrollers by simple yet powerful configuration files and control them remotely through Home Automation systems." readme = "README.md" authors = [ @@ -15,7 +15,6 @@ classifiers = [ "Environment :: Console", "Intended Audience :: Developers", "Intended Audience :: End Users/Desktop", - "License :: OSI Approved :: MIT License", "Programming Language :: C++", "Programming Language :: Python :: 3", "Topic :: Home Automation", From 429e989b695fca2811151e83afea55aacf2b25c7 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 17 Sep 2025 14:40:32 -0500 Subject: [PATCH 5/6] [core] Make StringRef convertToJson inline to save 250+ bytes flash (#10751) --- esphome/core/string_ref.cpp | 12 ------------ esphome/core/string_ref.h | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 esphome/core/string_ref.cpp diff --git a/esphome/core/string_ref.cpp b/esphome/core/string_ref.cpp deleted file mode 100644 index ce1e33cbb7..0000000000 --- a/esphome/core/string_ref.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "string_ref.h" - -namespace esphome { - -#ifdef USE_JSON - -// NOLINTNEXTLINE(readability-identifier-naming) -void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); } - -#endif // USE_JSON - -} // namespace esphome diff --git a/esphome/core/string_ref.h b/esphome/core/string_ref.h index c4320107e3..efaa17181d 100644 --- a/esphome/core/string_ref.h +++ b/esphome/core/string_ref.h @@ -130,7 +130,7 @@ inline std::string operator+(const StringRef &lhs, const char *rhs) { #ifdef USE_JSON // NOLINTNEXTLINE(readability-identifier-naming) -void convertToJson(const StringRef &src, JsonVariant dst); +inline void convertToJson(const StringRef &src, JsonVariant dst) { dst.set(src.c_str()); } #endif // USE_JSON } // namespace esphome From ff2df278d61c3a89f5ce316edfb005685ec46b31 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 17 Sep 2025 14:42:37 -0500 Subject: [PATCH 6/6] [api] Rename ConnectRequest/Response to AuthenticationRequest/Response (#10726) --- esphome/components/api/api.proto | 6 +++--- esphome/components/api/api_connection.cpp | 6 +++--- esphome/components/api/api_connection.h | 2 +- esphome/components/api/api_pb2.cpp | 6 +++--- esphome/components/api/api_pb2.h | 8 ++++---- esphome/components/api/api_pb2_dump.cpp | 7 +++++-- esphome/components/api/api_pb2_service.cpp | 12 ++++++------ esphome/components/api/api_pb2_service.h | 6 +++--- 8 files changed, 28 insertions(+), 25 deletions(-) diff --git a/esphome/components/api/api.proto b/esphome/components/api/api.proto index f82e762345..37e4c16bfc 100644 --- a/esphome/components/api/api.proto +++ b/esphome/components/api/api.proto @@ -7,7 +7,7 @@ service APIConnection { option (needs_setup_connection) = false; option (needs_authentication) = false; } - rpc connect (ConnectRequest) returns (ConnectResponse) { + rpc authenticate (AuthenticationRequest) returns (AuthenticationResponse) { option (needs_setup_connection) = false; option (needs_authentication) = false; } @@ -129,7 +129,7 @@ message HelloResponse { // Message sent at the beginning of each connection to authenticate the client // Can only be sent by the client and only at the beginning of the connection -message ConnectRequest { +message AuthenticationRequest { option (id) = 3; option (source) = SOURCE_CLIENT; option (no_delay) = true; @@ -141,7 +141,7 @@ message ConnectRequest { // Confirmation of successful connection. After this the connection is available for all traffic. // Can only be sent by the server and only at the beginning of the connection -message ConnectResponse { +message AuthenticationResponse { option (id) = 4; option (source) = SOURCE_SERVER; option (no_delay) = true; diff --git a/esphome/components/api/api_connection.cpp b/esphome/components/api/api_connection.cpp index 79f9fe9a08..dfcab4bda6 100644 --- a/esphome/components/api/api_connection.cpp +++ b/esphome/components/api/api_connection.cpp @@ -1387,14 +1387,14 @@ bool APIConnection::send_hello_response(const HelloRequest &msg) { return this->send_message(resp, HelloResponse::MESSAGE_TYPE); } #ifdef USE_API_PASSWORD -bool APIConnection::send_connect_response(const ConnectRequest &msg) { - ConnectResponse resp; +bool APIConnection::send_authenticate_response(const AuthenticationRequest &msg) { + AuthenticationResponse resp; // bool invalid_password = 1; resp.invalid_password = !this->parent_->check_password(msg.password); if (!resp.invalid_password) { this->complete_authentication_(); } - return this->send_message(resp, ConnectResponse::MESSAGE_TYPE); + return this->send_message(resp, AuthenticationResponse::MESSAGE_TYPE); } #endif // USE_API_PASSWORD diff --git a/esphome/components/api/api_connection.h b/esphome/components/api/api_connection.h index 70fc881a82..7d50aa4591 100644 --- a/esphome/components/api/api_connection.h +++ b/esphome/components/api/api_connection.h @@ -198,7 +198,7 @@ class APIConnection final : public APIServerConnection { #endif bool send_hello_response(const HelloRequest &msg) override; #ifdef USE_API_PASSWORD - bool send_connect_response(const ConnectRequest &msg) override; + bool send_authenticate_response(const AuthenticationRequest &msg) override; #endif bool send_disconnect_response(const DisconnectRequest &msg) override; bool send_ping_response(const PingRequest &msg) override; diff --git a/esphome/components/api/api_pb2.cpp b/esphome/components/api/api_pb2.cpp index 7b1601515e..4f2130466a 100644 --- a/esphome/components/api/api_pb2.cpp +++ b/esphome/components/api/api_pb2.cpp @@ -43,7 +43,7 @@ void HelloResponse::calculate_size(ProtoSize &size) const { size.add_length(1, this->name_ref_.size()); } #ifdef USE_API_PASSWORD -bool ConnectRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { +bool AuthenticationRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) { switch (field_id) { case 1: this->password = value.as_string(); @@ -53,8 +53,8 @@ bool ConnectRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value } return true; } -void ConnectResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->invalid_password); } -void ConnectResponse::calculate_size(ProtoSize &size) const { size.add_bool(1, this->invalid_password); } +void AuthenticationResponse::encode(ProtoWriteBuffer buffer) const { buffer.encode_bool(1, this->invalid_password); } +void AuthenticationResponse::calculate_size(ProtoSize &size) const { size.add_bool(1, this->invalid_password); } #endif #ifdef USE_AREAS void AreaInfo::encode(ProtoWriteBuffer buffer) const { diff --git a/esphome/components/api/api_pb2.h b/esphome/components/api/api_pb2.h index 421789a770..e68fce75aa 100644 --- a/esphome/components/api/api_pb2.h +++ b/esphome/components/api/api_pb2.h @@ -361,12 +361,12 @@ class HelloResponse final : public ProtoMessage { protected: }; #ifdef USE_API_PASSWORD -class ConnectRequest final : public ProtoDecodableMessage { +class AuthenticationRequest final : public ProtoDecodableMessage { public: static constexpr uint8_t MESSAGE_TYPE = 3; static constexpr uint8_t ESTIMATED_SIZE = 9; #ifdef HAS_PROTO_MESSAGE_DUMP - const char *message_name() const override { return "connect_request"; } + const char *message_name() const override { return "authentication_request"; } #endif std::string password{}; #ifdef HAS_PROTO_MESSAGE_DUMP @@ -376,12 +376,12 @@ class ConnectRequest final : public ProtoDecodableMessage { protected: bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override; }; -class ConnectResponse final : public ProtoMessage { +class AuthenticationResponse final : public ProtoMessage { public: static constexpr uint8_t MESSAGE_TYPE = 4; static constexpr uint8_t ESTIMATED_SIZE = 2; #ifdef HAS_PROTO_MESSAGE_DUMP - const char *message_name() const override { return "connect_response"; } + const char *message_name() const override { return "authentication_response"; } #endif bool invalid_password{false}; void encode(ProtoWriteBuffer buffer) const override; diff --git a/esphome/components/api/api_pb2_dump.cpp b/esphome/components/api/api_pb2_dump.cpp index 53af7eefef..222aa2b603 100644 --- a/esphome/components/api/api_pb2_dump.cpp +++ b/esphome/components/api/api_pb2_dump.cpp @@ -670,8 +670,11 @@ void HelloResponse::dump_to(std::string &out) const { dump_field(out, "name", this->name_ref_); } #ifdef USE_API_PASSWORD -void ConnectRequest::dump_to(std::string &out) const { dump_field(out, "password", this->password); } -void ConnectResponse::dump_to(std::string &out) const { dump_field(out, "invalid_password", this->invalid_password); } +void AuthenticationRequest::dump_to(std::string &out) const { dump_field(out, "password", this->password); } +void AuthenticationResponse::dump_to(std::string &out) const { + MessageDumpHelper helper(out, "AuthenticationResponse"); + dump_field(out, "invalid_password", this->invalid_password); +} #endif void DisconnectRequest::dump_to(std::string &out) const { out.append("DisconnectRequest {}"); } void DisconnectResponse::dump_to(std::string &out) const { out.append("DisconnectResponse {}"); } diff --git a/esphome/components/api/api_pb2_service.cpp b/esphome/components/api/api_pb2_service.cpp index 1bcbfe1ba2..ef7acbc6b2 100644 --- a/esphome/components/api/api_pb2_service.cpp +++ b/esphome/components/api/api_pb2_service.cpp @@ -25,13 +25,13 @@ void APIServerConnectionBase::read_message(uint32_t msg_size, uint32_t msg_type, break; } #ifdef USE_API_PASSWORD - case ConnectRequest::MESSAGE_TYPE: { - ConnectRequest msg; + case AuthenticationRequest::MESSAGE_TYPE: { + AuthenticationRequest msg; msg.decode(msg_data, msg_size); #ifdef HAS_PROTO_MESSAGE_DUMP - ESP_LOGVV(TAG, "on_connect_request: %s", msg.dump().c_str()); + ESP_LOGVV(TAG, "on_authentication_request: %s", msg.dump().c_str()); #endif - this->on_connect_request(msg); + this->on_authentication_request(msg); break; } #endif @@ -600,8 +600,8 @@ void APIServerConnection::on_hello_request(const HelloRequest &msg) { } } #ifdef USE_API_PASSWORD -void APIServerConnection::on_connect_request(const ConnectRequest &msg) { - if (!this->send_connect_response(msg)) { +void APIServerConnection::on_authentication_request(const AuthenticationRequest &msg) { + if (!this->send_authenticate_response(msg)) { this->on_fatal_error(); } } diff --git a/esphome/components/api/api_pb2_service.h b/esphome/components/api/api_pb2_service.h index cc7604c083..f81ac1a337 100644 --- a/esphome/components/api/api_pb2_service.h +++ b/esphome/components/api/api_pb2_service.h @@ -27,7 +27,7 @@ class APIServerConnectionBase : public ProtoService { virtual void on_hello_request(const HelloRequest &value){}; #ifdef USE_API_PASSWORD - virtual void on_connect_request(const ConnectRequest &value){}; + virtual void on_authentication_request(const AuthenticationRequest &value){}; #endif virtual void on_disconnect_request(const DisconnectRequest &value){}; @@ -216,7 +216,7 @@ class APIServerConnection : public APIServerConnectionBase { public: virtual bool send_hello_response(const HelloRequest &msg) = 0; #ifdef USE_API_PASSWORD - virtual bool send_connect_response(const ConnectRequest &msg) = 0; + virtual bool send_authenticate_response(const AuthenticationRequest &msg) = 0; #endif virtual bool send_disconnect_response(const DisconnectRequest &msg) = 0; virtual bool send_ping_response(const PingRequest &msg) = 0; @@ -339,7 +339,7 @@ class APIServerConnection : public APIServerConnectionBase { protected: void on_hello_request(const HelloRequest &msg) override; #ifdef USE_API_PASSWORD - void on_connect_request(const ConnectRequest &msg) override; + void on_authentication_request(const AuthenticationRequest &msg) override; #endif void on_disconnect_request(const DisconnectRequest &msg) override; void on_ping_request(const PingRequest &msg) override;