Heater and Stirrer can be real serial hardware (hendi, Pololu1376), but there was no connection concept at all - the constructors opened the port and crashed the whole server if the device was missing, with no way to see connection status or firmware version and no way to reconnect without a restart. Adds an observable Connectable mixin (components/connectable.py) shared by AHeater/AStirrer; real devices defer opening the serial port to an explicit connect(), auto-connect on server startup, and surface Connected/FirmwareVersion/Simulated plus manual Connect/Disconnect over the web GUI. Heating/stirring and Sud Start are all gated on connection state, and a disconnect mid-brew force-stops the run via the same path as a manual Stop. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YaPLuRPpyjWcwhMvCvpHCL
68 lines
1.4 KiB
Python
Executable File
68 lines
1.4 KiB
Python
Executable File
from components.aheater import AHeater
|
|
from components.actor.hendiCtrl import HendiCtrl
|
|
|
|
|
|
class HeaterHendi(AHeater):
|
|
def __init__(self, params):
|
|
AHeater.__init__(self, simulated=False)
|
|
self.hendi = HendiCtrl(params['port'], params['speed'])
|
|
self.power_set = 0
|
|
self.power_eff = 0
|
|
|
|
def get_power_min(self):
|
|
return 0
|
|
|
|
def get_power_max(self):
|
|
caps = self.hendi.getCapabilties()
|
|
return caps['pwr_watts_max']
|
|
|
|
def get_powers(self):
|
|
caps = self.hendi.getCapabilties()
|
|
return [0] + caps['pwr_list']
|
|
|
|
def connect(self):
|
|
ok = self.hendi.connect()
|
|
self.connected = ok
|
|
self.firmware_version = self.hendi.sw_ver if ok else None
|
|
return ok
|
|
|
|
def disconnect(self):
|
|
self.hendi.disconnect()
|
|
self.connected = False
|
|
self.firmware_version = None
|
|
|
|
def activate(self, enable):
|
|
if not self.connected:
|
|
return
|
|
if enable:
|
|
self.hendi.remoteEnable(1)
|
|
else:
|
|
self.hendi.setSwitch(0)
|
|
|
|
def is_activated(self):
|
|
if not self.connected:
|
|
return False
|
|
s = self.hendi.isRemoteEnable()
|
|
return '1' in s
|
|
|
|
def process(self):
|
|
if not self.connected:
|
|
self.power_eff = 0
|
|
return
|
|
power = self.power_set
|
|
if power == 0:
|
|
self.hendi.setSwitch(0)
|
|
else:
|
|
self.hendi.setSwitch(1)
|
|
self.hendi.setPowerWatts(power)
|
|
self.power_eff = self.hendi.getPowerWatts() if power > 0 else 0
|
|
|
|
def set_power(self, power):
|
|
self.power_set = min(self.get_power_max(), power)
|
|
|
|
def get_power(self):
|
|
return self.power_eff
|
|
|
|
def close(self):
|
|
self.disconnect()
|