ok, now just need to deal with exceptions

This commit is contained in:
jbruce 2022-11-01 10:50:51 -09:00
parent 5172d8c294
commit d6163a4c6e

View File

@ -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: