2022-01-02 11:25:56 +01:00
import asyncio
from asyncio import tasks
import logging
from cbpi . api import *
import aiohttp
from aiohttp import web
from cbpi . controller . fermentation_controller import FermentationController
from cbpi . api . dataclasses import Fermenter , Props , Step
from cbpi . api . base import CBPiBase
from cbpi . api . config import ConfigType
import json
import webbrowser
class FermenterAutostart ( CBPiExtension ) :
def __init__ ( self , cbpi ) :
self . cbpi = cbpi
self . _task = asyncio . create_task ( self . run ( ) )
self . controller : FermentationController = cbpi . fermenter
async def run ( self ) :
logging . info ( " Starting Fermenter Autorun " )
#get all kettles
2022-01-02 12:43:33 +01:00
try :
self . fermenter = self . controller . get_state ( )
for id in self . fermenter [ ' data ' ] :
try :
self . autostart = ( id [ ' props ' ] [ ' AutoStart ' ] )
if self . autostart == " Yes " :
fermenter_id = ( id [ ' id ' ] )
logging . info ( " Enabling Autostart for Fermenter {} " . format ( fermenter_id ) )
self . fermenter = self . cbpi . fermenter . _find_by_id ( fermenter_id )
try :
if ( self . fermenter . instance is None or self . fermenter . instance . state == False ) :
2022-03-02 07:53:43 +01:00
await self . cbpi . fermenter . start ( self . fermenter . id )
2022-01-02 12:43:33 +01:00
logging . info ( " Successfully switched on Ferenterlogic for Fermenter {} " . format ( self . fermenter . id ) )
except Exception as e :
logging . error ( " Failed to switch on FermenterLogic {} {} " . format ( self . fermenter . id , e ) )
except :
pass
except :
pass
2022-01-02 11:25:56 +01:00
@parameters ( [ Property . Number ( label = " HeaterOffsetOn " , configurable = True , description = " Offset as decimal number when the heater is switched on. Should be greater then ' HeaterOffsetOff ' . For example a value of 2 switches on the heater if the current temperature is 2 degrees below the target temperature " ) ,
Property . Number ( label = " HeaterOffsetOff " , configurable = True , description = " Offset as decimal number when the heater is switched off. Should be smaller then ' HeaterOffsetOn ' . For example a value of 1 switches off the heater if the current temperature is 1 degree below the target temperature " ) ,
2023-01-27 17:09:53 +01:00
Property . Number ( label = " CoolerOffsetOn " , configurable = True , description = " Offset as decimal number when the cooler is switched on. Should be greater then ' CoolerOffsetOff ' . For example a value of 2 switches on the cooler if the current temperature is 2 degrees above the target temperature " ) ,
Property . Number ( label = " CoolerOffsetOff " , configurable = True , description = " Offset as decimal number when the cooler is switched off. Should be smaller then ' CoolerOffsetOn ' . For example a value of 1 switches off the cooler if the current temperature is 1 degree above the target temperature " ) ,
2024-01-13 16:31:15 +01:00
Property . Number ( label = " HeaterMaxPower " , configurable = True , description = " Max Power [ % ] for Heater (default: 100) " ) ,
Property . Number ( label = " CoolerMaxPower " , configurable = True , description = " Max Power [ % ] for Cooler (default: 100) " ) ,
2022-01-03 12:47:20 +01:00
Property . Select ( label = " AutoStart " , options = [ " Yes " , " No " ] , description = " Autostart Fermenter on cbpi start " ) ,
Property . Sensor ( label = " sensor2 " , description = " Optional Sensor for LCDisplay(e.g. iSpindle) " ) ] )
2022-01-02 11:25:56 +01:00
class FermenterHysteresis ( CBPiFermenterLogic ) :
async def run ( self ) :
try :
self . heater_offset_min = float ( self . props . get ( " HeaterOffsetOn " , 0 ) )
self . heater_offset_max = float ( self . props . get ( " HeaterOffsetOff " , 0 ) )
self . cooler_offset_min = float ( self . props . get ( " CoolerOffsetOn " , 0 ) )
self . cooler_offset_max = float ( self . props . get ( " CoolerOffsetOff " , 0 ) )
2024-01-13 16:31:15 +01:00
self . heater_max_power = int ( self . props . get ( " HeaterMaxPower " , 100 ) )
self . cooler_max_power = int ( self . props . get ( " CoolerMaxPower " , 100 ) )
2022-01-02 11:25:56 +01:00
self . fermenter = self . get_fermenter ( self . id )
self . heater = self . fermenter . heater
self . cooler = self . fermenter . cooler
2022-01-03 12:47:20 +01:00
heater = self . cbpi . actor . find_by_id ( self . heater )
cooler = self . cbpi . actor . find_by_id ( self . cooler )
2022-01-02 11:25:56 +01:00
while self . running == True :
2022-01-02 13:24:40 +01:00
sensor_value = float ( self . get_sensor_value ( self . fermenter . sensor ) . get ( " value " ) )
target_temp = float ( self . get_fermenter_target_temp ( self . id ) )
2022-01-02 11:25:56 +01:00
2022-01-03 12:47:20 +01:00
try :
heater_state = heater . instance . state
except :
heater_state = False
try :
cooler_state = cooler . instance . state
except :
cooler_state = False
2022-01-02 11:25:56 +01:00
if sensor_value + self . heater_offset_min < = target_temp :
2022-01-03 12:47:20 +01:00
if self . heater and ( heater_state == False ) :
2024-01-13 16:31:15 +01:00
await self . actor_on ( self . heater , self . heater_max_power )
2022-01-02 11:25:56 +01:00
if sensor_value + self . heater_offset_max > = target_temp :
2022-01-03 12:47:20 +01:00
if self . heater and ( heater_state == True ) :
2022-01-02 11:25:56 +01:00
await self . actor_off ( self . heater )
if sensor_value > = self . cooler_offset_min + target_temp :
2022-01-03 12:47:20 +01:00
if self . cooler and ( cooler_state == False ) :
2024-01-13 16:31:15 +01:00
await self . actor_on ( self . cooler , self . cooler_max_power )
2022-01-02 11:25:56 +01:00
if sensor_value < = self . cooler_offset_max + target_temp :
2022-01-03 12:47:20 +01:00
if self . cooler and ( cooler_state == True ) :
2022-01-02 11:25:56 +01:00
await self . actor_off ( self . cooler )
await asyncio . sleep ( 1 )
except asyncio . CancelledError as e :
pass
except Exception as e :
2022-04-03 20:07:22 +02:00
logging . error ( " Fermenter Hysteresis Error {} " . format ( e ) )
2022-01-02 11:25:56 +01:00
finally :
self . running = False
if self . heater :
await self . actor_off ( self . heater )
if self . cooler :
await self . actor_off ( self . cooler )
2022-04-03 20:07:22 +02:00
@parameters ( [ Property . Number ( label = " HeaterOffsetOn " , configurable = True , description = " Offset as decimal number when the heater is switched on. Should be greater then ' HeaterOffsetOff ' . For example a value of 2 switches on the heater if the current temperature is 2 degrees below the target temperature " ) ,
Property . Number ( label = " HeaterOffsetOff " , configurable = True , description = " Offset as decimal number when the heater is switched off. Should be smaller then ' HeaterOffsetOn ' . For example a value of 1 switches off the heater if the current temperature is 1 degree below the target temperature " ) ,
Property . Number ( label = " CoolerOffsetOn " , configurable = True , description = " Offset as decimal number when the cooler is switched on. Should be greater then ' CoolerOffsetOff ' . For example a value of 2 switches on the cooler if the current temperature is 2 degrees below the target temperature " ) ,
Property . Number ( label = " CoolerOffsetOff " , configurable = True , description = " Offset as decimal number when the cooler is switched off. Should be smaller then ' CoolerOffsetOn ' . For example a value of 1 switches off the cooler if the current temperature is 1 degree below the target temperature " ) ,
Property . Number ( label = " SpundingOffsetOpen " , configurable = True , description = " Offset above target pressure as decimal number when the valve is opened " ) ,
2022-04-04 19:56:47 +02:00
Property . Select ( label = " ValveRelease " , options = [ 1 , 2 , 3 , 4 , 5 ] , description = " Valve Release time in seconds " ) ,
Property . Select ( label = " Pause " , options = [ 1 , 2 , 3 , 4 , 5 ] , description = " Pause time in seconds between valve release " ) ,
2022-04-03 20:07:22 +02:00
Property . Select ( label = " AutoStart " , options = [ " Yes " , " No " ] , description = " Autostart Fermenter on cbpi start " ) ,
Property . Sensor ( label = " sensor2 " , description = " Optional Sensor for LCDisplay(e.g. iSpindle) " ) ] )
class FermenterSpundingHysteresis ( CBPiFermenterLogic ) :
# subroutine that controls pressure
async def pressure_control ( self ) :
self . spunding_offset = float ( self . props . get ( " SpundingOffsetOpen " , 0 ) )
2022-04-04 19:56:47 +02:00
self . valverelease = int ( self . props . get ( " ValveRelease " , 1 ) )
self . pause = int ( self . props . get ( " Pause " , 2 ) )
2022-04-03 20:07:22 +02:00
if self . valve and self . fermenter . pressure_sensor :
2022-04-05 12:31:20 +02:00
#valve = self.cbpi.actor.find_by_id(self.valve)
2022-04-03 20:07:22 +02:00
await self . actor_off ( self . valve )
2022-04-05 12:31:20 +02:00
#logging.info("Closing Spunding Valve")
2022-04-03 20:07:22 +02:00
while self . running :
target_pressure = float ( self . fermenter . target_pressure )
current_pressure = float ( self . get_sensor_value ( self . fermenter . pressure_sensor ) . get ( " value " ) )
2022-04-05 12:31:20 +02:00
#logging.info(f'Target: {target_pressure} | Current: {current_pressure}')
if current_pressure > = ( target_pressure + self . spunding_offset ) and target_pressure != 0 :
2022-04-03 20:07:22 +02:00
while current_pressure > = target_pressure :
await self . actor_on ( self . valve )
2022-04-04 19:56:47 +02:00
await asyncio . sleep ( self . valverelease )
2022-04-03 20:07:22 +02:00
await self . actor_off ( self . valve )
2022-04-04 19:56:47 +02:00
await asyncio . sleep ( self . pause )
2022-04-03 20:07:22 +02:00
current_pressure = float ( self . get_sensor_value ( self . fermenter . pressure_sensor ) . get ( " value " ) )
2022-04-05 12:31:20 +02:00
#logging.info("Value higher than target: Spunding loop is running")
2022-04-03 20:07:22 +02:00
await asyncio . sleep ( 1 )
else :
logging . info ( " No valve or pressure sensor defined " )
2022-04-11 13:06:32 +02:00
async def temperature_control ( self ) :
2022-04-03 20:07:22 +02:00
self . heater_offset_min = float ( self . props . get ( " HeaterOffsetOn " , 0 ) )
self . heater_offset_max = float ( self . props . get ( " HeaterOffsetOff " , 0 ) )
self . cooler_offset_min = float ( self . props . get ( " CoolerOffsetOn " , 0 ) )
self . cooler_offset_max = float ( self . props . get ( " CoolerOffsetOff " , 0 ) )
heater = self . cbpi . actor . find_by_id ( self . heater )
cooler = self . cbpi . actor . find_by_id ( self . cooler )
while self . running == True :
sensor_value = float ( self . get_sensor_value ( self . fermenter . sensor ) . get ( " value " ) )
target_temp = float ( self . get_fermenter_target_temp ( self . id ) )
try :
heater_state = heater . instance . state
except :
heater_state = False
try :
cooler_state = cooler . instance . state
except :
cooler_state = False
if sensor_value + self . heater_offset_min < = target_temp :
if self . heater and ( heater_state == False ) :
await self . actor_on ( self . heater )
if sensor_value + self . heater_offset_max > = target_temp :
if self . heater and ( heater_state == True ) :
await self . actor_off ( self . heater )
if sensor_value > = self . cooler_offset_min + target_temp :
if self . cooler and ( cooler_state == False ) :
await self . actor_on ( self . cooler )
if sensor_value < = self . cooler_offset_max + target_temp :
if self . cooler and ( cooler_state == True ) :
await self . actor_off ( self . cooler )
await asyncio . sleep ( 1 )
2022-04-11 13:06:32 +02:00
async def run ( self ) :
try :
self . fermenter = self . get_fermenter ( self . id )
self . heater = self . fermenter . heater
self . cooler = self . fermenter . cooler
self . valve = self . fermenter . valve
pressure_controller = asyncio . create_task ( self . pressure_control ( ) )
temperature_controller = asyncio . create_task ( self . temperature_control ( ) )
await pressure_controller
await temperature_controller
2022-04-03 20:07:22 +02:00
except asyncio . CancelledError as e :
pass
except Exception as e :
logging . error ( " Fermenter Spunding Hysteresis Error {} " . format ( e ) )
finally :
self . running = False
if self . heater :
await self . actor_off ( self . heater )
if self . cooler :
await self . actor_off ( self . cooler )
2022-04-11 13:06:32 +02:00
if self . valve :
await self . actor_off ( self . valve )
2022-01-02 11:25:56 +01:00
def setup ( cbpi ) :
'''
This method is called by the server during startup
Here you need to register your plugins at the server
: param cbpi : the cbpi core
: return :
'''
2022-04-03 20:07:22 +02:00
cbpi . plugin . register ( " Fermenter Spunding Hysteresis " , FermenterSpundingHysteresis )
2022-01-02 11:25:56 +01:00
cbpi . plugin . register ( " Fermenter Hysteresis " , FermenterHysteresis )
cbpi . plugin . register ( " Fermenter Autostart " , FermenterAutostart )