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;