2013-11-24 16:57:12 +00:00
import threading , time , random , datetime , logging , json
2013-11-23 22:50:59 +00:00
2013-11-23 21:25:20 +00:00
log = logging . getLogger ( __name__ )
2013-11-23 23:36:10 +00:00
try :
from max31855 import MAX31855 , MAX31855Error
sensor_dummy = False
except ImportError :
log . warning ( " Could not initialize temperature sensor, using dummy values! " )
sensor_dummy = True
2013-11-23 21:25:20 +00:00
class Oven ( threading . Thread ) :
2013-11-24 14:27:29 +00:00
STATE_IDLE = " IDLE "
2013-11-23 21:25:20 +00:00
STATE_RUNNING = " RUNNING "
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
def __init__ ( self ) :
threading . Thread . __init__ ( self )
2013-11-23 22:54:45 +00:00
self . daemon = True
2013-11-25 00:50:10 +00:00
self . reset ( )
self . temp_sensor = TempSensor ( self )
self . temp_sensor . start ( )
self . start ( )
2013-11-28 16:44:06 +00:00
2013-11-25 00:50:10 +00:00
def reset ( self ) :
2013-11-23 21:25:20 +00:00
self . profile = None
self . start_time = 0
2013-11-23 23:30:06 +00:00
self . runtime = 0
2013-11-24 14:27:29 +00:00
self . totaltime = 0
2013-11-24 17:35:08 +00:00
self . target = 0
2013-11-23 21:25:20 +00:00
self . power = 0.0
self . state = Oven . STATE_IDLE
2013-11-28 16:44:06 +00:00
2013-11-23 21:25:20 +00:00
def run_profile ( self , profile ) :
2013-11-24 17:35:08 +00:00
log . info ( " Running profile %s " % profile . name )
2013-11-23 21:25:20 +00:00
self . profile = profile
2013-11-24 19:40:09 +00:00
self . totaltime = profile . get_duration ( )
2013-11-23 21:25:20 +00:00
self . state = Oven . STATE_RUNNING
self . start_time = datetime . datetime . now ( )
log . info ( " Starting " )
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
def abort_run ( self ) :
2013-11-25 00:50:10 +00:00
self . reset ( )
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
def run ( self ) :
while True :
if self . state == Oven . STATE_RUNNING :
2013-11-23 23:30:06 +00:00
self . runtime = ( datetime . datetime . now ( ) - self . start_time ) . total_seconds ( )
2013-11-24 17:54:29 +00:00
log . info ( " running at %.1f deg C (Target: %.1f ) , power %.2f ( %.1f s/ %.0f ) " % ( self . temp_sensor . temperature , self . target , self . power , self . runtime , self . totaltime ) )
2013-11-24 17:35:08 +00:00
self . target = self . profile . get_target_temperature ( self . runtime )
2013-11-28 16:44:06 +00:00
2013-11-24 17:35:08 +00:00
if self . temp_sensor . temperature < self . target :
2013-11-23 21:25:20 +00:00
self . power = 1.0
else :
self . power = 0.0
2013-11-24 14:27:29 +00:00
if self . runtime > = self . totaltime :
2013-11-25 00:50:10 +00:00
self . reset ( )
2013-11-28 16:44:06 +00:00
time . sleep ( 0.5 )
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
def get_state ( self ) :
state = {
2013-11-23 23:30:06 +00:00
' runtime ' : self . runtime ,
2013-11-23 21:25:20 +00:00
' temperature ' : self . temp_sensor . temperature ,
2013-11-24 17:35:08 +00:00
' target ' : self . target ,
2013-11-23 21:25:20 +00:00
' state ' : self . state ,
' power ' : self . power ,
2013-11-24 14:27:29 +00:00
' totaltime ' : self . totaltime
2013-11-23 21:25:20 +00:00
}
return state
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
class TempSensor ( threading . Thread ) :
def __init__ ( self , oven ) :
threading . Thread . __init__ ( self )
2013-11-23 22:54:45 +00:00
self . daemon = True
2013-11-28 16:44:06 +00:00
2013-11-23 21:25:20 +00:00
self . temperature = 0
self . oven = oven
2013-11-28 16:44:06 +00:00
2013-11-23 23:36:10 +00:00
if not sensor_dummy :
2013-11-23 22:50:59 +00:00
cs_pin = 27
clock_pin = 22
data_pin = 17
units = " c "
self . thermocouple = MAX31855 ( cs_pin , clock_pin , data_pin , units )
2013-11-23 22:40:46 +00:00
2013-11-23 21:25:20 +00:00
def run ( self ) :
while True :
2013-11-23 23:36:10 +00:00
if not sensor_dummy :
2013-11-23 22:50:59 +00:00
self . temperature = self . thermocouple . get ( )
else :
time_delta = ( 20.0 - self . temperature ) / 40
power_delta = 8.0 * self . oven . power
self . temperature + = ( time_delta + power_delta )
2013-11-28 16:44:06 +00:00
time . sleep ( 0.5 )
2013-11-23 22:40:46 +00:00
2013-11-24 16:57:12 +00:00
class Profile ( ) :
def __init__ ( self , json_data ) :
obj = json . loads ( json_data )
self . name = obj [ " name " ]
2013-11-24 17:35:08 +00:00
self . data = sorted ( obj [ " data " ] )
2013-11-28 16:44:06 +00:00
2013-11-24 16:57:12 +00:00
def get_duration ( self ) :
return max ( [ t for ( t , x ) in self . data ] )
2013-11-28 16:44:06 +00:00
2013-11-24 17:35:08 +00:00
def get_target_temperature ( self , time ) :
if time > self . get_duration ( ) :
return 0
2013-11-28 16:44:06 +00:00
2013-11-24 17:35:08 +00:00
prev_point = None
next_point = None
2013-11-28 16:44:06 +00:00
2013-11-24 17:35:08 +00:00
for i in range ( len ( self . data ) ) :
2013-11-24 17:54:29 +00:00
if time < self . data [ i ] [ 0 ] :
prev_point = self . data [ i - 1 ]
next_point = self . data [ i ]
2013-11-24 17:35:08 +00:00
break
2013-11-28 16:44:06 +00:00
2013-11-24 17:54:29 +00:00
incl = float ( next_point [ 1 ] - prev_point [ 1 ] ) / float ( next_point [ 0 ] - prev_point [ 0 ] )
2013-11-24 17:35:08 +00:00
temp = prev_point [ 1 ] + ( time - prev_point [ 0 ] ) * incl
return temp