diff --git a/esphome/build_gen/arduino8266.py b/esphome/build_gen/arduino8266.py index 21356f343f..abbaa3f8bf 100644 --- a/esphome/build_gen/arduino8266.py +++ b/esphome/build_gen/arduino8266.py @@ -298,6 +298,19 @@ def _resolve_build_config(defines: dict[str, str]) -> _BuildConfig: ) +def _pio_option(key: str, default: str) -> str: + """A platformio_options value the native build honors (str-normalized). + + Routed into ``CORE.platformio_options`` by core/config.py under the + arduino toolchain; a repeated option accumulates as a list, where the + last value wins like a later platformio.ini line. + """ + value = CORE.platformio_options.get(key) + if isinstance(value, list): + value = value[-1] if value else None + return default if value is None else str(value) + + def _defines_flags( config: _BuildConfig, flash_mode: str, board: str, board_defines: tuple[str, ...] ) -> list[str]: @@ -310,10 +323,11 @@ def _defines_flags( return [ f"-D{d}" for d in ( - # Upstream reads this from the board manifest (build.f_cpu); all - # 45 supported boards ship 80000000L, so the value is hardcoded - # here rather than drift (same rationale as _MMU_DEFAULT) - "F_CPU=80000000L", + # Upstream reads this from the board manifest (build.f_cpu), + # where all 45 supported boards ship 80000000L, overridable via + # board_build.f_cpu; published configs pin 160000000L for + # timing-sensitive integrations, so the override is honored + f"F_CPU={_pio_option('board_build.f_cpu', '80000000L')}", "__ets__", "ICACHE_FLASH", "_GNU_SOURCE", diff --git a/tests/unit_tests/build_gen/test_arduino8266.py b/tests/unit_tests/build_gen/test_arduino8266.py index 0f0aab72f5..f52a9fa617 100644 --- a/tests/unit_tests/build_gen/test_arduino8266.py +++ b/tests/unit_tests/build_gen/test_arduino8266.py @@ -887,3 +887,20 @@ def test_generate_ld_scripts_gcc_change_invalidates_stamp(tmp_path: Path) -> Non with patch.object(arduino8266.subprocess, "run", return_value=result) as mock_run: _run_generate_ld_scripts(paths) mock_run.assert_called_once() + + +def test_defines_flags_honors_f_cpu_override() -> None: + """board_build.f_cpu (a published-config overclock knob) reaches the + compile line; the default stays 80 MHz.""" + _set_flags() + config = _resolve_build_config(_flag_defines(set(), [])) + board_build = ESP8266_BOARD_BUILD["nodemcuv2"] + defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"]) + assert "-DF_CPU=80000000L" in defines + CORE.platformio_options = {"board_build.f_cpu": "160000000L"} + defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"]) + assert "-DF_CPU=160000000L" in defines + # A repeated option accumulates as a list; the last value wins + CORE.platformio_options = {"board_build.f_cpu": ["80000000L", "160000000L"]} + defines = _defines_flags(config, "dout", "nodemcuv2", board_build["defines"]) + assert "-DF_CPU=160000000L" in defines