diff --git a/tasks/heater.py b/tasks/heater.py index 0b69058..f186793 100755 --- a/tasks/heater.py +++ b/tasks/heater.py @@ -55,6 +55,20 @@ class HeaterTask(ATask): self._on_closed_loop_changed(True) asyncio.create_task(self.send({'ClosedLoop': True})) + def disconnect(self): + """Disconnects the device and zeroes its setpoint, so a later + reconnect (whether from an explicit Connect or an auto-reconnect) + never resumes at a stale power. Used for every disconnect - a + user-requested Disconnect, a comm-error timeout, and the + unexpected-exception recovery path alike - not just the explicit + one, since power_actor otherwise keeps whatever the TC last + computed (which can be stale/wound-up from before the outage) and + would be re-applied on the very next tick after reconnecting.""" + self.device.disconnect() + self.power_soll = 0 + self.power_actor = 0 + self.power_set_changed(0) + def actor(self, y): self.power_actor = max(0, self.device.get_power_max() * y) @@ -78,9 +92,7 @@ class HeaterTask(ATask): self.device.activate(True) elif pair[0] == 'Disconnect': self.device.activate(False) - self.device.disconnect() - self.power_soll = 0 - self.power_set_changed(0) + self.disconnect() elif 'Power' in pair[0]: self.power_soll = pair[1] @@ -167,12 +179,12 @@ class HeaterTask(ATask): self.device.process() except Exception as e: print(f"HeaterTask: comm error, marking disconnected: {e}") - self.device.disconnect() + self.disconnect() await asyncio.sleep(self.interval) except Exception as e: print(f"HeaterTask: unexpected error, recovering: {e}") try: - self.device.disconnect() + self.disconnect() except Exception: pass await asyncio.sleep(self.interval) diff --git a/tasks/stirrer.py b/tasks/stirrer.py index 3a3e61e..24bc8c0 100644 --- a/tasks/stirrer.py +++ b/tasks/stirrer.py @@ -37,6 +37,17 @@ class StirrerTask(ATask): if self._on_connected_changed: self._on_connected_changed(value) + def disconnect(self): + """Disconnects the device and zeroes its speed setpoint, so a later + reconnect never resumes spinning at whatever speed was last set. + Used for every disconnect - a user-requested Disconnect, a + comm-error timeout, and the unexpected-exception recovery path + alike - not just the explicit one, since self.device.speed + otherwise still holds the old value and the duty-cycle pulsing in + AStirrer.process() re-sends it on the next isOn transition.""" + self.device.disconnect() + self.device.set_speed(0.0) + async def recv(self, data): for pair in data.items(): if pair[0] == 'Connect': @@ -44,8 +55,7 @@ class StirrerTask(ATask): self.device.activate(True) elif pair[0] == 'Disconnect': self.device.activate(False) - self.device.disconnect() - self.device.set_speed(0.0) + self.disconnect() elif 'Speed' in pair[0]: self.device.set_speed(pair[1]) @@ -79,12 +89,12 @@ class StirrerTask(ATask): self.device.process() except Exception as e: print(f"StirrerTask: comm error, marking disconnected: {e}") - self.device.disconnect() + self.disconnect() await asyncio.sleep(self.interval) except Exception as e: print(f"StirrerTask: unexpected error, recovering: {e}") try: - self.device.disconnect() + self.disconnect() except Exception: pass await asyncio.sleep(self.interval)