Don't compile unnecessary platform files (e.g. ESP8266 files on ESP32) (#9354)

This commit is contained in:
J. Nick Koston 2025-07-07 16:04:41 -05:00 committed by GitHub
parent b122112d58
commit 440de12e3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
25 changed files with 657 additions and 12 deletions

View File

@ -10,8 +10,15 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ANALOG, CONF_INPUT, CONF_NUMBER, PLATFORM_ESP8266 from esphome.const import (
CONF_ANALOG,
CONF_INPUT,
CONF_NUMBER,
PLATFORM_ESP8266,
PlatformFramework,
)
from esphome.core import CORE from esphome.core import CORE
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
@ -229,3 +236,20 @@ def validate_adc_pin(value):
)(value) )(value)
raise NotImplementedError raise NotImplementedError
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"adc_sensor_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"adc_sensor_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"adc_sensor_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"adc_sensor_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -3,6 +3,7 @@ import base64
from esphome import automation from esphome import automation
from esphome.automation import Condition from esphome.automation import Condition
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import get_logger_level
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ACTION, CONF_ACTION,
@ -313,3 +314,17 @@ async def homeassistant_tag_scanned_to_code(config, action_id, template_arg, arg
@automation.register_condition("api.connected", APIConnectedCondition, {}) @automation.register_condition("api.connected", APIConnectedCondition, {})
async def api_connected_to_code(config, condition_id, template_arg, args): async def api_connected_to_code(config, condition_id, template_arg, args):
return cg.new_Pvariable(condition_id, template_arg) return cg.new_Pvariable(condition_id, template_arg)
def FILTER_SOURCE_FILES() -> list[str]:
"""Filter out api_pb2_dump.cpp when proto message dumping is not enabled."""
# api_pb2_dump.cpp is only needed when HAS_PROTO_MESSAGE_DUMP is defined
# This is a particularly large file that still needs to be opened and read
# all the way to the end even when ifdef'd out
#
# HAS_PROTO_MESSAGE_DUMP is defined when ESPHOME_LOG_HAS_VERY_VERBOSE is set,
# which happens when the logger level is VERY_VERBOSE
if get_logger_level() != "VERY_VERBOSE":
return ["api_pb2_dump.cpp"]
return []

View File

@ -1,4 +1,5 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_BLOCK, CONF_BLOCK,
@ -7,6 +8,7 @@ from esphome.const import (
CONF_FREE, CONF_FREE,
CONF_ID, CONF_ID,
CONF_LOOP_TIME, CONF_LOOP_TIME,
PlatformFramework,
) )
CODEOWNERS = ["@OttoWinter"] CODEOWNERS = ["@OttoWinter"]
@ -44,3 +46,21 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config): async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID]) var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config) await cg.register_component(var, config)
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"debug_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"debug_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"debug_host.cpp": {PlatformFramework.HOST_NATIVE},
"debug_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"debug_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -11,6 +11,7 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_DEFAULT, CONF_DEFAULT,
@ -27,6 +28,7 @@ from esphome.const import (
CONF_WAKEUP_PIN, CONF_WAKEUP_PIN,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PlatformFramework,
) )
WAKEUP_PINS = { WAKEUP_PINS = {
@ -313,3 +315,14 @@ async def deep_sleep_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg) var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID]) await cg.register_parented(var, config[CONF_ID])
return var return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"deep_sleep_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"deep_sleep_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
}
)

View File

@ -2,6 +2,7 @@ from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32 from esphome.components import esp32
from esphome.components.const import CONF_REQUEST_HEADERS from esphome.components.const import CONF_REQUEST_HEADERS
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ESP8266_DISABLE_SSL_SUPPORT, CONF_ESP8266_DISABLE_SSL_SUPPORT,
@ -13,6 +14,7 @@ from esphome.const import (
CONF_URL, CONF_URL,
CONF_WATCHDOG_TIMEOUT, CONF_WATCHDOG_TIMEOUT,
PLATFORM_HOST, PLATFORM_HOST,
PlatformFramework,
__version__, __version__,
) )
from esphome.core import CORE, Lambda from esphome.core import CORE, Lambda
@ -319,3 +321,19 @@ async def http_request_action_to_code(config, action_id, template_arg, args):
await automation.build_automation(trigger, [], conf) await automation.build_automation(trigger, [], conf)
return var return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"http_request_host.cpp": {PlatformFramework.HOST_NATIVE},
"http_request_arduino.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.RP2040_ARDUINO,
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"http_request_idf.cpp": {PlatformFramework.ESP32_IDF},
}
)

