From f60c662a5b5989053020d2c0f3d521318855e387 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 13 Oct 2026 15:44:47 -1000 Subject: [PATCH] Count a reservation against the store its own in_flash selects --- esphome/components/esp8266/const.py | 25 +++++++++++-------- esphome/preferences.py | 10 ++++++-- .../components/esp8266/test_preferences.py | 7 ++++-- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/esphome/components/esp8266/const.py b/esphome/components/esp8266/const.py index f46c1f413b7..422186f3b59 100644 --- a/esphome/components/esp8266/const.py +++ b/esphome/components/esp8266/const.py @@ -52,8 +52,16 @@ def preference_words(value_bytes: int) -> int: return (value_bytes + 3) // 4 + 1 -def reserve_preferences(count: int, value_bytes: int, in_flash: bool = False) -> None: - """Record saved values a component creates; check_preferences_fit() adds them all up.""" +def reserve_preferences( + count: int, value_bytes: int, in_flash: bool | None = None +) -> None: + """Record saved values a component creates; check_preferences_fit() adds them all up. + + in_flash is the value's own storage, as passed to make_preference(); None is the two-argument + form, which follows restore_from_flash. + """ + if in_flash is None: + in_flash = CORE.config[KEY_ESP8266][CONF_RESTORE_FROM_FLASH] reservations = CORE.data.setdefault(KEY_ESP8266, {}).setdefault(KEY_PREFERENCES, []) reservations.extend([(preference_words(value_bytes), in_flash)] * count) @@ -75,15 +83,12 @@ def _rtc_values_can_split(values: list[int]) -> bool: @coroutine_with_priority(CoroPriority.FINAL) async def check_preferences_fit() -> None: """Fail the build when the reserved saved values cannot fit the space preferences.cpp has.""" - restore_from_flash = CORE.config[KEY_ESP8266][CONF_RESTORE_FROM_FLASH] - flash_store = preferences_flash_words(restore_from_flash) - reservations = CORE.data[KEY_ESP8266].get(KEY_PREFERENCES, []) - flash_words = sum( - w for w, in_flash in reservations if in_flash or restore_from_flash + flash_store = preferences_flash_words( + CORE.config[KEY_ESP8266][CONF_RESTORE_FROM_FLASH] ) - rtc_values = [ - w for w, in_flash in reservations if not (in_flash or restore_from_flash) - ] + reservations = CORE.data[KEY_ESP8266].get(KEY_PREFERENCES, []) + flash_words = sum(w for w, in_flash in reservations if in_flash) + rtc_values = [w for w, in_flash in reservations if not in_flash] if flash_words > flash_store: raise EsphomeError( f"Saved values need {flash_words} words but the ESP8266 flash store has {flash_store}; " diff --git a/esphome/preferences.py b/esphome/preferences.py index d1344d81b3f..c9a465d6252 100644 --- a/esphome/preferences.py +++ b/esphome/preferences.py @@ -104,8 +104,14 @@ def is_in_flash(value: str) -> bool: return in_flash -def reserve_preferences(count: int, value_bytes: int, in_flash: bool = False) -> None: - """Reserve saved values from to_code so a platform with a small store can check they all fit.""" +def reserve_preferences( + count: int, value_bytes: int, in_flash: bool | None = None +) -> None: + """Reserve saved values from to_code so a platform with a small store can check they all fit. + + in_flash is the value's own storage (is_in_flash(config[CONF_STORAGE])); leave it None for a + component that calls the two-argument make_preference() and takes the platform default. + """ if CORE.is_esp8266: from esphome.components.esp8266.const import reserve_preferences as reserve diff --git a/tests/unit_tests/components/esp8266/test_preferences.py b/tests/unit_tests/components/esp8266/test_preferences.py index 4bcb9acf325..2de5caa0525 100644 --- a/tests/unit_tests/components/esp8266/test_preferences.py +++ b/tests/unit_tests/components/esp8266/test_preferences.py @@ -42,14 +42,17 @@ def test_preference_words_rounds_up_and_adds_the_checksum( # 25 words each: 3 in the 78-word region and 1 in the 32-word one (False, False, 4, "RTC memory has 110"), # 125 of 128 flash words - (True, False, 5, "flash store has 128"), + (False, None, 4, "RTC memory has 110"), + # an explicit RTC value stays in RTC whatever restore_from_flash says + (True, False, 4, "RTC memory has 110"), + (True, None, 5, "flash store has 128"), (True, True, 5, "flash store has 128"), # explicit flash values without restore_from_flash use the 64-word store (False, True, 2, "flash store has 64"), ], ) def test_reservations_add_up_against_the_store_they_land_in( - restore_from_flash: bool, in_flash: bool, fitting: int, match: str + restore_from_flash: bool, in_flash: bool | None, fitting: int, match: str ) -> None: CORE.config[KEY_ESP8266]["restore_from_flash"] = restore_from_flash reserve_preferences(fitting - 1, 94, in_flash) # one component