From a074dc760f16cf028636a9a799e86f72537e451d Mon Sep 17 00:00:00 2001 From: bvweerd Date: Sun, 27 Sep 2026 19:07:57 +0200 Subject: [PATCH] fix: always persist calibration after sampling, not only when correction moves When the efficiency correction is at CALIBRATION_APPLY_MAX (1.05) every new sample is added to the rolling window but record() returns moved=False, so async_save() is never called. The file on disk then keeps the old raw_ratio schema indefinitely and is re-migrated on every HA restart, resetting to correction=1.05 each time. The sensor appears permanently stuck. Fix: save after every successful sample (CALIBRATION_SAMPLED), not only when the correction shifts by more than CALIBRATION_SIGNIFICANT_CHANGE. This keeps the file in the current efficiency_factor schema and the sample count current, so a reset is not needed to unblock the sensor. --- .../battery_controller/coordinator_optimization.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/custom_components/battery_controller/coordinator_optimization.py b/custom_components/battery_controller/coordinator_optimization.py index ca57c14..31c77cb 100644 --- a/custom_components/battery_controller/coordinator_optimization.py +++ b/custom_components/battery_controller/coordinator_optimization.py @@ -30,6 +30,7 @@ CALIBRATION_NO_SOC_SOURCE, CALIBRATION_NOT_DISPATCHED, CALIBRATION_PLAN_NOT_EXECUTED, + CALIBRATION_SAMPLED, CALIBRATION_STEP_INCOMPLETE, CHARGE_CALIBRATION, DISCHARGE_CALIBRATION, @@ -2218,7 +2219,12 @@ def _update_battery_eff_calibration( ) actual_delta = max(0.0, measured) - if calibration.record(planned_delta, actual_delta, "SoC delta"): + moved = calibration.record(planned_delta, actual_delta, "SoC delta") + # Always persist after a sample, not only when the correction moves. + # When the correction is at the cap (1.05) every new sample is added to + # the rolling window but never triggers a save, so the file on disk stays + # in the old raw_ratio format and is re-migrated on every restart. + if moved or calibration.last_result == CALIBRATION_SAMPLED: self.hass.async_create_task(calibration.async_save()) def _update_charge_eff_calibration(