2021-02-07 13:08:13 +01:00
import asyncio
2021-03-15 19:54:22 +01:00
2021-03-15 19:55:59 +01:00
from cbpi . api import parameters , Property , action
from cbpi . api . step import StepResult , CBPiStep
2021-03-15 19:54:22 +01:00
from cbpi . api . timer import Timer
2021-03-30 21:00:17 +02:00
from datetime import datetime
import time
from voluptuous . schema_builder import message
from cbpi . api . dataclasses import NotificationAction , NotificationType
2021-04-20 21:20:03 +02:00
from cbpi . api . dataclasses import Kettle , Props
from cbpi . api import *
import logging
from socket import timeout
from typing import KeysView
from cbpi . api . config import ConfigType
from cbpi . api . base import CBPiBase
import numpy as np
import warnings
2021-05-30 11:58:18 +02:00
2021-04-20 21:20:03 +02:00
@parameters ( [ Property . Text ( label = " Notification " , configurable = True , description = " Text for notification " ) ,
Property . Select ( label = " AutoNext " , options = [ " Yes " , " No " ] , description = " Automatically move to next step (Yes) or pause after Notification (No) " ) ] )
class NotificationStep ( CBPiStep ) :
async def NextStep ( self , * * kwargs ) :
await self . next ( )
2021-02-07 13:08:13 +01:00
2021-04-20 21:20:03 +02:00
async def on_timer_done ( self , timer ) :
self . summary = self . props . get ( " Notification " , " " )
2021-03-15 12:59:55 +01:00
2021-04-20 21:20:03 +02:00
if self . AutoNext == True :
self . cbpi . notify ( self . name , self . props . get ( " Notification " , " " ) , NotificationType . INFO )
await self . next ( )
else :
self . cbpi . notify ( self . name , self . props . get ( " Notification " , " " ) , NotificationType . INFO , action = [ NotificationAction ( " Next Step " , self . NextStep ) ] )
await self . push_update ( )
async def on_timer_update ( self , timer , seconds ) :
await self . push_update ( )
async def on_start ( self ) :
self . summary = " "
self . AutoNext = False if self . props . get ( " AutoNext " , " No " ) == " No " else True
if 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 = " "
await self . push_update ( )
async def run ( self ) :
while self . running == True :
await asyncio . sleep ( 1 )
if self . timer . is_running is not True :
self . timer . start ( )
self . timer . is_running = True
return StepResult . DONE
@parameters ( [ Property . Number ( label = " Temp " , configurable = True ) ,
Property . Sensor ( label = " Sensor " ) ,
Property . Kettle ( label = " Kettle " ) ,
2021-09-21 16:20:44 +02:00
Property . Text ( label = " Notification " , configurable = True , description = " Text for notification when Temp is reached " ) ,
2021-04-20 21:20:03 +02:00
Property . Select ( label = " AutoMode " , options = [ " Yes " , " No " ] , description = " Switch Kettlelogic automatically on and off -> Yes " ) ] )
class MashInStep ( CBPiStep ) :
async def NextStep ( self , * * kwargs ) :
await self . next ( )
async def on_timer_done ( self , timer ) :
2021-09-21 16:20:44 +02:00
self . summary = " "
2021-09-26 12:41:39 +02:00
self . kettle . target_temp = 0
2021-04-20 21:20:03 +02:00
await self . push_update ( )
if self . AutoMode == True :
await self . setAutoMode ( False )
2021-09-21 16:20:44 +02:00
self . cbpi . notify ( self . name , self . props . get ( " Notification " , " Target Temp reached. Please add malt and klick next to move on. " ) , action = [ NotificationAction ( " Next Step " , self . NextStep ) ] )
2021-04-20 21:20:03 +02:00
async def on_timer_update ( self , timer , seconds ) :
await self . push_update ( )
async def on_start ( self ) :
self . AutoMode = True if self . props . get ( " AutoMode " , " No " ) == " Yes " else False
self . kettle = self . get_kettle ( self . props . get ( " Kettle " , None ) )
if self . kettle is not None :
self . kettle . target_temp = int ( self . props . get ( " Temp " , 0 ) )
if self . AutoMode == True :
await self . setAutoMode ( True )
self . summary = " Waiting for Target Temp "
if self . cbpi . kettle 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 run ( self ) :
while self . running == True :
await asyncio . sleep ( 1 )
sensor_value = self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " )
if sensor_value > = int ( self . props . get ( " Temp " , 0 ) ) and self . timer . is_running is not True :
self . timer . start ( )
self . timer . is_running = True
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 )
async def setAutoMode ( self , auto_state ) :
try :
if ( self . kettle . instance is None or self . kettle . instance . state == False ) and ( auto_state is True ) :
await self . cbpi . kettle . toggle ( self . kettle . id )
elif ( self . kettle . instance . state == True ) and ( auto_state is False ) :
2021-11-20 11:13:51 +01:00
await self . cbpi . kettle . stop ( self . kettle . id )
2021-04-20 21:20:03 +02:00
await self . push_update ( )
except Exception as e :
logging . error ( " Failed to switch on KettleLogic {} {} " . format ( self . kettle . id , e ) )
@parameters ( [ Property . Number ( label = " Timer " , description = " Time in Minutes " , configurable = True ) ,
2021-02-07 13:08:13 +01:00
Property . Number ( label = " Temp " , configurable = True ) ,
2021-02-10 07:38:55 +01:00
Property . Sensor ( label = " Sensor " ) ,
2021-04-20 21:20:03 +02:00
Property . Kettle ( label = " Kettle " ) ,
Property . Select ( label = " AutoMode " , options = [ " Yes " , " No " ] , description = " Switch Kettlelogic automatically on and off -> Yes " ) ] )
2021-02-07 13:08:13 +01:00
class MashStep ( CBPiStep ) :
2021-04-17 11:11:14 +02:00
@action ( " Start Timer " , [ ] )
async def start_timer ( self ) :
if self . timer . is_running is not True :
self . cbpi . notify ( self . name , ' Timer started ' , NotificationType . INFO )
self . timer . start ( )
self . timer . is_running = True
else :
self . cbpi . notify ( self . name , ' Timer is already running ' , NotificationType . WARNING )
@action ( " Add 5 Minutes to Timer " , [ ] )
async def add_timer ( self ) :
if self . timer . is_running == True :
self . cbpi . notify ( self . name , ' 5 Minutes added ' , NotificationType . INFO )
await self . timer . add ( 300 )
else :
self . cbpi . notify ( self . name , ' Timer must be running to add time ' , NotificationType . WARNING )
2021-04-20 21:20:03 +02:00
async def on_timer_done ( self , timer ) :
2021-02-16 20:37:51 +01:00
self . summary = " "
2021-09-26 12:41:39 +02:00
self . kettle . target_temp = 0
2021-04-20 21:20:03 +02:00
if self . AutoMode == True :
await self . setAutoMode ( False )
self . cbpi . notify ( self . name , ' Step finished ' , NotificationType . SUCCESS )
2021-02-16 20:37:51 +01:00
await self . next ( )
2021-02-10 07:38:55 +01:00
2021-04-20 21:20:03 +02:00
async def on_timer_update ( self , timer , seconds ) :
2021-02-16 20:37:51 +01:00
self . summary = Timer . format_time ( seconds )
await self . push_update ( )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def on_start ( self ) :
2021-04-20 21:20:03 +02:00
self . AutoMode = True if self . props . get ( " AutoMode " , " No " ) == " Yes " else False
self . kettle = self . get_kettle ( self . props . Kettle )
if self . kettle is not None :
self . kettle . target_temp = int ( self . props . get ( " Temp " , 0 ) )
if self . AutoMode == True :
await self . setAutoMode ( True )
await self . push_update ( )
if self . cbpi . kettle is not None and self . timer is None :
self . timer = Timer ( int ( self . props . get ( " Timer " , 0 ) ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-11-03 09:30:16 +01:00
elif self . cbpi . kettle is not None :
try :
if self . timer . is_running == True :
self . timer . start ( )
except :
pass
2021-09-26 12:41:39 +02:00
2021-02-16 20:37:51 +01:00
self . summary = " Waiting for Target Temp "
await self . push_update ( )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def on_stop ( self ) :
await self . timer . stop ( )
self . summary = " "
2021-04-20 21:20:03 +02:00
if self . AutoMode == True :
await self . setAutoMode ( False )
2021-02-16 20:37:51 +01:00
await self . push_update ( )
2021-02-10 07:38:55 +01:00
async def reset ( self ) :
2021-04-20 21:20:03 +02:00
self . timer = Timer ( int ( self . props . get ( " Timer " , 0 ) ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-07 13:08:13 +01:00
2021-02-16 20:37:51 +01:00
async def run ( self ) :
2021-03-15 22:09:23 +01:00
while self . running == True :
2021-02-10 07:38:55 +01:00
await asyncio . sleep ( 1 )
2021-04-20 21:20:03 +02:00
sensor_value = self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " )
if sensor_value > = int ( self . props . get ( " Temp " , 0 ) ) and self . timer . is_running is not True :
2021-02-17 23:52:54 +01:00
self . timer . start ( )
2021-03-08 07:54:58 +01:00
self . timer . is_running = True
2021-04-20 21:20:03 +02:00
estimated_completion_time = datetime . fromtimestamp ( time . time ( ) + ( int ( self . props . get ( " Timer " , 0 ) ) ) * 60 )
self . cbpi . notify ( self . name , ' Timer started. Estimated completion: {} ' . format ( estimated_completion_time . strftime ( " % H: % M " ) ) , NotificationType . INFO )
2021-02-16 20:37:51 +01:00
return StepResult . DONE
2021-04-20 21:20:03 +02:00
async def setAutoMode ( self , auto_state ) :
try :
if ( self . kettle . instance is None or self . kettle . instance . state == False ) and ( auto_state is True ) :
await self . cbpi . kettle . toggle ( self . kettle . id )
elif ( self . kettle . instance . state == True ) and ( auto_state is False ) :
2021-11-20 11:13:51 +01:00
await self . cbpi . kettle . stop ( self . kettle . id )
2021-04-20 21:20:03 +02:00
await self . push_update ( )
except Exception as e :
logging . error ( " Failed to switch on KettleLogic {} {} " . format ( self . kettle . id , e ) )
2021-03-08 07:54:58 +01:00
2021-02-10 07:38:55 +01:00
@parameters ( [ Property . Number ( label = " Timer " , description = " Time in Minutes " , configurable = True ) ] )
class WaitStep ( CBPiStep ) :
2021-03-15 19:54:22 +01:00
async def on_timer_done ( self , timer ) :
2021-02-16 20:37:51 +01:00
self . summary = " "
await self . next ( )
2021-02-10 07:38:55 +01:00
2021-03-15 19:54:22 +01:00
async def on_timer_update ( self , timer , seconds ) :
2021-02-16 20:37:51 +01:00
self . summary = Timer . format_time ( seconds )
await self . push_update ( )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def on_start ( self ) :
2021-02-10 07:38:55 +01:00
if self . timer is None :
2021-03-15 19:54:22 +01:00
self . timer = Timer ( int ( self . props . Timer ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-10 07:38:55 +01:00
self . timer . start ( )
2021-02-16 20:37:51 +01:00
async def on_stop ( self ) :
await self . timer . stop ( )
self . summary = " "
await self . push_update ( )
2021-02-10 07:38:55 +01:00
async def reset ( self ) :
2021-03-15 19:54:22 +01:00
self . timer = Timer ( int ( self . props . Timer ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def run ( self ) :
2021-03-08 01:34:13 +01:00
while self . running == True :
2021-02-10 07:38:55 +01:00
await asyncio . sleep ( 1 )
2021-02-16 20:37:51 +01:00
return StepResult . DONE
2021-02-10 07:38:55 +01:00
2021-03-15 19:54:22 +01:00
2021-11-03 09:30:16 +01:00
@parameters ( [ Property . Select ( label = " toggle_type " , options = [ " On " , " Off " ] , description = " Choose if Actor should be switched on or off in this step " ) ,
2021-08-15 11:41:18 +02:00
Property . Actor ( label = " Actor " , description = " Actor that should be toggled during this step " ) ] )
class ToggleStep ( CBPiStep ) :
async def on_timer_done ( self , timer ) :
self . summary = " "
await self . next ( )
async def on_timer_update ( self , timer , seconds ) :
self . summary = Timer . format_time ( seconds )
await self . push_update ( )
async def on_start ( self ) :
if self . timer is None :
self . timer = Timer ( 1 , on_update = self . on_timer_update , on_done = self . on_timer_done )
self . timer . start ( )
self . type = self . props . get ( " toggle_type " , " Off " )
self . Actor = self . props . get ( " Actor " , None )
if self . Actor is not None and self . type == " On " :
await self . actor_on ( self . Actor )
if self . Actor is not None and self . type == " Off " :
await self . actor_off ( self . Actor )
async def on_stop ( self ) :
await self . timer . stop ( )
self . summary = " "
await self . push_update ( )
async def reset ( self ) :
self . timer = Timer ( 1 , on_update = self . on_timer_update , on_done = self . on_timer_done )
async def run ( self ) :
while self . running == True :
await asyncio . sleep ( 1 )
return StepResult . DONE
2021-02-12 00:03:18 +01:00
@parameters ( [ Property . Number ( label = " Timer " , description = " Time in Minutes " , configurable = True ) ,
2021-03-15 19:54:22 +01:00
Property . Actor ( label = " Actor " ) ] )
2021-02-10 07:38:55 +01:00
class ActorStep ( CBPiStep ) :
2021-03-15 19:54:22 +01:00
async def on_timer_done ( self , timer ) :
2021-02-16 20:37:51 +01:00
self . summary = " "
await self . next ( )
2021-02-10 07:38:55 +01:00
2021-03-15 19:54:22 +01:00
async def on_timer_update ( self , timer , seconds ) :
2021-02-16 20:37:51 +01:00
self . summary = Timer . format_time ( seconds )
await self . push_update ( )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def on_start ( self ) :
2021-02-10 07:38:55 +01:00
if self . timer is None :
2021-03-15 19:54:22 +01:00
self . timer = Timer ( int ( self . props . Timer ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-10 07:38:55 +01:00
self . timer . start ( )
2021-02-16 20:37:51 +01:00
await self . actor_on ( self . props . Actor )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def on_stop ( self ) :
await self . actor_off ( self . props . Actor )
await self . timer . stop ( )
self . summary = " "
await self . push_update ( )
2021-03-15 19:54:22 +01:00
2021-02-16 20:37:51 +01:00
async def reset ( self ) :
2021-03-15 19:54:22 +01:00
self . timer = Timer ( int ( self . props . Timer ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-10 07:38:55 +01:00
2021-02-16 20:37:51 +01:00
async def run ( self ) :
2021-03-08 01:34:13 +01:00
while self . running == True :
2021-02-10 07:38:55 +01:00
await asyncio . sleep ( 1 )
2021-02-16 20:37:51 +01:00
return StepResult . DONE
2021-02-17 23:52:54 +01:00
2021-03-30 21:00:17 +02:00
@parameters ( [ Property . Number ( label = " Timer " , description = " Time in Minutes " , configurable = True ) ,
2021-02-17 23:52:54 +01:00
Property . Number ( label = " Temp " , description = " Boil temperature " , configurable = True ) ,
2023-02-07 19:34:58 +01:00
#Property.Number(label="DwellTime", description="Time in minutes (Recommended: 5). If temp is not changing significantly within this time, Timer will start. Defaul:0 disabled", configurable=True),
2021-02-17 23:52:54 +01:00
Property . Sensor ( label = " Sensor " ) ,
2021-03-30 21:00:17 +02:00
Property . Kettle ( label = " Kettle " ) ,
2022-01-03 17:21:32 +01:00
Property . Select ( label = " LidAlert " , options = [ " Yes " , " No " ] , description = " Trigger Alert to remove lid if temp is close to boil " ) ,
2021-04-20 21:20:03 +02:00
Property . Select ( label = " AutoMode " , options = [ " Yes " , " No " ] , description = " Switch Kettlelogic automatically on and off -> Yes " ) ,
2023-02-07 19:34:58 +01:00
#Property.Select(label="AutoTimer",options=["Yes","No"], description="Start Timer automatically if Temp does not change for 5 Minutes and is above 95C/203F"),
2021-03-30 21:00:17 +02:00
Property . Select ( " First_Wort " , options = [ " Yes " , " No " ] , description = " First Wort Hop alert if set to Yes " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " First_Wort_text " , configurable = True , description = " First Wort Hop alert text " ) ,
2021-03-30 21:00:17 +02:00
Property . Number ( " Hop_1 " , configurable = True , description = " First Hop alert (minutes before finish) " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " Hop_1_text " , configurable = True , description = " First Hop alert text " ) ,
2021-03-30 21:00:17 +02:00
Property . Number ( " Hop_2 " , configurable = True , description = " Second Hop alert (minutes before finish) " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " Hop_2_text " , configurable = True , description = " Second Hop alert text " ) ,
2021-03-30 21:00:17 +02:00
Property . Number ( " Hop_3 " , configurable = True , description = " Third Hop alert (minutes before finish) " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " Hop_3_text " , configurable = True , description = " Third Hop alert text " ) ,
2021-03-30 21:00:17 +02:00
Property . Number ( " Hop_4 " , configurable = True , description = " Fourth Hop alert (minutes before finish) " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " Hop_4_text " , configurable = True , description = " Fourth Hop alert text " ) ,
2021-03-30 21:00:17 +02:00
Property . Number ( " Hop_5 " , configurable = True , description = " Fifth Hop alert (minutes before finish) " ) ,
2022-10-22 13:02:13 +02:00
Property . Text ( " Hop_5_text " , configurable = True , description = " Fifth Hop alert text " ) ,
Property . Number ( " Hop_6 " , configurable = True , description = " Sixth Hop alert (minutes before finish) " ) ,
Property . Text ( " Hop_6_text " , configurable = True , description = " Sixth Hop alert text " ) ] )
2021-02-17 23:52:54 +01:00
class BoilStep ( CBPiStep ) :
2021-03-30 21:00:17 +02:00
@action ( " Start Timer " , [ ] )
async def start_timer ( self ) :
2021-04-17 11:11:14 +02:00
if self . timer . is_running is not True :
2021-03-30 21:00:17 +02:00
self . cbpi . notify ( self . name , ' Timer started ' , NotificationType . INFO )
self . timer . start ( )
2021-04-17 11:11:14 +02:00
self . timer . is_running = True
2021-03-30 21:00:17 +02:00
else :
self . cbpi . notify ( self . name , ' Timer is already running ' , NotificationType . WARNING )
@action ( " Add 5 Minutes to Timer " , [ ] )
async def add_timer ( self ) :
2021-04-17 11:11:14 +02:00
if self . timer . is_running == True :
2021-03-30 21:00:17 +02:00
self . cbpi . notify ( self . name , ' 5 Minutes added ' , NotificationType . INFO )
await self . timer . add ( 300 )
else :
self . cbpi . notify ( self . name , ' Timer must be running to add time ' , NotificationType . WARNING )
2021-04-20 21:20:03 +02:00
async def on_timer_done ( self , timer ) :
2021-02-17 23:52:54 +01:00
self . summary = " "
2021-04-20 21:20:03 +02:00
self . kettle . target_temp = 0
if self . AutoMode == True :
await self . setAutoMode ( False )
self . cbpi . notify ( self . name , ' Boiling completed ' , NotificationType . SUCCESS )
2021-02-17 23:52:54 +01:00
await self . next ( )
2021-04-20 21:20:03 +02:00
async def on_timer_update ( self , timer , seconds ) :
2021-02-17 23:52:54 +01:00
self . summary = Timer . format_time ( seconds )
2021-03-30 21:00:17 +02:00
self . remaining_seconds = seconds
2021-02-17 23:52:54 +01:00
await self . push_update ( )
async def on_start ( self ) :
2021-04-20 21:20:03 +02:00
self . lid_temp = 95 if self . get_config_value ( " TEMP_UNIT " , " C " ) == " C " else 203
self . lid_flag = True if self . props . get ( " LidAlert " , " No " ) == " Yes " else False
self . AutoMode = True if self . props . get ( " AutoMode " , " No " ) == " Yes " else False
2023-02-07 19:34:58 +01:00
self . AutoTimer = True if self . cbpi . config . get ( " BoilAutoTimer " , " No " ) == " Yes " else False
2021-03-30 21:00:17 +02:00
self . first_wort_hop_flag = False
2021-04-17 11:11:14 +02:00
self . first_wort_hop = self . props . get ( " First_Wort " , " No " )
2022-10-22 13:02:13 +02:00
self . first_wort_hop_text = self . props . get ( " First_Wort_text " , None )
2021-03-30 21:00:17 +02:00
self . hops_added = [ " " , " " , " " , " " , " " , " " ]
self . remaining_seconds = None
2023-02-07 19:34:58 +01:00
self . temparray = np . array ( [ ] )
#self.dwelltime=int(self.props.get("DwellTime", 0))*60
self . dwelltime = 5 * 60 #tested with 5 minutes -> not exactly 5 min due to accuracy of asyncio.sleep
self . deviationlimit = 0.3 # derived from a test
logging . warning ( self . AutoTimer )
2021-02-17 23:52:54 +01:00
2021-04-20 21:20:03 +02:00
self . kettle = self . get_kettle ( self . props . get ( " Kettle " , None ) )
if self . kettle is not None :
2023-02-11 15:30:19 +01:00
self . kettle . target_temp = float ( self . props . get ( " Temp " , 0 ) )
2021-04-20 21:20:03 +02:00
if self . cbpi . kettle is not None and self . timer is None :
self . timer = Timer ( int ( self . props . get ( " Timer " , 0 ) ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-11-03 09:30:16 +01:00
elif self . cbpi . kettle is not None :
try :
if self . timer . is_running == True :
self . timer . start ( )
except :
pass
2021-04-20 21:20:03 +02:00
self . summary = " Waiting for Target Temp "
if self . AutoMode == True :
await self . setAutoMode ( True )
await self . push_update ( )
2022-10-22 13:02:13 +02:00
async def check_hop_timer ( self , number , value , text ) :
2021-04-20 21:20:03 +02:00
if value is not None and self . hops_added [ number - 1 ] is not True :
if self . remaining_seconds != None and self . remaining_seconds < = ( int ( value ) * 60 + 1 ) :
self . hops_added [ number - 1 ] = True
2022-10-22 13:02:13 +02:00
if text is not None and text != " " :
self . cbpi . notify ( ' Hop Alert ' , " Please add %s ( %s ) " % ( text , number ) , NotificationType . INFO )
else :
self . cbpi . notify ( ' Hop Alert ' , " Please add Hop %s " % number , NotificationType . INFO )
2021-04-20 21:20:03 +02:00
2021-02-17 23:52:54 +01:00
async def on_stop ( self ) :
await self . timer . stop ( )
self . summary = " "
2021-04-20 21:20:03 +02:00
self . kettle . target_temp = 0
if self . AutoMode == True :
await self . setAutoMode ( False )
2021-02-17 23:52:54 +01:00
await self . push_update ( )
async def reset ( self ) :
2021-04-20 21:20:03 +02:00
self . timer = Timer ( int ( self . props . get ( " Timer " , 0 ) ) * 60 , on_update = self . on_timer_update , on_done = self . on_timer_done )
2021-02-17 23:52:54 +01:00
async def run ( self ) :
2021-03-30 21:00:17 +02:00
if self . first_wort_hop_flag == False and self . first_wort_hop == " Yes " :
self . first_wort_hop_flag = True
2022-10-22 13:02:13 +02:00
if self . first_wort_hop_text is not None and self . first_wort_hop_text != " " :
self . cbpi . notify ( ' First Wort Hop Addition! ' , ' Please add %s for first wort ' % self . first_wort_hop_text , NotificationType . INFO )
else :
self . cbpi . notify ( ' First Wort Hop Addition! ' , ' Please add hops for first wort ' , NotificationType . INFO )
2021-03-30 21:00:17 +02:00
2021-03-08 01:34:13 +01:00
while self . running == True :
2021-02-17 23:52:54 +01:00
await asyncio . sleep ( 1 )
2021-04-20 21:20:03 +02:00
sensor_value = self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " )
2023-02-07 19:34:58 +01:00
self . temparray = np . append ( self . temparray , sensor_value )
if self . temparray . size > self . dwelltime :
self . temparray = np . delete ( self . temparray , 0 )
deviation = np . std ( self . temparray )
if ( sensor_value > = self . lid_temp ) and ( deviation < = self . deviationlimit ) and ( self . AutoTimer is True ) and ( self . timer . is_running is not True ) :
self . timer . start ( )
self . timer . is_running = True
estimated_completion_time = datetime . fromtimestamp ( time . time ( ) + ( int ( self . props . get ( " Timer " , 0 ) ) ) * 60 )
self . cbpi . notify ( self . name , ' Timer started automatically. Estimated completion: {} ' . format ( estimated_completion_time . strftime ( " % H: % M " ) ) , NotificationType . INFO )
logging . info ( " Current: " + str ( sensor_value ) + " | Dev: " + str ( deviation ) )
2021-04-20 21:20:03 +02:00
if self . lid_flag == True and sensor_value > = self . lid_temp :
self . cbpi . notify ( " Please remove lid! " , " Reached temp close to boiling " , NotificationType . INFO )
self . lid_flag = False
2023-02-11 15:30:19 +01:00
if sensor_value > = float ( self . props . get ( " Temp " , 0 ) ) and self . timer . is_running is not True :
2021-02-17 23:52:54 +01:00
self . timer . start ( )
2021-03-08 07:54:58 +01:00
self . timer . is_running = True
2021-04-20 21:20:03 +02:00
estimated_completion_time = datetime . fromtimestamp ( time . time ( ) + ( int ( self . props . get ( " Timer " , 0 ) ) ) * 60 )
self . cbpi . notify ( self . name , ' Timer started. Estimated completion: {} ' . format ( estimated_completion_time . strftime ( " % H: % M " ) ) , NotificationType . INFO )
2021-03-30 21:00:17 +02:00
else :
2021-04-17 11:11:14 +02:00
for x in range ( 1 , 6 ) :
2022-10-22 13:02:13 +02:00
await self . check_hop_timer ( x , self . props . get ( " Hop_ %s " % x , None ) , self . props . get ( " Hop_ %s _text " % x , None ) )
2021-03-30 21:00:17 +02:00
2021-02-17 23:52:54 +01:00
return StepResult . DONE
2021-04-20 21:20:03 +02:00
async def setAutoMode ( self , auto_state ) :
try :
if ( self . kettle . instance is None or self . kettle . instance . state == False ) and ( auto_state is True ) :
await self . cbpi . kettle . toggle ( self . kettle . id )
elif ( self . kettle . instance . state == True ) and ( auto_state is False ) :
2021-11-20 11:13:51 +01:00
await self . cbpi . kettle . stop ( self . kettle . id )
2021-04-20 21:20:03 +02:00
await self . push_update ( )
except Exception as e :
logging . error ( " Failed to switch on KettleLogic {} {} " . format ( self . kettle . id , e ) )
@parameters ( [ Property . Number ( label = " Temp " , configurable = True , description = " Target temperature for cooldown. Notification will be send when temp is reached and Actor can be triggered " ) ,
Property . Sensor ( label = " Sensor " , description = " Sensor that is used during cooldown " ) ,
Property . Actor ( label = " Actor " , description = " Actor can trigger a valve for the cooldwon to target temperature " ) ,
Property . Kettle ( label = " Kettle " ) ] )
class CooldownStep ( CBPiStep ) :
async def on_timer_done ( self , timer ) :
self . summary = " "
if self . actor is not None :
await self . actor_off ( self . actor )
self . cbpi . notify ( ' CoolDown ' , ' Wort cooled down. Please transfer to Fermenter. ' , NotificationType . INFO )
await self . next ( )
async def on_timer_update ( self , timer , seconds ) :
await self . push_update ( )
async def on_start ( self ) :
2024-09-15 13:29:58 +02:00
try :
warnings . simplefilter ( ' ignore ' , np . exceptions . RankWarning )
except Exception as e :
logging . error ( f " Numpy Error: { e } " )
2021-04-20 21:20:03 +02:00
self . temp_array = [ ]
self . time_array = [ ]
self . kettle = self . get_kettle ( self . props . get ( " Kettle " , None ) )
self . actor = self . props . get ( " Actor " , None )
self . target_temp = int ( self . props . get ( " Temp " , 0 ) )
2023-02-11 15:30:19 +01:00
self . Interval = 10 # Interval in minutes on how often cooldwon end time is calculated
2021-04-20 21:20:03 +02:00
self . cbpi . notify ( self . name , ' Cool down to {} ° ' . format ( self . target_temp ) , NotificationType . INFO )
if self . timer is None :
self . timer = Timer ( 1 , on_update = self . on_timer_update , on_done = self . on_timer_done )
self . start_time = time . time ( )
self . temp_array . append ( self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " ) )
self . time_array . append ( time . time ( ) )
self . next_check = self . start_time + self . Interval * 60
self . count = 0
2021-05-30 11:58:18 +02:00
self . initial_date = None
2021-04-20 21:20:03 +02:00
async def on_stop ( self ) :
await self . timer . stop ( )
self . summary = " "
if self . actor is not None :
await self . actor_off ( self . actor )
await self . push_update ( )
async def reset ( self ) :
self . timer = Timer ( 1 , on_update = self . on_timer_update , on_done = self . on_timer_done )
async def run ( self ) :
timestring = datetime . fromtimestamp ( self . start_time )
if self . actor is not None :
await self . actor_on ( self . actor )
self . summary = " Started: {} " . format ( timestring . strftime ( " % H: % M " ) )
await self . push_update ( )
while self . running == True :
current_temp = self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " )
2023-02-11 15:30:19 +01:00
if self . count == 3 :
2021-04-20 21:20:03 +02:00
self . temp_array . append ( current_temp )
2021-05-30 11:58:18 +02:00
current_time = time . time ( )
if self . initial_date == None :
self . initial_date = current_time
self . time_array . append ( current_time )
2021-04-20 21:20:03 +02:00
self . count = 0
if time . time ( ) > = self . next_check :
self . next_check = time . time ( ) + ( self . Interval * 60 )
2021-05-30 11:58:18 +02:00
2024-07-07 19:14:55 +02:00
cooldown_model = np . polynomial . polynomial . Polynomial . fit ( self . temp_array , self . time_array , 2 )
2021-04-20 21:20:03 +02:00
target_time = cooldown_model ( self . target_temp )
target_timestring = datetime . fromtimestamp ( target_time )
self . summary = " ECT: {} " . format ( target_timestring . strftime ( " % H: % M " ) )
self . cbpi . notify ( " Cooldown Step " , " Current: {} °, reaching {} ° at {} " . format ( round ( current_temp , 1 ) , self . target_temp , target_timestring . strftime ( " %d . % m % H: % M " ) ) , NotificationType . INFO )
2023-02-11 15:30:19 +01:00
self . temp_array = [ ]
self . time_array = [ ]
self . temp_array . append ( self . get_sensor_value ( self . props . get ( " Sensor " , None ) ) . get ( " value " ) )
self . time_array . append ( time . time ( ) )
2021-04-20 21:20:03 +02:00
await self . push_update ( )
if current_temp < = self . target_temp and self . timer . is_running is not True :
self . timer . start ( )
self . timer . is_running = True
self . count + = 1
await asyncio . sleep ( 1 )
return StepResult . DONE
2021-03-15 19:54:22 +01:00
2021-02-07 13:08:13 +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 :
2021-03-15 19:54:22 +01:00
'''
2021-04-20 21:20:03 +02:00
cbpi . plugin . register ( " MashInStep " , MashInStep )
cbpi . plugin . register ( " MashStep " , MashStep )
2021-02-17 23:52:54 +01:00
cbpi . plugin . register ( " BoilStep " , BoilStep )
2021-04-20 21:20:03 +02:00
cbpi . plugin . register ( " CooldownStep " , CooldownStep )
2021-02-10 07:38:55 +01:00
cbpi . plugin . register ( " WaitStep " , WaitStep )
2021-08-15 11:41:18 +02:00
cbpi . plugin . register ( " ToggleStep " , ToggleStep )
2021-02-16 20:37:51 +01:00
cbpi . plugin . register ( " ActorStep " , ActorStep )
2021-04-20 21:20:03 +02:00
cbpi . plugin . register ( " NotificationStep " , NotificationStep )