From 42670efd9c95265f34398e548d9d6eecdb5041f8 Mon Sep 17 00:00:00 2001 From: avollkopf <43980694+avollkopf@users.noreply.github.com> Date: Mon, 28 Mar 2022 15:59:04 +0200 Subject: [PATCH] Added fermenterstep with controlled ramp rate --- cbpi/controller/fermentation_controller.py | 12 +- cbpi/extension/FermentationStep/__init__.py | 121 +++++++++++++++++++- 2 files changed, 121 insertions(+), 12 deletions(-) diff --git a/cbpi/controller/fermentation_controller.py b/cbpi/controller/fermentation_controller.py index 7015618..f75690a 100644 --- a/cbpi/controller/fermentation_controller.py +++ b/cbpi/controller/fermentation_controller.py @@ -54,10 +54,7 @@ class FermentationController: for step in fermenter.steps: try: self.logger.info("Stop {}".format(step.name)) - try: - step.instance.shutdown = True - except: - pass + step.instance.shutdown = True await step.instance.stop() except Exception as e: self.logger.error(e) @@ -67,10 +64,7 @@ class FermentationController: for step in fermenter.steps: try: self.logger.info("Stop {}".format(step.name)) - try: - step.instance.shutdown = True - except: - pass + step.instance.shutdown = True await step.instance.stop() except Exception as e: self.logger.error(e) @@ -588,4 +582,4 @@ class FermentationController: self.save() self.push_update("fermenterstepupdate") return step - \ No newline at end of file + diff --git a/cbpi/extension/FermentationStep/__init__.py b/cbpi/extension/FermentationStep/__init__.py index 7ebfbc2..7d905a9 100644 --- a/cbpi/extension/FermentationStep/__init__.py +++ b/cbpi/extension/FermentationStep/__init__.py @@ -81,8 +81,9 @@ class FermenterTargetTempStep(CBPiFermentationStep): if self.AutoMode == True: await self.setAutoMode(False) self.cbpi.notify(self.name, self.props.get("Notification","Target Temp reached. Please add malt and klick next to move on.")) - await self.next(self.fermenter.id) - return StepResult.DONE + if self.shutdown == False: + await self.next(self.fermenter.id) + return StepResult.DONE async def on_timer_update(self,timer, seconds): @@ -183,7 +184,7 @@ class FermenterStep(CBPiFermentationStep): if self.AutoMode == True: await self.setAutoMode(False) self.cbpi.notify(self.name, 'Step finished', NotificationType.SUCCESS) - if self.shutdown != True: + if self.shutdown == False: await self.next(self.fermenter.id) return StepResult.DONE @@ -291,6 +292,119 @@ class FermenterStep(CBPiFermentationStep): except Exception as e: logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e)) +@parameters([Property.Number(label="Temp", configurable=True, description = "Ramp to this temp"), + Property.Number(label="RampRate", configurable=True, description = "Ramp x °C/F per day. Default: 1"), + Property.Sensor(label="Sensor"), + Property.Text(label="Notification",configurable = True, description = "Text for notification when Temp is reached"), + Property.Select(label="AutoMode",options=["Yes","No"], description="Switch Fermenterlogic automatically on and off -> Yes")]) +class FermenterRampTempStep(CBPiFermentationStep): + + async def NextStep(self, **kwargs): + if self.shutdown == False: + await self.next(self.fermenter.id) + return StepResult.DONE + + async def on_timer_done(self,timer): + self.summary = "" + await self.push_update() + if self.AutoMode == True: + await self.setAutoMode(False) + self.cbpi.notify(self.name, self.props.get("Notification","Target Temp reached. Please add malt and klick next to move on.")) + await self.next(self.fermenter.id) + return StepResult.DONE + + + async def on_timer_update(self,timer, seconds): + await self.push_update() + + async def on_start(self): + self.shutdown = False + self.AutoMode = True if self.props.get("AutoMode","No") == "Yes" else False + self.rate=float(self.props.get("RampRate",1)) + logging.info(self.rate) + self.target_temp = round(float(self.props.get("Temp", 0))*10)/10 + logging.info(self.target_temp) + while self.get_sensor_value(self.props.get("Sensor", None)).get("value") > 900: + await asyncio.sleep(1) + self.starttemp = self.get_sensor_value(self.props.get("Sensor", None)).get("value") + + self.current_target_temp = self.starttemp + if self.fermenter is not None: + await self.set_fermenter_target_temp(self.fermenter.id, self.current_target_temp) + if self.AutoMode == True: + await self.setAutoMode(True) + self.summary = "Ramping to {}° with {}° per day".format(self.target_temp,self.rate) + if self.fermenter is not None and self.timer is None: + self.timer = Timer(1 ,on_update=self.on_timer_update, on_done=self.on_timer_done) + await self.push_update() + + async def on_stop(self): + await self.timer.stop() + self.summary = "" + if self.AutoMode == True: + await self.setAutoMode(False) + await self.push_update() + + async def calc_target_temp(self): + delta_time = time.time() - self.starttime + current_target_temp = round((self.starttemp + delta_time * self.ratesecond)*10)/10 +# logging.info(current_target_temp) + if current_target_temp != self.current_target_temp: + self.current_target_temp = current_target_temp + await self.set_fermenter_target_temp(self.fermenter.id, self.current_target_temp) + #self.fermenter.target_temp = self.current_target_temp + await self.push_update() + + pass + + async def run(self): + self.delta_temp = self.target_temp-self.starttemp + try: + self.deltadays = abs(self.delta_temp / self.rate) + self.deltaseconds = self.deltadays * 24 * 60 * 60 + self.ratesecond = self.delta_temp/self.deltaseconds + except Exception as e: + logging.info(e) + self.starttime=time.time() + + if self.target_temp >= self.starttemp: + logging.info("warmup") + while self.running == True: + if self.current_target_temp != self.target_temp: + await self.calc_target_temp() + sensor_value = self.get_sensor_value(self.props.get("Sensor", None)).get("value") + if sensor_value >= self.target_temp and self.timer.is_running is not True: + self.timer.start() + self.timer.is_running = True + await asyncio.sleep(1) + elif self.target_temp <= self.starttemp: + logging.info("Cooldown") + while self.running == True: + if self.current_target_temp != self.target_temp: + await self.calc_target_temp() + sensor_value = self.get_sensor_value(self.props.get("Sensor", None)).get("value") + if sensor_value <= self.target_temp and self.timer.is_running is not True: + self.timer.start() + self.timer.is_running = True + await asyncio.sleep(1) + await self.push_update() + return StepResult.DONE + + async def reset(self): + self.timer = Timer(1 ,on_update=self.on_timer_update, on_done=self.on_timer_done) + self.timer.is_running == False + + async def setAutoMode(self, auto_state): + try: + if (self.fermenter.instance is None or self.fermenter.instance.state == False) and (auto_state is True): + await self.cbpi.fermenter.toggle(self.fermenter.id) + elif (self.fermenter.instance.state == True) and (auto_state is False): + await self.fermenter.instance.stop() + await self.push_update() + + except Exception as e: + logging.error("Failed to switch on FermenterLogic {} {}".format(self.fermenter.id, e)) + def setup(cbpi): ''' @@ -303,4 +417,5 @@ def setup(cbpi): cbpi.plugin.register("FermenterNotificationStep", FermenterNotificationStep) cbpi.plugin.register("FermenterTargetTempStep", FermenterTargetTempStep) + cbpi.plugin.register("FermenterRampTempStep", FermenterRampTempStep) cbpi.plugin.register("FermenterStep", FermenterStep)