Fix step-1-skipped-on-restart race and Progress tab step number mismatch

Re-enabling the temp controller landed unconditionally in HOLD and
relied on the next tick to correct it, but SudTask.on_process() reads
is_holding() synchronously in the same call chain that pushes a fresh
step's setpoint - so a restart could finish a hold-less step instantly
instead of actually ramping. Resolve the FSM against the real gap right
away instead. Also fix the status bar showing one step number below
what the Progress tab's plates show for the same step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0189FkmyJkY77HqsNomr1DwV
This commit is contained in:
2026-06-24 23:30:37 +02:00
co-authored by Claude Sonnet 4.6
parent 787f02b8dc
commit 35d33530ef
2 changed files with 25 additions and 7 deletions
+20 -6
View File
@@ -160,14 +160,28 @@ class TempControllerBase(APid):
elif not self.enabled:
state_next = States.IDLE
elif self.state == States.IDLE:
# Just (re-)enabled - land in HOLD; the very next tick's
# threshold check (below) moves it on to HEAT/COOL if the gap
# actually warrants it. pid_heat was frozen (see process_pid())
# and possibly stale for as long as we were disabled - start it
# clean rather than resuming wherever it last left off.
state_next = States.HOLD
# Just (re-)enabled - resolve straight to HEAT/COOL/HOLD against
# the real gap, the same threshold check the HOLD branch below
# uses, rather than landing in HOLD and waiting for the next
# tick to correct it: is_holding() is read synchronously within
# this very same call chain (tasks/sud.py's SudTask.on_step_
# changed() pushes the new step's setpoint via set_theta_soll(),
# which calls this method directly), so an unconditional HOLD
# here gets mistaken for "ramp already reached" and can finish
# a freshly (re-)started step instantly - see SudTask.
# on_process()'s is_holding() check. pid_heat/pid_cool were
# frozen (see process_pid()) and possibly stale for as long as
# we were disabled - start whichever one matters clean rather
# than resuming wherever it last left off.
self.pid_hold.reset()
self.pid_heat.reset()
self.pid_cool.reset()
if diff >= self.thresholds['HoldHeat']:
state_next = States.HEAT
elif diff <= -self.thresholds['HoldCool']:
state_next = States.COOL
else:
state_next = States.HOLD
elif self.state == States.HOLD:
if diff >= self.thresholds['HoldHeat']:
state_next = States.HEAT