ok, now just need to deal with exceptions
This commit is contained in:
parent
5172d8c294
commit
d6163a4c6e
159
lib/oven.py
159
lib/oven.py
@ -79,9 +79,8 @@ class TempSensor(threading.Thread):
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
threading.Thread.__init__(self)
|
threading.Thread.__init__(self)
|
||||||
self.daemon = True
|
self.daemon = True
|
||||||
self.bad_percent = 0
|
|
||||||
self.time_step = config.sensor_time_wait
|
self.time_step = config.sensor_time_wait
|
||||||
self.noConnection = self.shortToGround = self.shortToVCC = self.unknownError = False
|
self.status = ThermocoupleTracker()
|
||||||
|
|
||||||
class TempSensorSimulated(TempSensor):
|
class TempSensorSimulated(TempSensor):
|
||||||
'''not much here, just need to be able to set the temperature'''
|
'''not much here, just need to be able to set the temperature'''
|
||||||
@ -96,18 +95,14 @@ class TempSensorReal(TempSensor):
|
|||||||
during the time_step'''
|
during the time_step'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
TempSensor.__init__(self)
|
TempSensor.__init__(self)
|
||||||
self.temps = []
|
|
||||||
self.sleeptime = self.time_step / float(config.temperature_average_samples)
|
self.sleeptime = self.time_step / float(config.temperature_average_samples)
|
||||||
self.bad_count = 0
|
self.temptracker = TempTracker()
|
||||||
self.ok_count = 0
|
|
||||||
self.bad_stamp = 0
|
|
||||||
|
|
||||||
self.spi = busio.SPI(config.spi_sclk, config.spi_mosi, config.spi_miso)
|
self.spi = busio.SPI(config.spi_sclk, config.spi_mosi, config.spi_miso)
|
||||||
self.cs = digitalio.DigitalInOut(config.spi_cs)
|
self.cs = digitalio.DigitalInOut(config.spi_cs)
|
||||||
|
|
||||||
def get_temperature(self):
|
def get_temperature(self):
|
||||||
'''must be provided by subclass'''
|
'''read temp from tc and convert if needed'''
|
||||||
temp = self.raw_temp()
|
temp = self.raw_temp() # raw_temp provided by subclasses
|
||||||
if config.temp_scale.lower() == "f":
|
if config.temp_scale.lower() == "f":
|
||||||
temp = (temp*9/5)+32
|
temp = (temp*9/5)+32
|
||||||
return temp
|
return temp
|
||||||
@ -130,8 +125,6 @@ class TempSensorReal(TempSensor):
|
|||||||
# self.bad_count = self.bad_count + 1
|
# self.bad_count = self.bad_count + 1
|
||||||
# if rte.args and rte.args[0] == "faulty reading":
|
# if rte.args and rte.args[0] == "faulty reading":
|
||||||
# self.bad_count = self.bad_count + 1
|
# self.bad_count = self.bad_count + 1
|
||||||
# if rte.args and rte.args[0] == "faulty reading":
|
|
||||||
# self.bad_count = self.bad_count + 1
|
|
||||||
#
|
#
|
||||||
# log.error("Problem reading temp %s" % (rte.args[0]))
|
# log.error("Problem reading temp %s" % (rte.args[0]))
|
||||||
# # fix still need to include max-31856 errors by calling fault
|
# # fix still need to include max-31856 errors by calling fault
|
||||||
@ -140,54 +133,82 @@ class TempSensorReal(TempSensor):
|
|||||||
# return None
|
# return None
|
||||||
|
|
||||||
def temperature(self):
|
def temperature(self):
|
||||||
if (self.temps):
|
'''average temp over a duty cycle'''
|
||||||
return self.get_avg_temp(self.temps)
|
return self.temptracker.get_avg_temp()
|
||||||
return 0
|
|
||||||
|
|
||||||
def add_temp(self,temp):
|
|
||||||
if temp:
|
|
||||||
self.temps.append(temp)
|
|
||||||
# fix this should happen someplace else
|
|
||||||
self.ok_count += 1
|
|
||||||
while(len(self.temps) > config.temperature_average_samples):
|
|
||||||
del self.temps[0]
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
'''use a moving average of config.temperature_average_samples across the time_step'''
|
|
||||||
while True:
|
while True:
|
||||||
# reset error counter if time is up
|
# not at all sure this try/except should be here
|
||||||
if (time.time() - self.bad_stamp) > (self.time_step * 2):
|
# might be better getting the temp
|
||||||
if self.bad_count + self.ok_count:
|
try:
|
||||||
self.bad_percent = (self.bad_count / (self.bad_count + self.ok_count)) * 100
|
temp = self.get_temperature()
|
||||||
else:
|
self.status.good()
|
||||||
self.bad_percent = 0
|
self.temptracker.add(temp)
|
||||||
self.bad_count = 0
|
except RuntimeError as rte:
|
||||||
self.ok_count = 0
|
self.status.bad()
|
||||||
self.bad_stamp = time.time()
|
log.error("Problem reading temp %s" % (rte.args[0]))
|
||||||
|
|
||||||
temp = self.get_temperature()
|
|
||||||
#log.info("temp = %0.2f" % temp)
|
|
||||||
self.add_temp(temp)
|
|
||||||
time.sleep(self.sleeptime)
|
time.sleep(self.sleeptime)
|
||||||
|
|
||||||
def get_avg_temp(self, temps, chop=25):
|
class TempTracker(object):
|
||||||
|
'''creates a sliding window of temperatures
|
||||||
|
'''
|
||||||
|
def __init__(self):
|
||||||
|
self.size = config.temperature_average_samples
|
||||||
|
self.temps = [0 for i in range(self.size)]
|
||||||
|
|
||||||
|
def add(self,temp):
|
||||||
|
self.temps.append(temp)
|
||||||
|
while(len(self.temps) > self.size):
|
||||||
|
del self.temps[0]
|
||||||
|
|
||||||
|
def get_avg_temp(self, chop=25):
|
||||||
'''
|
'''
|
||||||
strip off chop percent from the beginning and end of the sorted temps
|
strip off chop percent from the beginning and end of the sorted temps
|
||||||
then return the average of what is left
|
then return the average of what is left
|
||||||
'''
|
'''
|
||||||
chop = chop / 100
|
chop = chop / 100
|
||||||
temps = sorted(temps)
|
temps = sorted(self.temps)
|
||||||
total = len(temps)
|
total = len(temps)
|
||||||
items = int(total*chop)
|
items = int(total*chop)
|
||||||
temps = temps[items:total-items]
|
temps = temps[items:total-items]
|
||||||
return sum(temps) / len(temps)
|
return sum(temps) / len(temps)
|
||||||
|
|
||||||
|
class ThermocoupleTracker(object):
|
||||||
|
'''Keeps sliding window to track successful/failed calls to get temp
|
||||||
|
over the last two duty cycles.
|
||||||
|
'''
|
||||||
|
def __init__(self):
|
||||||
|
self.size = config.temperature_average_samples * 2
|
||||||
|
self.status = [True for i in range(self.size)]
|
||||||
|
self.limit = 30
|
||||||
|
|
||||||
|
def good(self):
|
||||||
|
'''True is good!'''
|
||||||
|
self.status.append(True)
|
||||||
|
del self.status[0]
|
||||||
|
|
||||||
|
def bad(self):
|
||||||
|
'''False is bad!'''
|
||||||
|
self.status.append(False)
|
||||||
|
del self.status[0]
|
||||||
|
|
||||||
|
def error_percent(self):
|
||||||
|
errors = sum(i == False for i in self.status)
|
||||||
|
return (errors/self.size)*100
|
||||||
|
|
||||||
|
def over_error_limit(self):
|
||||||
|
if self.error_percent() > self.limit:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
class Max31855(TempSensorReal):
|
class Max31855(TempSensorReal):
|
||||||
'''each subclass expected to handle errors and get temperature'''
|
'''each subclass expected to handle errors and get temperature'''
|
||||||
|
# FIX I need unified errors from these classes since the underlying
|
||||||
|
# implementations are different
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
TempSensorReal.__init__(self)
|
TempSensorReal.__init__(self)
|
||||||
log.info("init MAX31855")
|
log.info("thermocouple MAX31855")
|
||||||
import adafruit_max31855
|
import adafruit_max31855
|
||||||
self.thermocouple = adafruit_max31855.MAX31855(self.spi, self.cs)
|
self.thermocouple = adafruit_max31855.MAX31855(self.spi, self.cs)
|
||||||
|
|
||||||
@ -198,7 +219,7 @@ class Max31856(TempSensorReal):
|
|||||||
'''each subclass expected to handle errors and get temperature'''
|
'''each subclass expected to handle errors and get temperature'''
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
TempSensorReal.__init__(self)
|
TempSensorReal.__init__(self)
|
||||||
log.info("init MAX31856")
|
log.info("thermocouple MAX31856")
|
||||||
import adafruit_max31856
|
import adafruit_max31856
|
||||||
adafruit_max31856.ThermocoupleType(config.thermocouple_type)
|
adafruit_max31856.ThermocoupleType(config.thermocouple_type)
|
||||||
self.thermocouple = adafruit_max31856.MAX31856(spi, cs)
|
self.thermocouple = adafruit_max31856.MAX31856(spi, cs)
|
||||||
@ -234,18 +255,19 @@ class Oven(threading.Thread):
|
|||||||
def run_profile(self, profile, startat=0):
|
def run_profile(self, profile, startat=0):
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
if self.board.temp_sensor.noConnection:
|
# FIX, these need to be moved
|
||||||
log.info("Refusing to start profile - thermocouple not connected")
|
#if self.board.temp_sensor.noConnection:
|
||||||
return
|
# log.info("Refusing to start profile - thermocouple not connected")
|
||||||
if self.board.temp_sensor.shortToGround:
|
# return
|
||||||
log.info("Refusing to start profile - thermocouple short to ground")
|
#if self.board.temp_sensor.shortToGround:
|
||||||
return
|
# log.info("Refusing to start profile - thermocouple short to ground")
|
||||||
if self.board.temp_sensor.shortToVCC:
|
# return
|
||||||
log.info("Refusing to start profile - thermocouple short to VCC")
|
#if self.board.temp_sensor.shortToVCC:
|
||||||
return
|
# log.info("Refusing to start profile - thermocouple short to VCC")
|
||||||
if self.board.temp_sensor.unknownError:
|
# return
|
||||||
log.info("Refusing to start profile - thermocouple unknown error")
|
#if self.board.temp_sensor.unknownError:
|
||||||
return
|
# log.info("Refusing to start profile - thermocouple unknown error")
|
||||||
|
# return
|
||||||
|
|
||||||
self.startat = startat * 60
|
self.startat = startat * 60
|
||||||
self.runtime = self.startat
|
self.runtime = self.startat
|
||||||
@ -288,26 +310,27 @@ class Oven(threading.Thread):
|
|||||||
|
|
||||||
def reset_if_emergency(self):
|
def reset_if_emergency(self):
|
||||||
'''reset if the temperature is way TOO HOT, or other critical errors detected'''
|
'''reset if the temperature is way TOO HOT, or other critical errors detected'''
|
||||||
if (self.board.temp_sensor.temperature() + config.thermocouple_offset >=
|
# FIX - need to fix this whole thing...
|
||||||
config.emergency_shutoff_temp):
|
#if (self.board.temp_sensor.temperature() + config.thermocouple_offset >=
|
||||||
log.info("emergency!!! temperature too high")
|
# config.emergency_shutoff_temp):
|
||||||
if config.ignore_temp_too_high == False:
|
# log.info("emergency!!! temperature too high")
|
||||||
self.abort_run()
|
# if config.ignore_temp_too_high == False:
|
||||||
|
# self.abort_run()
|
||||||
|
|
||||||
if self.board.temp_sensor.noConnection:
|
#if self.board.temp_sensor.noConnection:
|
||||||
log.info("emergency!!! lost connection to thermocouple")
|
# log.info("emergency!!! lost connection to thermocouple")
|
||||||
if config.ignore_lost_connection_tc == False:
|
# if config.ignore_lost_connection_tc == False:
|
||||||
self.abort_run()
|
# self.abort_run()
|
||||||
|
|
||||||
if self.board.temp_sensor.unknownError:
|
#if self.board.temp_sensor.unknownError:
|
||||||
log.info("emergency!!! unknown thermocouple error")
|
# log.info("emergency!!! unknown thermocouple error")
|
||||||
if config.ignore_unknown_tc_error == False:
|
# if config.ignore_unknown_tc_error == False:
|
||||||
self.abort_run()
|
# self.abort_run()
|
||||||
|
|
||||||
if self.board.temp_sensor.bad_percent > 30:
|
#if self.board.temp_sensor.status.over_error_limit():
|
||||||
log.info("emergency!!! too many errors in a short period")
|
# log.info("emergency!!! too many errors in a short period")
|
||||||
if config.ignore_too_many_tc_errors == False:
|
# if config.ignore_too_many_tc_errors == False:
|
||||||
self.abort_run()
|
# self.abort_run()
|
||||||
|
|
||||||
def reset_if_schedule_ended(self):
|
def reset_if_schedule_ended(self):
|
||||||
if self.runtime > self.totaltime:
|
if self.runtime > self.totaltime:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user