Merge branch 'flash_write_after_ota_broken_libretiny' into integration

This commit is contained in:
J. Nick Koston
2026-01-06 16:12:56 -10:00
3 changed files with 11 additions and 10 deletions
@@ -1,6 +1,8 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import coroutine_with_priority
from esphome.coroutine import CoroPriority
CODEOWNERS = ["@esphome/core"]
@@ -16,6 +18,7 @@ CONFIG_SCHEMA = cv.Schema(
).extend(cv.COMPONENT_SCHEMA)
@coroutine_with_priority(CoroPriority.PREFERENCES)
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
cg.add(var.set_write_interval(config[CONF_FLASH_WRITE_INTERVAL]))
@@ -150,16 +150,6 @@ void SafeModeComponent::clean_rtc() {
// remain incremented.
uint32_t val = 0;
this->rtc_.save(&val);
#ifdef USE_LIBRETINY
// On LibreTiny (BK72xx, RTL87xx), preferences queued during shutdown are not
// reliably persisted to flash. This was observed on TuyaMCU devices where:
// 1. Safe mode button pressed or boot loop detected -> clean_rtc() queues counter=0
// 2. OTA completes -> safe_reboot() triggers IntervalSyncer::on_shutdown() -> sync()
// 3. After reboot, counter is NOT cleared -> device stuck in safe mode loop
// The FlashDB layer appears to fail silently when writing during shutdown.
// Sync immediately to ensure the boot counter is actually persisted.
global_preferences->sync();
#endif
}
void SafeModeComponent::on_safe_shutdown() {
+8
View File
@@ -114,6 +114,14 @@ class CoroPriority(enum.IntEnum):
# Examples: web_server_ota (52)
WEB_SERVER_OTA = 52
# Preferences - must run before APPLICATION (safe_mode) because safe_mode
# uses an early return when entering safe mode, skipping all lower priority
# component registration. Without IntervalSyncer registered, preferences
# cannot be synced during shutdown in safe mode, causing issues like the
# boot counter never being cleared and devices getting stuck in safe mode.
# Examples: preferences (51)
PREFERENCES = 51
# Application-level services
# Examples: safe_mode (50)
APPLICATION = 50