View File

@ -3,6 +3,7 @@ import logging
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32 from esphome.components import esp32
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ADDRESS, CONF_ADDRESS,
@ -18,6 +19,7 @@ from esphome.const import (
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_RP2040, PLATFORM_RP2040,
PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
@ -205,3 +207,18 @@ def final_validate_device_schema(
{cv.Required(CONF_I2C_ID): fv.id_declaration_match_schema(hub_schema)}, {cv.Required(CONF_I2C_ID): fv.id_declaration_match_schema(hub_schema)},
extra=cv.ALLOW_EXTRA, extra=cv.ALLOW_EXTRA,
) )
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"i2c_bus_arduino.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.RP2040_ARDUINO,
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"i2c_bus_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
}
)

View File

@ -21,6 +21,7 @@ from esphome.components.libretiny.const import (
COMPONENT_LN882X, COMPONENT_LN882X,
COMPONENT_RTL87XX, COMPONENT_RTL87XX,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ARGS, CONF_ARGS,
@ -42,6 +43,7 @@ from esphome.const import (
PLATFORM_LN882X, PLATFORM_LN882X,
PLATFORM_RP2040, PLATFORM_RP2040,
PLATFORM_RTL87XX, PLATFORM_RTL87XX,
PlatformFramework,
) )
from esphome.core import CORE, Lambda, coroutine_with_priority from esphome.core import CORE, Lambda, coroutine_with_priority
@ -444,3 +446,25 @@ async def logger_set_level_to_code(config, action_id, template_arg, args):
lambda_ = await cg.process_lambda(Lambda(text), args, return_type=cg.void) lambda_ = await cg.process_lambda(Lambda(text), args, return_type=cg.void)
return cg.new_Pvariable(action_id, template_arg, lambda_) return cg.new_Pvariable(action_id, template_arg, lambda_)
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"logger_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"logger_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
"logger_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"logger_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"task_log_buffer.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
}
)

View File

@ -1,5 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_component from esphome.components.esp32 import add_idf_component
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_DISABLED, CONF_DISABLED,
@ -8,6 +9,7 @@ from esphome.const import (
CONF_PROTOCOL, CONF_PROTOCOL,
CONF_SERVICE, CONF_SERVICE,
CONF_SERVICES, CONF_SERVICES,
PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@ -108,3 +110,21 @@ async def to_code(config):
) )
cg.add(var.add_extra_service(exp)) cg.add(var.add_extra_service(exp))
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"mdns_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"mdns_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"mdns_host.cpp": {PlatformFramework.HOST_NATIVE},
"mdns_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"mdns_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -5,6 +5,7 @@ from esphome.automation import Condition
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import logger from esphome.components import logger
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_AVAILABILITY, CONF_AVAILABILITY,
@ -54,6 +55,7 @@ from esphome.const import (
PLATFORM_BK72XX, PLATFORM_BK72XX,
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@ -596,3 +598,13 @@ async def mqtt_enable_to_code(config, action_id, template_arg, args):
async def mqtt_disable_to_code(config, action_id, template_arg, args): async def mqtt_disable_to_code(config, action_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID]) paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren) return cg.new_Pvariable(action_id, template_arg, paren)
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"mqtt_backend_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
}
)

View File

@ -1,5 +1,7 @@
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import uart from esphome.components import uart
from esphome.config_helpers import filter_source_files_from_platform
from esphome.const import PlatformFramework
nextion_ns = cg.esphome_ns.namespace("nextion") nextion_ns = cg.esphome_ns.namespace("nextion")
Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice) Nextion = nextion_ns.class_("Nextion", cg.PollingComponent, uart.UARTDevice)
@ -8,3 +10,17 @@ nextion_ref = Nextion.operator("ref")
CONF_NEXTION_ID = "nextion_id" CONF_NEXTION_ID = "nextion_id"
CONF_PUBLISH_STATE = "publish_state" CONF_PUBLISH_STATE = "publish_state"
CONF_SEND_TO_NEXTION = "send_to_nextion" CONF_SEND_TO_NEXTION = "send_to_nextion"
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"nextion_upload_arduino.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.RP2040_ARDUINO,
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"nextion_upload_idf.cpp": {PlatformFramework.ESP32_IDF},
}
)

