Remove the ad-hoc cooling override now that COOL handles it natively
TempControllerBase.cooling/set_cooling() forced y=0 in advance of a
Sud ramp-down step; redundant now that the FSM's own COOL state
detects and handles a negative diff itself. Removed from the
controller, SudTask's anticipatory detection (and the Step message's
now-unused "Cooling" field), and demo_sud.py's mirror of it.
gui: the "Cool down" status-bar indicator now reflects the
controller's actual State ("States.COOL") via the TempCtrl channel,
rather than Sud's removed anticipatory flag - renamed
sud_cooling/set_sud_cooling to tc_cooling/set_tc_cooling to match.
This commit is contained in:
+10
-9
@@ -308,10 +308,11 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.statusBar().addPermanentWidget(self.status_label_env)
|
self.statusBar().addPermanentWidget(self.status_label_env)
|
||||||
self.update_status_env_label()
|
self.update_status_env_label()
|
||||||
|
|
||||||
# Blinking indicator for a Sud ramp step that's cooling down
|
# Blinking indicator for the temperature controller's own COOL
|
||||||
# (target below the current temperature - the heater is forced off
|
# state (target below the current temperature - the heater is
|
||||||
# server-side and we just wait for ambient loss to catch up).
|
# forced off server-side and we just wait for ambient loss to
|
||||||
self.sud_cooling = False
|
# catch up).
|
||||||
|
self.tc_cooling = False
|
||||||
self.status_label_cooling = QtWidgets.QLabel("Cool down")
|
self.status_label_cooling = QtWidgets.QLabel("Cool down")
|
||||||
self.status_label_cooling.setStyleSheet("color: blue; font-weight: bold;")
|
self.status_label_cooling.setStyleSheet("color: blue; font-weight: bold;")
|
||||||
self.status_label_cooling.setVisible(False)
|
self.status_label_cooling.setVisible(False)
|
||||||
@@ -496,7 +497,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.sud_step_type = None
|
self.sud_step_type = None
|
||||||
self.sud_hold_remaining = 0.0
|
self.sud_hold_remaining = 0.0
|
||||||
self.forecast_history = []
|
self.forecast_history = []
|
||||||
self.set_sud_cooling(False)
|
self.set_tc_cooling(False)
|
||||||
self.update_sud_actions()
|
self.update_sud_actions()
|
||||||
self.update_status_env_label()
|
self.update_status_env_label()
|
||||||
self.setWindowTitle("BrewPi")
|
self.setWindowTitle("BrewPi")
|
||||||
@@ -551,10 +552,10 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
title += " - {}".format(description)
|
title += " - {}".format(description)
|
||||||
return title
|
return title
|
||||||
|
|
||||||
def set_sud_cooling(self, cooling):
|
def set_tc_cooling(self, cooling):
|
||||||
if cooling == self.sud_cooling:
|
if cooling == self.tc_cooling:
|
||||||
return
|
return
|
||||||
self.sud_cooling = cooling
|
self.tc_cooling = cooling
|
||||||
if cooling:
|
if cooling:
|
||||||
self.status_label_cooling.setVisible(True)
|
self.status_label_cooling.setVisible(True)
|
||||||
self.cooling_blink_timer.start(500)
|
self.cooling_blink_timer.start(500)
|
||||||
@@ -651,6 +652,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
for key in msg:
|
for key in msg:
|
||||||
if 'State' in key:
|
if 'State' in key:
|
||||||
self.label_state.setText(msg['State'])
|
self.label_state.setText(msg['State'])
|
||||||
|
self.set_tc_cooling(msg['State'] == 'States.COOL')
|
||||||
elif "Soll" in key:
|
elif "Soll" in key:
|
||||||
submsg = msg['Soll']
|
submsg = msg['Soll']
|
||||||
if 'Temp' in submsg:
|
if 'Temp' in submsg:
|
||||||
@@ -800,7 +802,6 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.sud_step_index = step.get('Index')
|
self.sud_step_index = step.get('Index')
|
||||||
self.sud_step_descr = step.get('Descr')
|
self.sud_step_descr = step.get('Descr')
|
||||||
self.sud_step_type = step.get('Type')
|
self.sud_step_type = step.get('Type')
|
||||||
self.set_sud_cooling(step.get('Cooling', False))
|
|
||||||
self.update_status_step_label()
|
self.update_status_step_label()
|
||||||
elif "HoldRemaining" in key:
|
elif "HoldRemaining" in key:
|
||||||
self.sud_hold_remaining = msg['HoldRemaining']
|
self.sud_hold_remaining = msg['HoldRemaining']
|
||||||
|
|||||||
@@ -45,14 +45,6 @@ class TempControllerBase(APid):
|
|||||||
self.pid_rate.set_params(params['Heat'])
|
self.pid_rate.set_params(params['Heat'])
|
||||||
self.pid_cool.set_params(params['Cool'])
|
self.pid_cool.set_params(params['Cool'])
|
||||||
self.is_startup = True
|
self.is_startup = True
|
||||||
# Explicit override for a ramp step whose target is below the
|
|
||||||
# current temperature: forces y to 0 immediately rather than
|
|
||||||
# waiting for the FSM's own (slower, hysteresis-based) COOL
|
|
||||||
# transition, as soon as the caller (SudTask) knows the step needs
|
|
||||||
# to passively cool down. Mostly superseded by the COOL state
|
|
||||||
# below for a heat-only actuator (both end up clamped to 0
|
|
||||||
# power) - kept for the immediate, decided-in-advance response.
|
|
||||||
self.cooling = False
|
|
||||||
# Master on/off switch: while disabled, the FSM is held in IDLE and
|
# Master on/off switch: while disabled, the FSM is held in IDLE and
|
||||||
# the controller tries not to drive the heater at all (output
|
# the controller tries not to drive the heater at all (output
|
||||||
# forced to 0) - off by default, enabled either by the user
|
# forced to 0) - off by default, enabled either by the user
|
||||||
@@ -91,9 +83,6 @@ class TempControllerBase(APid):
|
|||||||
def set_heatrate_soll(self, value):
|
def set_heatrate_soll(self, value):
|
||||||
self.heatrate_soll_set = value
|
self.heatrate_soll_set = value
|
||||||
|
|
||||||
def set_cooling(self, value):
|
|
||||||
self.cooling = value
|
|
||||||
|
|
||||||
def set_enabled(self, value):
|
def set_enabled(self, value):
|
||||||
self.enabled = value
|
self.enabled = value
|
||||||
|
|
||||||
@@ -150,7 +139,7 @@ class TempControllerBase(APid):
|
|||||||
self.pid_rate.process(heatrate_err, -self.heatrate_ist)
|
self.pid_rate.process(heatrate_err, -self.heatrate_ist)
|
||||||
self.pid_cool.process(heatrate_err, -self.heatrate_ist)
|
self.pid_cool.process(heatrate_err, -self.heatrate_ist)
|
||||||
|
|
||||||
if self.state == States.IDLE or self.cooling:
|
if self.state == States.IDLE:
|
||||||
self.y = 0
|
self.y = 0
|
||||||
elif self.state == States.COOL:
|
elif self.state == States.COOL:
|
||||||
self.y = self.pid_cool.get_y()
|
self.y = self.pid_cool.get_y()
|
||||||
|
|||||||
@@ -87,14 +87,6 @@ if __name__ == '__main__':
|
|||||||
ramping = sud.state == SudState.RAMPING
|
ramping = sud.state == SudState.RAMPING
|
||||||
phase = step['ramp'] if ramping and 'ramp' in step else step.get('hold', {})
|
phase = step['ramp'] if ramping and 'ramp' in step else step.get('hold', {})
|
||||||
|
|
||||||
# A ramp step whose target is below the current temperature can
|
|
||||||
# only be reached by passive cooling - force the heater off,
|
|
||||||
# mirroring tasks/sud.py's SudTask.
|
|
||||||
cooling = bool(ramping and 'ramp' in step and step['temperature'] < ctrl.get_theta_ist() - TEMP_REACHED_TOLERANCE)
|
|
||||||
ctrl.set_cooling(cooling)
|
|
||||||
if cooling:
|
|
||||||
print(" -> cooling down to {}".format(step['temperature']))
|
|
||||||
|
|
||||||
print(f"Step {step['number']}: {step['descr']}")
|
print(f"Step {step['number']}: {step['descr']}")
|
||||||
apply_plant_params(step)
|
apply_plant_params(step)
|
||||||
if ramping and 'ramp' in step:
|
if ramping and 'ramp' in step:
|
||||||
|
|||||||
@@ -61,17 +61,6 @@ class SudTask(ATask):
|
|||||||
ramping = self.sud.state == SudState.RAMPING
|
ramping = self.sud.state == SudState.RAMPING
|
||||||
phase = ramp if ramping and ramp is not None else hold
|
phase = ramp if ramping and ramp is not None else hold
|
||||||
|
|
||||||
# A ramp step whose target is below the current temperature can
|
|
||||||
# only be reached by passive cooling - force the heater off for
|
|
||||||
# its whole duration (decided once, here, rather than re-checked
|
|
||||||
# every tick) instead of relying on the controller's own FSM to
|
|
||||||
# notice and idle out.
|
|
||||||
# bool(...): get_theta_ist() can be a numpy.float64 (Pot's transport
|
|
||||||
# delay line is a numpy array internally) - the '<' comparison would
|
|
||||||
# then yield numpy.bool_, which json.dumps() can't serialize.
|
|
||||||
cooling = bool(ramping and ramp is not None and step['temperature'] < self.tc.get_theta_ist() - TEMP_REACHED_TOLERANCE)
|
|
||||||
self.tc.set_cooling(cooling)
|
|
||||||
|
|
||||||
if step is not None:
|
if step is not None:
|
||||||
self.apply_plant_params(step)
|
self.apply_plant_params(step)
|
||||||
if ramping and ramp is not None:
|
if ramping and ramp is not None:
|
||||||
@@ -87,7 +76,6 @@ class SudTask(ATask):
|
|||||||
'Rate': ramp.get('rate') if ramp else None,
|
'Rate': ramp.get('rate') if ramp else None,
|
||||||
'Duration': hold.get('duration') if (hold is not None and not ramping) else None,
|
'Duration': hold.get('duration') if (hold is not None and not ramping) else None,
|
||||||
'WaitForUser': step.get('user_wait_for_continue', False) if step else None,
|
'WaitForUser': step.get('user_wait_for_continue', False) if step else None,
|
||||||
'Cooling': cooling,
|
|
||||||
}}))
|
}}))
|
||||||
|
|
||||||
def on_state_changed(self, value):
|
def on_state_changed(self, value):
|
||||||
|
|||||||
Reference in New Issue
Block a user