diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index a30e4fd1b7..cb6354cc74 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -552,6 +552,30 @@ CONF_ENABLE_LWIP_CHECK_THREAD_SAFETY = "enable_lwip_check_thread_safety" CONF_DISABLE_LIBC_LOCKS_IN_IRAM = "disable_libc_locks_in_iram" CONF_DISABLE_VFS_SUPPORT_TERMIOS = "disable_vfs_support_termios" CONF_DISABLE_VFS_SUPPORT_SELECT = "disable_vfs_support_select" +CONF_DISABLE_VFS_SUPPORT_DIR = "disable_vfs_support_dir" + +# VFS requirement tracking +# Components that need VFS features can call require_vfs_select() or require_vfs_dir() +KEY_VFS_SELECT_REQUIRED = "vfs_select_required" +KEY_VFS_DIR_REQUIRED = "vfs_dir_required" + + +def require_vfs_select() -> None: + """Mark that VFS select support is required by a component. + + Call this from components that use esp_vfs_eventfd or other VFS select features. + This prevents CONFIG_VFS_SUPPORT_SELECT from being disabled. + """ + CORE.data[KEY_VFS_SELECT_REQUIRED] = True + + +def require_vfs_dir() -> None: + """Mark that VFS directory support is required by a component. + + Call this from components that use directory functions (opendir, readdir, mkdir, etc.). + This prevents CONFIG_VFS_SUPPORT_DIR from being disabled. + """ + CORE.data[KEY_VFS_DIR_REQUIRED] = True def _validate_idf_component(config: ConfigType) -> ConfigType: @@ -623,6 +647,7 @@ FRAMEWORK_SCHEMA = cv.All( cv.Optional( CONF_DISABLE_VFS_SUPPORT_SELECT, default=True ): cv.boolean, + cv.Optional(CONF_DISABLE_VFS_SUPPORT_DIR, default=True): cv.boolean, cv.Optional(CONF_EXECUTE_FROM_PSRAM): cv.boolean, } ), @@ -980,12 +1005,32 @@ async def to_code(config): # Disable VFS support for select() with file descriptors # ESPHome only uses select() with sockets via lwip_select(), which still works. - # VFS select is only needed for UART/eventfd file descriptors, which ESPHome doesn't use. + # VFS select is only needed for UART/eventfd file descriptors. + # Components that need it (e.g., openthread) call require_vfs_select(). # Saves approximately 2.7KB of flash when disabled (default). - add_idf_sdkconfig_option( - "CONFIG_VFS_SUPPORT_SELECT", - not advanced.get(CONF_DISABLE_VFS_SUPPORT_SELECT, True), - ) + if CORE.data.get(KEY_VFS_SELECT_REQUIRED, False): + # Component requires VFS select - force enable regardless of user setting + add_idf_sdkconfig_option("CONFIG_VFS_SUPPORT_SELECT", True) + else: + # No component needs it - allow user to control (default: disabled) + add_idf_sdkconfig_option( + "CONFIG_VFS_SUPPORT_SELECT", + not advanced.get(CONF_DISABLE_VFS_SUPPORT_SELECT, True), + ) + + # Disable VFS support for directory functions (opendir, readdir, mkdir, etc.) + # ESPHome doesn't use directory functions on ESP32. + # Components that need it (e.g., storage components) call require_vfs_dir(). + # Saves approximately 0.5KB+ of flash when disabled (default). + if CORE.data.get(KEY_VFS_DIR_REQUIRED, False): + # Component requires VFS directory support - force enable regardless of user setting + add_idf_sdkconfig_option("CONFIG_VFS_SUPPORT_DIR", True) + else: + # No component needs it - allow user to control (default: disabled) + add_idf_sdkconfig_option( + "CONFIG_VFS_SUPPORT_DIR", + not advanced.get(CONF_DISABLE_VFS_SUPPORT_DIR, True), + ) cg.add_platformio_option("board_build.partitions", "partitions.csv") if CONF_PARTITIONS in config: diff --git a/esphome/components/openthread/__init__.py b/esphome/components/openthread/__init__.py index 3fac497c3d..5277455eca 100644 --- a/esphome/components/openthread/__init__.py +++ b/esphome/components/openthread/__init__.py @@ -4,6 +4,7 @@ from esphome.components.esp32 import ( VARIANT_ESP32H2, add_idf_sdkconfig_option, only_on_variant, + require_vfs_select, ) from esphome.components.mdns import MDNSComponent, enable_mdns_storage import esphome.config_validation as cv @@ -141,6 +142,9 @@ FINAL_VALIDATE_SCHEMA = _final_validate async def to_code(config): cg.add_define("USE_OPENTHREAD") + # OpenThread uses esp_vfs_eventfd which requires VFS select support + require_vfs_select() + # OpenThread SRP needs access to mDNS services after setup enable_mdns_storage()