View File

@ -1,5 +1,6 @@
from esphome import automation from esphome import automation
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_ESPHOME, CONF_ESPHOME,
@ -7,6 +8,7 @@ from esphome.const import (
CONF_OTA, CONF_OTA,
CONF_PLATFORM, CONF_PLATFORM,
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@ -120,3 +122,18 @@ async def ota_to_code(var, config):
use_state_callback = True use_state_callback = True
if use_state_callback: if use_state_callback:
cg.add_define("USE_OTA_STATE_CALLBACK") cg.add_define("USE_OTA_STATE_CALLBACK")
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"ota_backend_arduino_esp32.cpp": {PlatformFramework.ESP32_ARDUINO},
"ota_backend_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
"ota_backend_arduino_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"ota_backend_arduino_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"ota_backend_arduino_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -1,6 +1,7 @@
from esphome import pins from esphome import pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32, esp32_rmt, remote_base from esphome.components import esp32, esp32_rmt, remote_base
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_BUFFER_SIZE, CONF_BUFFER_SIZE,
@ -15,6 +16,7 @@ from esphome.const import (
CONF_TYPE, CONF_TYPE,
CONF_USE_DMA, CONF_USE_DMA,
CONF_VALUE, CONF_VALUE,
PlatformFramework,
) )
from esphome.core import CORE, TimePeriod from esphome.core import CORE, TimePeriod
@ -170,3 +172,19 @@ async def to_code(config):
cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE])) cg.add(var.set_buffer_size(config[CONF_BUFFER_SIZE]))
cg.add(var.set_filter_us(config[CONF_FILTER])) cg.add(var.set_filter_us(config[CONF_FILTER]))
cg.add(var.set_idle_us(config[CONF_IDLE])) cg.add(var.set_idle_us(config[CONF_IDLE]))
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"remote_receiver_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"remote_receiver_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"remote_receiver_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -1,6 +1,7 @@
from esphome import automation, pins from esphome import automation, pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components import esp32, esp32_rmt, remote_base from esphome.components import esp32, esp32_rmt, remote_base
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_CARRIER_DUTY_PERCENT, CONF_CARRIER_DUTY_PERCENT,
@ -12,6 +13,7 @@ from esphome.const import (
CONF_PIN, CONF_PIN,
CONF_RMT_SYMBOLS, CONF_RMT_SYMBOLS,
CONF_USE_DMA, CONF_USE_DMA,
PlatformFramework,
) )
from esphome.core import CORE from esphome.core import CORE
@ -95,3 +97,19 @@ async def to_code(config):
await automation.build_automation( await automation.build_automation(
var.get_complete_trigger(), [], on_complete_config var.get_complete_trigger(), [], on_complete_config
) )
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"remote_transmitter_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"remote_transmitter_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"remote_transmitter_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -1,5 +1,6 @@
import esphome.codegen as cg import esphome.codegen as cg
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.core import CORE
CODEOWNERS = ["@esphome/core"] CODEOWNERS = ["@esphome/core"]
@ -40,3 +41,18 @@ async def to_code(config):
elif impl == IMPLEMENTATION_BSD_SOCKETS: elif impl == IMPLEMENTATION_BSD_SOCKETS:
cg.add_define("USE_SOCKET_IMPL_BSD_SOCKETS") cg.add_define("USE_SOCKET_IMPL_BSD_SOCKETS")
cg.add_define("USE_SOCKET_SELECT_SUPPORT") cg.add_define("USE_SOCKET_SELECT_SUPPORT")
def FILTER_SOURCE_FILES() -> list[str]:
"""Return list of socket implementation files that aren't selected by the user."""
impl = CORE.config["socket"][CONF_IMPLEMENTATION]
# Build list of files to exclude based on selected implementation
excluded = []
if impl != IMPLEMENTATION_LWIP_TCP:
excluded.append("lwip_raw_tcp_impl.cpp")
if impl != IMPLEMENTATION_BSD_SOCKETS:
excluded.append("bsd_sockets_impl.cpp")
if impl != IMPLEMENTATION_LWIP_SOCKETS:
excluded.append("lwip_sockets_impl.cpp")
return excluded

View File

