diff --git a/esphome/components/esp32/__init__.py b/esphome/components/esp32/__init__.py index 475de6aa3e..eaa9aa163d 100644 --- a/esphome/components/esp32/__init__.py +++ b/esphome/components/esp32/__init__.py @@ -59,6 +59,7 @@ from .const import ( # noqa KEY_EXTRA_BUILD_FILES, KEY_FLASH_SIZE, KEY_FULL_CERT_BUNDLE, + KEY_IDF_VERSION, KEY_PATH, KEY_REF, KEY_REPO, @@ -420,9 +421,20 @@ def set_core_data(config): CORE.data[KEY_ESP32][KEY_EXCLUDE_COMPONENTS] = excluded # Initialize Arduino library tracking - cg.add_library() auto-enables libraries CORE.data[KEY_ESP32][KEY_ARDUINO_LIBRARIES] = set() - CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse( - config[CONF_FRAMEWORK][CONF_VERSION] - ) + framework_ver = cv.Version.parse(config[CONF_FRAMEWORK][CONF_VERSION]) + CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = framework_ver + + # Store the underlying IDF version for framework-agnostic checks + if conf[CONF_TYPE] == FRAMEWORK_ESP_IDF: + CORE.data[KEY_ESP32][KEY_IDF_VERSION] = framework_ver + elif (idf_ver := ARDUINO_IDF_VERSION_LOOKUP.get(framework_ver)) is not None: + CORE.data[KEY_ESP32][KEY_IDF_VERSION] = idf_ver + else: + raise cv.Invalid( + f"Arduino version {framework_ver} has no known ESP-IDF version mapping. " + "Please update ARDUINO_IDF_VERSION_LOOKUP.", + path=[CONF_FRAMEWORK, CONF_VERSION], + ) CORE.data[KEY_ESP32][KEY_BOARD] = config[CONF_BOARD] CORE.data[KEY_ESP32][KEY_FLASH_SIZE] = config[CONF_FLASH_SIZE] @@ -974,6 +986,7 @@ KEY_USB_SERIAL_JTAG_SECONDARY_REQUIRED = "usb_serial_jtag_secondary_required" KEY_MBEDTLS_PEER_CERT_REQUIRED = "mbedtls_peer_cert_required" KEY_MBEDTLS_PKCS7_REQUIRED = "mbedtls_pkcs7_required" KEY_FATFS_REQUIRED = "fatfs_required" +KEY_MBEDTLS_SHA512_REQUIRED = "mbedtls_sha512_required" def require_vfs_select() -> None: @@ -1043,6 +1056,25 @@ def require_mbedtls_pkcs7() -> None: CORE.data[KEY_ESP32][KEY_MBEDTLS_PKCS7_REQUIRED] = True +def require_mbedtls_sha512() -> None: + """Mark that mbedTLS SHA-384/SHA-512 support is required by a component. + + Call this from components that need to verify TLS certificates or signatures + using SHA-384 or SHA-512 algorithms. This prevents CONFIG_MBEDTLS_SHA384_C + and CONFIG_MBEDTLS_SHA512_C from being disabled. + """ + CORE.data[KEY_ESP32][KEY_MBEDTLS_SHA512_REQUIRED] = True + + +def idf_version() -> cv.Version: + """Return the underlying ESP-IDF version regardless of framework choice. + + For ESP-IDF builds this is the framework version directly. + For Arduino builds this is the mapped IDF version from ARDUINO_IDF_VERSION_LOOKUP. + """ + return CORE.data[KEY_ESP32][KEY_IDF_VERSION] + + def require_fatfs() -> None: """Mark that FATFS support is required by a component. @@ -1802,6 +1834,21 @@ async def to_code(config): elif advanced[CONF_DISABLE_MBEDTLS_PKCS7]: add_idf_sdkconfig_option("CONFIG_MBEDTLS_PKCS7_C", False) + # Disable SHA-384 and SHA-512 in mbedTLS + # ESPHome doesn't use either algorithm. SHA-384 shares the same + # compression function as SHA-512 (mbedtls_internal_sha512_process), + # so both must be disabled to eliminate the ~3KB software fallback + # that IDF 6.0's PSA parallel engine always links in. + # On IDF < 6.0 these are a single config and hardware-only (no + # software fallback), so there was no code size cost to leaving + # them enabled. + # Components that need SHA-384/SHA-512 can call require_mbedtls_sha512() + if idf_version() >= cv.Version(6, 0, 0) and not CORE.data[KEY_ESP32].get( + KEY_MBEDTLS_SHA512_REQUIRED, False + ): + add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA384_C", False) + add_idf_sdkconfig_option("CONFIG_MBEDTLS_SHA512_C", False) + # Disable regi2c control functions in IRAM # Only needed if using analog peripherals (ADC, DAC, etc.) from ISRs while cache is disabled if advanced[CONF_DISABLE_REGI2C_IN_IRAM]: diff --git a/esphome/components/esp32/const.py b/esphome/components/esp32/const.py index 7874c1c759..d0d00723fc 100644 --- a/esphome/components/esp32/const.py +++ b/esphome/components/esp32/const.py @@ -15,6 +15,7 @@ KEY_PATH = "path" KEY_SUBMODULES = "submodules" KEY_EXTRA_BUILD_FILES = "extra_build_files" KEY_FULL_CERT_BUNDLE = "full_cert_bundle" +KEY_IDF_VERSION = "idf_version" VARIANT_ESP32 = "ESP32" VARIANT_ESP32C2 = "ESP32C2" diff --git a/esphome/components/esp32_hosted/__init__.py b/esphome/components/esp32_hosted/__init__.py index a51ae2cd66..3f9185745d 100644 --- a/esphome/components/esp32_hosted/__init__.py +++ b/esphome/components/esp32_hosted/__init__.py @@ -4,14 +4,7 @@ from pathlib import Path from esphome import pins from esphome.components import esp32 import esphome.config_validation as cv -from esphome.const import ( - CONF_CLK_PIN, - CONF_RESET_PIN, - CONF_VARIANT, - KEY_CORE, - KEY_FRAMEWORK_VERSION, -) -from esphome.core import CORE +from esphome.const import CONF_CLK_PIN, CONF_RESET_PIN, CONF_VARIANT from esphome.cpp_generator import add_define CODEOWNERS = ["@swoboda1337"] @@ -100,9 +93,9 @@ async def to_code(config): int(config[CONF_SDIO_FREQUENCY] // 1000), ) - framework_ver: cv.Version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] - os.environ["ESP_IDF_VERSION"] = f"{framework_ver.major}.{framework_ver.minor}" - if framework_ver >= cv.Version(5, 5, 0): + idf_ver = esp32.idf_version() + os.environ["ESP_IDF_VERSION"] = f"{idf_ver.major}.{idf_ver.minor}" + if idf_ver >= cv.Version(5, 5, 0): esp32.add_idf_component(name="espressif/esp_wifi_remote", ref="1.4.0") esp32.add_idf_component(name="espressif/eppp_link", ref="1.1.4") esp32.add_idf_component(name="espressif/esp_hosted", ref="2.12.1") diff --git a/esphome/components/ethernet/__init__.py b/esphome/components/ethernet/__init__.py index 935d2004d4..e520c0e914 100644 --- a/esphome/components/ethernet/__init__.py +++ b/esphome/components/ethernet/__init__.py @@ -14,6 +14,7 @@ from esphome.components.esp32 import ( add_idf_component, add_idf_sdkconfig_option, get_esp32_variant, + idf_version, include_builtin_idf_component, ) from esphome.components.network import ip_address_literal @@ -176,13 +177,12 @@ ManualIP = ethernet_ns.struct("ManualIP") def _is_framework_spi_polling_mode_supported(): # SPI Ethernet without IRQ feature is added in # esp-idf >= (5.3+ ,5.2.1+, 5.1.4) - # Note: Arduino now uses ESP-IDF as a component, so we only check IDF version - framework_version = CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] - if framework_version >= cv.Version(5, 3, 0): + ver = idf_version() + if ver >= cv.Version(5, 3, 0): return True - if cv.Version(5, 3, 0) > framework_version >= cv.Version(5, 2, 1): + if cv.Version(5, 3, 0) > ver >= cv.Version(5, 2, 1): return True - if cv.Version(5, 2, 0) > framework_version >= cv.Version(5, 1, 4): # noqa: SIM103 + if cv.Version(5, 2, 0) > ver >= cv.Version(5, 1, 4): # noqa: SIM103 return True return False diff --git a/esphome/components/psram/__init__.py b/esphome/components/psram/__init__.py index 9b364584ff..86c17ce9ca 100644 --- a/esphome/components/psram/__init__.py +++ b/esphome/components/psram/__init__.py @@ -14,6 +14,7 @@ from esphome.components.esp32 import ( VARIANT_ESP32S3, add_idf_sdkconfig_option, get_esp32_variant, + idf_version, ) import esphome.config_validation as cv from esphome.const import ( @@ -23,8 +24,6 @@ from esphome.const import ( CONF_ID, CONF_MODE, CONF_SPEED, - KEY_CORE, - KEY_FRAMEWORK_VERSION, PLATFORM_ESP32, ) from esphome.core import CORE @@ -202,9 +201,7 @@ async def to_code(config): # ESP32 and ESP32-S2 don't have this constraint. if variant not in (VARIANT_ESP32, VARIANT_ESP32S2): add_idf_sdkconfig_option("CONFIG_ESPTOOLPY_FLASHFREQ_120M", True) - if config[CONF_MODE] == TYPE_OCTAL and CORE.data[KEY_CORE][ - KEY_FRAMEWORK_VERSION - ] >= cv.Version(5, 4, 0): + if config[CONF_MODE] == TYPE_OCTAL and idf_version() >= cv.Version(5, 4, 0): add_idf_sdkconfig_option( "CONFIG_SPIRAM_TIMING_TUNING_POINT_VIA_TEMPERATURE_SENSOR", True,