Add Reset learned model to Configure

Configure now opens a menu: Settings (the previous form) or Reset learned
model. After an explicit confirmation the entry is unloaded, the learned
parts of the stored model (zone, extended and ventilation coefficients,
models kept for removed zones, Model Error and Forecast Error statistics,
fingerprints) are removed under the storage lock, and the entry is set up
again. Configuration, heat-source baselines and the window event log are
kept, and model_changes records the reset. Unloading first means no update
still running can write the old model back. English and Romanian strings;
the gust hint now refers to Model Error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
buzeraandClaude Opus 5.5 committed 2026-10-27 04:29:03 +02:00
1 parent 28ff953ddd
commit 49565d610a
8 files changed
+174 -12

No files matched your search

@@ -65,6 +65,34 @@ def model_removed(hass: HomeAssistant, entry_id: str) -> bool:
return entry_id in hass.data.get(f"{DOMAIN}_removed", ())
# Stored keys holding what was learned. The rest is observation, not model: the
# heat sources' baseline samples, the window history and the heater's identity.
LEARNED_KEYS = ("learners", "retired_learners", "zone_models", "ventilation_models", "evaluation",
"operational_evaluation", "fingerprint_version", "fingerprints", "on_samples", "off_samples")
async def async_reset_learned_model(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Forget everything learned for this entry; the configuration is not touched.
The entry is unloaded first, so no running update can save the old model
afterwards, then set up again from the stripped data. Accuracy statistics go
too: they describe the model being discarded.
"""
await hass.config_entries.async_unload(entry.entry_id)
store = Store(hass, 1, f"{DOMAIN}.{entry.entry_id}")
async with storage_lock(hass, entry.entry_id):
stored = await store.async_load()
if isinstance(stored, dict):
kept = {key: value for key, value in stored.items() if key not in LEARNED_KEYS}
changes = kept.get("model_changes") if isinstance(kept.get("model_changes"), list) else []
kept["model_changes"] = [*changes, {
"time": datetime.now(timezone.utc).isoformat(timespec="seconds"), "zone": "all",
"recalibrated": ["all"], "reasons": ["learned model reset by the user"]}][-MAX_MODEL_CHANGES:]
await store.async_save(kept)
_LOGGER.info("Heating MPC: learned model reset by the user")
await hass.config_entries.async_setup(entry.entry_id)
def entry_zone_list(entry: ConfigEntry, config: dict[str, Any]) -> list[Zone]:
"""Zones from the entry's zone subentries; one zone per legacy room sensor otherwise."""
subentries = getattr(entry, "subentries", None) or {}