@ -13,6 +13,7 @@ from esphome.components.esp32.const import (
VARIANT_ESP32S2, VARIANT_ESP32S2,
VARIANT_ESP32S3, VARIANT_ESP32S3,
) )
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_CLK_PIN, CONF_CLK_PIN,
@ -31,6 +32,7 @@ from esphome.const import (
PLATFORM_ESP32, PLATFORM_ESP32,
PLATFORM_ESP8266, PLATFORM_ESP8266,
PLATFORM_RP2040, PLATFORM_RP2040,
PlatformFramework,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
@ -423,3 +425,18 @@ def final_validate_device_schema(name: str, *, require_mosi: bool, require_miso:
{cv.Required(CONF_SPI_ID): fv.id_declaration_match_schema(hub_schema)}, {cv.Required(CONF_SPI_ID): fv.id_declaration_match_schema(hub_schema)},
extra=cv.ALLOW_EXTRA, extra=cv.ALLOW_EXTRA,
) )
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"spi_arduino.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.RP2040_ARDUINO,
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"spi_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
}
)

View File

@ -2,6 +2,7 @@ import re
from esphome import automation, pins from esphome import automation, pins
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_AFTER, CONF_AFTER,
@ -27,6 +28,7 @@ from esphome.const import (
CONF_TX_PIN, CONF_TX_PIN,
CONF_UART_ID, CONF_UART_ID,
PLATFORM_HOST, PLATFORM_HOST,
PlatformFramework,
) )
from esphome.core import CORE from esphome.core import CORE
import esphome.final_validate as fv import esphome.final_validate as fv
@ -438,3 +440,19 @@ async def uart_write_to_code(config, action_id, template_arg, args):
else: else:
cg.add(var.set_data_static(data)) cg.add(var.set_data_static(data))
return var return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"uart_component_esp32_arduino.cpp": {PlatformFramework.ESP32_ARDUINO},
"uart_component_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
"uart_component_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"uart_component_host.cpp": {PlatformFramework.HOST_NATIVE},
"uart_component_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},
"uart_component_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
}
)

View File

@ -3,6 +3,7 @@ from esphome.automation import Condition
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant from esphome.components.esp32 import add_idf_sdkconfig_option, const, get_esp32_variant
from esphome.components.network import IPAddress from esphome.components.network import IPAddress
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_AP, CONF_AP,
@ -39,6 +40,7 @@ from esphome.const import (
CONF_TTLS_PHASE_2, CONF_TTLS_PHASE_2,
CONF_USE_ADDRESS, CONF_USE_ADDRESS,
CONF_USERNAME, CONF_USERNAME,
PlatformFramework,
) )
from esphome.core import CORE, HexInt, coroutine_with_priority from esphome.core import CORE, HexInt, coroutine_with_priority
import esphome.final_validate as fv import esphome.final_validate as fv
@ -526,3 +528,18 @@ async def wifi_set_sta_to_code(config, action_id, template_arg, args):
await automation.build_automation(var.get_error_trigger(), [], on_error_config) await automation.build_automation(var.get_error_trigger(), [], on_error_config)
await cg.register_component(var, config) await cg.register_component(var, config)
return var return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"wifi_component_esp32_arduino.cpp": {PlatformFramework.ESP32_ARDUINO},
"wifi_component_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
"wifi_component_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"wifi_component_libretiny.cpp": {
PlatformFramework.BK72XX_ARDUINO,
PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO,
},
"wifi_component_pico_w.cpp": {PlatformFramework.RP2040_ARDUINO},
}
)

View File

