From da1ea2cfa3204797a9ea79a2d4103c4ac56b469a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 11 Feb 2026 23:07:05 -0600 Subject: [PATCH 1/3] [ethernet] Add per-PHY compile guards to eliminate unused PHY drivers (#13947) --- esphome/components/ethernet/__init__.py | 7 +- .../ethernet/ethernet_component.cpp | 69 ++++++++++++------- esphome/core/defines.h | 6 ++ 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 38489ceb2b..52f5f44d41 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -130,11 +130,16 @@ ETHERNET_TYPES = { } # PHY types that need compile-time defines for conditional compilation +# Each RMII PHY type gets a define so unused PHY drivers are excluded by the linker _PHY_TYPE_TO_DEFINE = { + "LAN8720": "USE_ETHERNET_LAN8720", + "RTL8201": "USE_ETHERNET_RTL8201", + "DP83848": "USE_ETHERNET_DP83848", + "IP101": "USE_ETHERNET_IP101", + "JL1101": "USE_ETHERNET_JL1101", "KSZ8081": "USE_ETHERNET_KSZ8081", "KSZ8081RNA": "USE_ETHERNET_KSZ8081", "LAN8670": "USE_ETHERNET_LAN8670", - # Add other PHY types here only if they need conditional compilation } SPI_ETHERNET_TYPES = ["W5500", "DM9051"] diff --git a/esphome/components/ethernet/ethernet_component.cpp b/esphome/components/ethernet/ethernet_component.cpp index af7fed608b..f9d98ad51b 100644 --- a/esphome/components/ethernet/ethernet_component.cpp +++ b/esphome/components/ethernet/ethernet_component.cpp @@ -186,31 +186,43 @@ void EthernetComponent::setup() { } #endif #if CONFIG_ETH_USE_ESP32_EMAC +#ifdef USE_ETHERNET_LAN8720 case ETHERNET_TYPE_LAN8720: { this->phy_ = esp_eth_phy_new_lan87xx(&phy_config); break; } +#endif +#ifdef USE_ETHERNET_RTL8201 case ETHERNET_TYPE_RTL8201: { this->phy_ = esp_eth_phy_new_rtl8201(&phy_config); break; } +#endif +#ifdef USE_ETHERNET_DP83848 case ETHERNET_TYPE_DP83848: { this->phy_ = esp_eth_phy_new_dp83848(&phy_config); break; } +#endif +#ifdef USE_ETHERNET_IP101 case ETHERNET_TYPE_IP101: { this->phy_ = esp_eth_phy_new_ip101(&phy_config); break; } +#endif +#ifdef USE_ETHERNET_JL1101 case ETHERNET_TYPE_JL1101: { this->phy_ = esp_eth_phy_new_jl1101(&phy_config); break; } +#endif +#ifdef USE_ETHERNET_KSZ8081 case ETHERNET_TYPE_KSZ8081: case ETHERNET_TYPE_KSZ8081RNA: { this->phy_ = esp_eth_phy_new_ksz80xx(&phy_config); break; } +#endif #ifdef USE_ETHERNET_LAN8670 case ETHERNET_TYPE_LAN8670: { this->phy_ = esp_eth_phy_new_lan867x(&phy_config); @@ -343,26 +355,32 @@ void EthernetComponent::loop() { void EthernetComponent::dump_config() { const char *eth_type; switch (this->type_) { +#ifdef USE_ETHERNET_LAN8720 case ETHERNET_TYPE_LAN8720: eth_type = "LAN8720"; break; - +#endif +#ifdef USE_ETHERNET_RTL8201 case ETHERNET_TYPE_RTL8201: eth_type = "RTL8201"; break; - +#endif +#ifdef USE_ETHERNET_DP83848 case ETHERNET_TYPE_DP83848: eth_type = "DP83848"; break; - +#endif +#ifdef USE_ETHERNET_IP101 case ETHERNET_TYPE_IP101: eth_type = "IP101"; break; - +#endif +#ifdef USE_ETHERNET_JL1101 case ETHERNET_TYPE_JL1101: eth_type = "JL1101"; break; - +#endif +#ifdef USE_ETHERNET_KSZ8081 case ETHERNET_TYPE_KSZ8081: eth_type = "KSZ8081"; break; @@ -370,19 +388,22 @@ void EthernetComponent::dump_config() { case ETHERNET_TYPE_KSZ8081RNA: eth_type = "KSZ8081RNA"; break; - +#endif +#if CONFIG_ETH_SPI_ETHERNET_W5500 case ETHERNET_TYPE_W5500: eth_type = "W5500"; break; - - case ETHERNET_TYPE_OPENETH: - eth_type = "OPENETH"; - break; - +#endif +#if CONFIG_ETH_SPI_ETHERNET_DM9051 case ETHERNET_TYPE_DM9051: eth_type = "DM9051"; break; - +#endif +#ifdef USE_ETHERNET_OPENETH + case ETHERNET_TYPE_OPENETH: + eth_type = "OPENETH"; + break; +#endif #ifdef USE_ETHERNET_LAN8670 case ETHERNET_TYPE_LAN8670: eth_type = "LAN8670"; @@ -686,16 +707,22 @@ void EthernetComponent::dump_connect_params_() { char gateway_buf[network::IP_ADDRESS_BUFFER_SIZE]; char dns1_buf[network::IP_ADDRESS_BUFFER_SIZE]; char dns2_buf[network::IP_ADDRESS_BUFFER_SIZE]; + char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE]; ESP_LOGCONFIG(TAG, " IP Address: %s\n" " Hostname: '%s'\n" " Subnet: %s\n" " Gateway: %s\n" " DNS1: %s\n" - " DNS2: %s", + " DNS2: %s\n" + " MAC Address: %s\n" + " Is Full Duplex: %s\n" + " Link Speed: %u", network::IPAddress(&ip.ip).str_to(ip_buf), App.get_name().c_str(), network::IPAddress(&ip.netmask).str_to(subnet_buf), network::IPAddress(&ip.gw).str_to(gateway_buf), - network::IPAddress(dns_ip1).str_to(dns1_buf), network::IPAddress(dns_ip2).str_to(dns2_buf)); + network::IPAddress(dns_ip1).str_to(dns1_buf), network::IPAddress(dns_ip2).str_to(dns2_buf), + this->get_eth_mac_address_pretty_into_buffer(mac_buf), + YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), this->get_link_speed() == ETH_SPEED_100M ? 100 : 10); #if USE_NETWORK_IPV6 struct esp_ip6_addr if_ip6s[CONFIG_LWIP_IPV6_NUM_ADDRESSES]; @@ -706,14 +733,6 @@ void EthernetComponent::dump_connect_params_() { ESP_LOGCONFIG(TAG, " IPv6: " IPV6STR, IPV62STR(if_ip6s[i])); } #endif /* USE_NETWORK_IPV6 */ - - char mac_buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE]; - ESP_LOGCONFIG(TAG, - " MAC Address: %s\n" - " Is Full Duplex: %s\n" - " Link Speed: %u", - this->get_eth_mac_address_pretty_into_buffer(mac_buf), - YESNO(this->get_duplex_mode() == ETH_DUPLEX_FULL), this->get_link_speed() == ETH_SPEED_100M ? 100 : 10); } #ifdef USE_ETHERNET_SPI @@ -837,13 +856,15 @@ void EthernetComponent::ksz8081_set_clock_reference_(esp_eth_mac_t *mac) { void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister register_data) { esp_err_t err; - constexpr uint8_t eth_phy_psr_reg_addr = 0x1F; +#ifdef USE_ETHERNET_RTL8201 + constexpr uint8_t eth_phy_psr_reg_addr = 0x1F; if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) { ESP_LOGD(TAG, "Select PHY Register Page: 0x%02" PRIX32, register_data.page); err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, register_data.page); ESPHL_ERROR_CHECK(err, "Select PHY Register page failed"); } +#endif ESP_LOGD(TAG, "Writing to PHY Register Address: 0x%02" PRIX32 "\n" @@ -852,11 +873,13 @@ void EthernetComponent::write_phy_register_(esp_eth_mac_t *mac, PHYRegister regi err = mac->write_phy_reg(mac, this->phy_addr_, register_data.address, register_data.value); ESPHL_ERROR_CHECK(err, "Writing PHY Register failed"); +#ifdef USE_ETHERNET_RTL8201 if (this->type_ == ETHERNET_TYPE_RTL8201 && register_data.page) { ESP_LOGD(TAG, "Select PHY Register Page 0x00"); err = mac->write_phy_reg(mac, this->phy_addr_, eth_phy_psr_reg_addr, 0x0); ESPHL_ERROR_CHECK(err, "Select PHY Register Page 0 failed"); } +#endif } #endif diff --git a/esphome/core/defines.h b/esphome/core/defines.h index 8fc30760c7..bfa33e4e59 100644 --- a/esphome/core/defines.h +++ b/esphome/core/defines.h @@ -241,7 +241,13 @@ #ifdef USE_ARDUINO #define USE_ARDUINO_VERSION_CODE VERSION_CODE(3, 3, 7) #define USE_ETHERNET +#define USE_ETHERNET_LAN8720 +#define USE_ETHERNET_RTL8201 +#define USE_ETHERNET_DP83848 +#define USE_ETHERNET_IP101 +#define USE_ETHERNET_JL1101 #define USE_ETHERNET_KSZ8081 +#define USE_ETHERNET_LAN8670 #define USE_ETHERNET_MANUAL_IP #define USE_ETHERNET_IP_STATE_LISTENERS #define USE_ETHERNET_CONNECT_TRIGGER From d6461251f925c4be1197a34f7d6be761a1cc014f Mon Sep 17 00:00:00 2001 From: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:04:19 +1300 Subject: [PATCH 2/3] Bump version to 2026.3.0-dev --- Doxyfile | 2 +- esphome/const.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Doxyfile b/Doxyfile index efc2f464e3..1a9e0b4e10 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 = 2026.2.0-dev +PROJECT_NUMBER = 2026.3.0-dev # 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 00d8013cc6..f72cbc8893 100644 --- a/esphome/const.py +++ b/esphome/const.py @@ -4,7 +4,7 @@ from enum import Enum from esphome.enum import StrEnum -__version__ = "2026.2.0-dev" +__version__ = "2026.3.0-dev" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" VALID_SUBSTITUTIONS_CHARACTERS = ( From 9c185b42c3bf2300a94bf44a4fcfb1f3ef7d34ea Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Thu, 12 Feb 2026 06:23:30 -0600 Subject: [PATCH 3/3] Reword comment to avoid ci-custom scanf lint false positive The regex matches `scanf (` in comments too since `\s*\(` matches the space before the parenthesized size note. Co-Authored-By: Claude Opus 4.6 --- tests/components/time/posix_tz_parser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/components/time/posix_tz_parser.cpp b/tests/components/time/posix_tz_parser.cpp index 2f41b17239..301136175a 100644 --- a/tests/components/time/posix_tz_parser.cpp +++ b/tests/components/time/posix_tz_parser.cpp @@ -1,5 +1,5 @@ // Tests for the POSIX TZ parser and ESPTime::strptime implementations -// These custom parsers avoid pulling in scanf (~9.8KB on ESP32-IDF). +// These custom parsers avoid pulling in the scanf family, saving ~9.8KB on ESP32-IDF. // Enable USE_TIME_TIMEZONE for tests #define USE_TIME_TIMEZONE