From 8714a140bbde2a3d84c221a96f31046080dc30c4 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Sun, 28 Jun 2026 11:49:00 +0200 Subject: [PATCH] Fix resume not resetting temp soll for steps that inherit temperature MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Steps with no 'temperature' field inherit their target from a prior step (temperature=None in the resolved schedule). The resume-from-pause code only called set_theta_soll when the current step had an explicit temperature, so any manual setpoint change made during pause was never reverted for inherited steps (e.g. sud_0010 steps 2-3 both hold at step 1's 57 °C). Fix: save theta_soll_set at pause time; use it as fallback on resume when the current step's temperature is None. Also set initialTempSollSync=true in the browser on play so the slider accepts the next server Soll push regardless of message arrival order relative to the State update. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01SH2D4LRuCnhLSzoYerAfJX --- tasks/sud.py | 14 ++++++++++++-- web/app.js | 6 ++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/tasks/sud.py b/tasks/sud.py index 344ac94..cc9c5de 100644 --- a/tasks/sud.py +++ b/tasks/sud.py @@ -107,6 +107,9 @@ class SudTask(ATask): self.energy_by_step = {} self._energy_index = None self._energy_changed = ChangedFloat(self._on_energy_changed, prec=2) + # Saved on pause so resume can restore the effective setpoint even + # when the current step has temperature=None (inherits from a prior step). + self._paused_temp_soll = None msg_handler.set_recv_handler(self.recv) def apply_plant_params(self, grain_mass, water_mass): @@ -445,8 +448,14 @@ class SudTask(ATask): ramp = step.get('ramp') hold = step.get('hold') ramping = self.sud.state == SudState.RAMPING - if step.get('temperature') is not None: - self.tc.set_theta_soll(step['temperature']) + # Use step's own temperature if set; fall back to + # the value saved at pause for steps that inherit + # their target from a prior step (temperature=None). + target_temp = step.get('temperature') + if target_temp is None: + target_temp = self._paused_temp_soll + if target_temp is not None: + self.tc.set_theta_soll(target_temp) if ramping and ramp: self.tc.set_heatrate_soll(ramp['rate']) phase = ramp if ramping else hold @@ -458,6 +467,7 @@ class SudTask(ATask): # reanchor itself - see _reanchor_forecast(). self.sud.confirm() elif 'Pause' in pair[0]: + self._paused_temp_soll = self.tc.theta_soll_set self.sud.pause() elif 'Stop' in pair[0]: self.sud.stop() diff --git a/web/app.js b/web/app.js index 0d7f8ff..0486370 100644 --- a/web/app.js +++ b/web/app.js @@ -672,6 +672,12 @@ function onSudChanged(msg) { closedLoop = true; document.getElementById('closed-loop').checked = true; sendMsg('Heater', {ClosedLoop: true}); + // Accept the next Soll push from the server even if it + // arrives before sudRunning has gone true at this client + // (the two messages are sent as separate tasks server-side, + // so arrival order is non-deterministic in edge cases). + initialTempSollSync = true; + initialHeatrateSync = true; elapsed = 0; energyByStep = {}; energyCurrent = 0;