@ -1,4 +1,20 @@
from esphome.const import CONF_ID from collections.abc import Callable
from esphome.const import (
CONF_ID,
CONF_LEVEL,
CONF_LOGGER,
KEY_CORE,
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PlatformFramework,
)
from esphome.core import CORE
# Pre-build lookup map from (platform, framework) tuples to PlatformFramework enum
_PLATFORM_FRAMEWORK_LOOKUP = {
(pf.value[0].value, pf.value[1].value): pf for pf in PlatformFramework
}
class Extend: class Extend:
@ -103,3 +119,60 @@ def merge_config(full_old, full_new):
return new return new
return merge(full_old, full_new) return merge(full_old, full_new)
def filter_source_files_from_platform(
files_map: dict[str, set[PlatformFramework]],
) -> Callable[[], list[str]]:
"""Helper to build a FILTER_SOURCE_FILES function from platform mapping.
Args:
files_map: Dict mapping filename to set of PlatformFramework enums
that should compile this file
Returns:
Function that returns list of files to exclude for current platform
"""
def filter_source_files() -> list[str]:
# Get current platform/framework
core_data = CORE.data.get(KEY_CORE, {})
target_platform = core_data.get(KEY_TARGET_PLATFORM)
target_framework = core_data.get(KEY_TARGET_FRAMEWORK)
if not target_platform or not target_framework:
return []
# Direct lookup of current PlatformFramework
current_platform_framework = _PLATFORM_FRAMEWORK_LOOKUP.get(
(target_platform, target_framework)
)
if not current_platform_framework:
return []
# Return files that should be excluded for current platform
return [
filename
for filename, platforms in files_map.items()
if current_platform_framework not in platforms
]
return filter_source_files
def get_logger_level() -> str:
"""Get the configured logger level.
This is used by components to determine what logging features to include
based on the configured log level.
Returns:
The configured logger level string, defaults to "DEBUG" if not configured
"""
# Check if logger config exists
if CONF_LOGGER not in CORE.config:
return "DEBUG"
logger_config = CORE.config[CONF_LOGGER]
return logger_config.get(CONF_LEVEL, "DEBUG")

View File

@ -1,5 +1,9 @@
"""Constants used by esphome.""" """Constants used by esphome."""
from enum import Enum
from esphome.enum import StrEnum
__version__ = "2025.7.0-dev" __version__ = "2025.7.0-dev"
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_" ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
@ -7,14 +11,55 @@ VALID_SUBSTITUTIONS_CHARACTERS = (
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_" "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"
) )
PLATFORM_BK72XX = "bk72xx"
PLATFORM_ESP32 = "esp32" class Platform(StrEnum):
PLATFORM_ESP8266 = "esp8266" """Platform identifiers for ESPHome."""
PLATFORM_HOST = "host"
PLATFORM_LIBRETINY_OLDSTYLE = "libretiny" BK72XX = "bk72xx"
PLATFORM_LN882X = "ln882x" ESP32 = "esp32"
PLATFORM_RP2040 = "rp2040" ESP8266 = "esp8266"
PLATFORM_RTL87XX = "rtl87xx" HOST = "host"
LIBRETINY_OLDSTYLE = "libretiny"
LN882X = "ln882x"
RP2040 = "rp2040"
RTL87XX = "rtl87xx"
class Framework(StrEnum):
"""Framework identifiers for ESPHome."""
ARDUINO = "arduino"
ESP_IDF = "esp-idf"
NATIVE = "host"
class PlatformFramework(Enum):
"""Combined platform-framework identifiers with tuple values."""
# ESP32 variants
ESP32_ARDUINO = (Platform.ESP32, Framework.ARDUINO)
ESP32_IDF = (Platform.ESP32, Framework.ESP_IDF)
# Arduino framework platforms
ESP8266_ARDUINO = (Platform.ESP8266, Framework.ARDUINO)
RP2040_ARDUINO = (Platform.RP2040, Framework.ARDUINO)
BK72XX_ARDUINO = (Platform.BK72XX, Framework.ARDUINO)
RTL87XX_ARDUINO = (Platform.RTL87XX, Framework.ARDUINO)
LN882X_ARDUINO = (Platform.LN882X, Framework.ARDUINO)
# Host platform (native)
HOST_NATIVE = (Platform.HOST, Framework.NATIVE)
# Maintain backward compatibility by reassigning after enum definition
PLATFORM_BK72XX = Platform.BK72XX
PLATFORM_ESP32 = Platform.ESP32
PLATFORM_ESP8266 = Platform.ESP8266
PLATFORM_HOST = Platform.HOST
PLATFORM_LIBRETINY_OLDSTYLE = Platform.LIBRETINY_OLDSTYLE
PLATFORM_LN882X = Platform.LN882X
PLATFORM_RP2040 = Platform.RP2040
PLATFORM_RTL87XX = Platform.RTL87XX
SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"} SOURCE_FILE_EXTENSIONS = {".cpp", ".hpp", ".h", ".c", ".tcc", ".ino"}

View File

@ -6,6 +6,7 @@ from pathlib import Path
from esphome import automation, core from esphome import automation, core
import esphome.codegen as cg import esphome.codegen as cg
from esphome.config_helpers import filter_source_files_from_platform
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import ( from esphome.const import (
CONF_AREA, CONF_AREA,
@ -35,6 +36,7 @@ from esphome.const import (
CONF_TRIGGER_ID, CONF_TRIGGER_ID,
CONF_VERSION, CONF_VERSION,
KEY_CORE, KEY_CORE,
PlatformFramework,
__version__ as ESPHOME_VERSION, __version__ as ESPHOME_VERSION,
) )
from esphome.core import CORE, coroutine_with_priority from esphome.core import CORE, coroutine_with_priority
@ -551,3 +553,16 @@ async def to_code(config: ConfigType) -> None:
cg.add(dev.set_area_id(area_id_hash)) cg.add(dev.set_area_id(area_id_hash))
cg.add(cg.App.register_device(dev)) cg.add(cg.App.register_device(dev))
# Platform-specific source files for core
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"ring_buffer.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
# Note: lock_free_queue.h and event_pool.h are header files and don't need to be filtered
# as they are only included when needed by the preprocessor
}
)

View File

@ -9,6 +9,7 @@ import os
from typing import TYPE_CHECKING, Any from typing import TYPE_CHECKING, Any
from esphome import const, util from esphome import const, util
from esphome.enum import StrEnum
from esphome.storage_json import StorageJSON, ext_storage_path from esphome.storage_json import StorageJSON, ext_storage_path
from .const import ( from .const import (
@ -18,7 +19,6 @@ from .const import (
EVENT_ENTRY_STATE_CHANGED, EVENT_ENTRY_STATE_CHANGED,
EVENT_ENTRY_UPDATED, EVENT_ENTRY_UPDATED,
) )
from .enum import StrEnum
from .util.subprocess import async_run_system_command from .util.subprocess import async_run_system_command
if TYPE_CHECKING: if TYPE_CHECKING:

View File

@ -112,8 +112,17 @@ class ComponentManifest:
This will return all cpp source files that are located in the same folder as the This will return all cpp source files that are located in the same folder as the
loaded .py file (does not look through subdirectories) loaded .py file (does not look through subdirectories)
""" """
ret = [] ret: list[FileResource] = []
# Get filter function for source files
filter_source_files_func = getattr(self.module, "FILTER_SOURCE_FILES", None)
# Get list of files to exclude
excluded_files = (
set(filter_source_files_func()) if filter_source_files_func else set()
)
# Process all resources
for resource in ( for resource in (
r.name r.name
for r in importlib.resources.files(self.package).iterdir() for r in importlib.resources.files(self.package).iterdir()
@ -124,6 +133,11 @@ class ComponentManifest:
if not importlib.resources.files(self.package).joinpath(resource).is_file(): if not importlib.resources.files(self.package).joinpath(resource).is_file():
# Not a resource = this is a directory (yeah this is confusing) # Not a resource = this is a directory (yeah this is confusing)
continue continue
# Skip excluded files
if resource in excluded_files:
continue
ret.append(FileResource(self.package, resource)) ret.append(FileResource(self.package, resource))
return ret return ret

View File

@ -0,0 +1,135 @@
"""Unit tests for esphome.config_helpers module."""
from collections.abc import Callable
from unittest.mock import patch
from esphome.config_helpers import filter_source_files_from_platform, get_logger_level
from esphome.const import (
CONF_LEVEL,
CONF_LOGGER,
KEY_CORE,
KEY_TARGET_FRAMEWORK,
KEY_TARGET_PLATFORM,
PlatformFramework,
)
def test_filter_source_files_from_platform_esp32() -> None:
"""Test that filter_source_files_from_platform correctly filters files for ESP32 platform."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"logger_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
"logger_common.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.HOST_NATIVE,
},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test ESP32 with Arduino framework
mock_core_data: dict[str, dict[str, str]] = {
KEY_CORE: {
KEY_TARGET_PLATFORM: "esp32",
KEY_TARGET_FRAMEWORK: "arduino",
}
}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# ESP32 Arduino should exclude ESP8266 and HOST files
assert "logger_esp8266.cpp" in excluded
assert "logger_host.cpp" in excluded
# But not ESP32 or common files
assert "logger_esp32.cpp" not in excluded
assert "logger_common.cpp" not in excluded
def test_filter_source_files_from_platform_host() -> None:
"""Test that filter_source_files_from_platform correctly filters files for HOST platform."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
},
"logger_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
"logger_common.cpp": {
PlatformFramework.ESP32_ARDUINO,
PlatformFramework.ESP32_IDF,
PlatformFramework.ESP8266_ARDUINO,
PlatformFramework.HOST_NATIVE,
},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test Host platform
mock_core_data: dict[str, dict[str, str]] = {
KEY_CORE: {
KEY_TARGET_PLATFORM: "host",
KEY_TARGET_FRAMEWORK: "host", # Framework.NATIVE is "host"
}
}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# Host should exclude ESP32 and ESP8266 files
assert "logger_esp32.cpp" in excluded
assert "logger_esp8266.cpp" in excluded
# But not host or common files
assert "logger_host.cpp" not in excluded
assert "logger_common.cpp" not in excluded
def test_filter_source_files_from_platform_handles_missing_data() -> None:
"""Test that filter_source_files_from_platform returns empty list when platform/framework data is missing."""
# Define test file mappings
files_map: dict[str, set[PlatformFramework]] = {
"logger_esp32.cpp": {PlatformFramework.ESP32_ARDUINO},
"logger_host.cpp": {PlatformFramework.HOST_NATIVE},
}
# Create the filter function
filter_func: Callable[[], list[str]] = filter_source_files_from_platform(files_map)
# Test case: Missing platform/framework data
mock_core_data: dict[str, dict[str, str]] = {KEY_CORE: {}}
with patch("esphome.config_helpers.CORE.data", mock_core_data):
excluded: list[str] = filter_func()
# Should return empty list when platform/framework not set
assert excluded == []
def test_get_logger_level() -> None:
"""Test get_logger_level helper function."""
# Test no logger config - should return default DEBUG
mock_config = {}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "DEBUG"
# Test with logger set to INFO
mock_config = {CONF_LOGGER: {CONF_LEVEL: "INFO"}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "INFO"
# Test with VERY_VERBOSE
mock_config = {CONF_LOGGER: {CONF_LEVEL: "VERY_VERBOSE"}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "VERY_VERBOSE"
# Test with logger missing level (uses default DEBUG)
mock_config = {CONF_LOGGER: {}}
with patch("esphome.config_helpers.CORE.config", mock_config):
assert get_logger_level() == "DEBUG"

View File

@ -0,0 +1,63 @@
"""Unit tests for esphome.loader module."""
from unittest.mock import MagicMock, patch
from esphome.loader import ComponentManifest
def test_component_manifest_resources_with_filter_source_files() -> None:
"""Test that ComponentManifest.resources correctly filters out excluded files."""
# Create a mock module with FILTER_SOURCE_FILES function
mock_module = MagicMock()
mock_module.FILTER_SOURCE_FILES = lambda: [
"platform_esp32.cpp",
"platform_esp8266.cpp",
]
mock_module.__package__ = "esphome.components.test_component"
# Create ComponentManifest instance
manifest = ComponentManifest(mock_module)
# Mock the files in the package
def create_mock_file(filename: str) -> MagicMock:
mock_file = MagicMock()
mock_file.name = filename
mock_file.is_file.return_value = True
return mock_file
mock_files = [
create_mock_file("test.cpp"),
create_mock_file("test.h"),
create_mock_file("platform_esp32.cpp"),
create_mock_file("platform_esp8266.cpp"),
create_mock_file("common.cpp"),
create_mock_file("README.md"), # Should be excluded by extension
]
# Mock importlib.resources
with patch("importlib.resources.files") as mock_files_func:
mock_package_files = MagicMock()
mock_package_files.iterdir.return_value = mock_files
mock_package_files.joinpath = lambda name: MagicMock(is_file=lambda: True)
mock_files_func.return_value = mock_package_files
# Get resources
resources = manifest.resources
# Convert to list of filenames for easier testing
resource_names = [r.resource for r in resources]
# Check that platform files are excluded
assert "platform_esp32.cpp" not in resource_names
assert "platform_esp8266.cpp" not in resource_names
# Check that other source files are included
assert "test.cpp" in resource_names
assert "test.h" in resource_names
assert "common.cpp" in resource_names
# Check that non-source files are excluded
assert "README.md" not in resource_names
# Verify the correct number of resources
assert len(resources) == 3 # test.cpp, test.h, common.cpp