Seek is working with log, pytests added.

This commit is contained in:
James Kirikland Garner 2022-12-23 15:01:35 -08:00
parent 4c03cfa8a6
commit ee70ba1667
5 changed files with 131 additions and 4 deletions

1
Test/test-cases.json Normal file
View File

@ -0,0 +1 @@
{"data": [[0, 200], [3600, 200], [4200, 500], [10800, 500], [14400, 2250], [16400, 2000], [19400, 2250]], "type": "profile", "name": "test-fast"}

1
Test/test-fast.json Normal file
View File

@ -0,0 +1 @@
{"data": [[0, 200], [3600, 200], [10800, 2000], [14400, 2250], [16400, 2250], [19400, 700]], "type": "profile", "name": "test-fast"}

80
Test/test_Profile.py Normal file
View File

@ -0,0 +1,80 @@
from lib.oven import Profile
import os
import json
def get_profile(file = "test-fast.json"):
profile_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'Test', file))
print(profile_path)
with open(profile_path) as infile:
profile_json = json.dumps(json.load(infile))
profile = Profile(profile_json)
return profile
def test_get_target_temperature():
profile = get_profile()
temperature = profile.get_target_temperature(3000)
assert int(temperature) == 200
temperature = profile.get_target_temperature(6004)
assert temperature == 801.0
def test_find_time_from_temperature():
profile = get_profile()
time = profile.find_next_time_from_temperature(500)
assert time == 4800
time = profile.find_next_time_from_temperature(2004)
assert time == 10857.6
time = profile.find_next_time_from_temperature(1900)
assert time == 10400.0
def test_find_time_odd_profile():
profile = get_profile("test-cases.json")
time = profile.find_next_time_from_temperature(500)
assert time == 4200
time = profile.find_next_time_from_temperature(2023)
assert time == 16676.0
def test_find_x_given_y_on_line_from_two_points():
profile = get_profile()
y = 500
p1 = [3600, 200]
p2 = [10800, 2000]
time = profile.find_x_given_y_on_line_from_two_points(y, p1, p2)
assert time == 4800
y = 500
p1 = [3600, 200]
p2 = [10800, 200]
time = profile.find_x_given_y_on_line_from_two_points(y, p1, p2)
assert time == 0
y = 500
p1 = [3600, 600]
p2 = [10800, 600]
time = profile.find_x_given_y_on_line_from_two_points(y, p1, p2)
assert time == 0
y = 500
p1 = [3600, 500]
p2 = [10800, 500]
time = profile.find_x_given_y_on_line_from_two_points(y, p1, p2)
assert time == 0

View File

@ -75,6 +75,13 @@ max31856 = 0
# ThermocoupleType.S # ThermocoupleType.S
# ThermocoupleType.T # ThermocoupleType.T
########################################################################
#
# If your kiln is above the scheduled starting temperature when you click the Start button this
# feature will start the schedule at that temperature.
#
seek_start = True
######################################################################## ########################################################################
# #
# duty cycle of the entire system in seconds # duty cycle of the entire system in seconds
@ -204,7 +211,7 @@ ignore_tc_too_many_errors = False
# cleaned up (deleted) by the OS on boot. # cleaned up (deleted) by the OS on boot.
# The state file is written to disk every sensor_time_wait seconds (2s by default) # The state file is written to disk every sensor_time_wait seconds (2s by default)
# and is written in the same directory as config.py. # and is written in the same directory as config.py.
automatic_restarts = True automatic_restarts = False
automatic_restart_window = 15 # max minutes since power outage automatic_restart_window = 15 # max minutes since power outage
automatic_restart_state_file = os.path.abspath(os.path.join(os.path.dirname( __file__ ),'state.json')) automatic_restart_state_file = os.path.abspath(os.path.join(os.path.dirname( __file__ ),'state.json'))

View File

@ -103,7 +103,7 @@ class TempSensorSimulated(TempSensor):
'''Simulates a temperature sensor ''' '''Simulates a temperature sensor '''
def __init__(self): def __init__(self):
TempSensor.__init__(self) TempSensor.__init__(self)
self.simulated_temperature = 0 self.simulated_temperature = 255
def temperature(self): def temperature(self):
return self.simulated_temperature return self.simulated_temperature
@ -329,10 +329,26 @@ class Oven(threading.Thread):
self.heat = 0 self.heat = 0
self.pid = PID(ki=config.pid_ki, kd=config.pid_kd, kp=config.pid_kp) self.pid = PID(ki=config.pid_ki, kd=config.pid_kd, kp=config.pid_kp)
@staticmethod
def get_start_from_temperature(profile, temp):
target_temp = profile.get_target_temperature(0)
if temp > target_temp + 5:
startat = profile.find_next_time_from_temperature(temp)
log.info("seek_start is in effect")
else:
startat = 0
return startat
def run_profile(self, profile, startat=0): def run_profile(self, profile, startat=0):
runtime = startat * 60
if self.state == 'IDLE':
if config.seek_start:
temp = self.board.temp_sensor.temperature() # Defined in a subclass
runtime += self.get_start_from_temperature(profile, temp)
self.reset() self.reset()
self.startat = startat * 60 self.startat = startat * 60
self.runtime = self.startat self.runtime = runtime
self.start_time = datetime.datetime.now() - datetime.timedelta(seconds=self.startat) self.start_time = datetime.datetime.now() - datetime.timedelta(seconds=self.startat)
self.profile = profile self.profile = profile
self.totaltime = profile.get_duration() self.totaltime = profile.get_duration()
@ -507,7 +523,7 @@ class SimulatedOven(Oven):
self.R_ho = self.R_ho_noair self.R_ho = self.R_ho_noair
# set temps to the temp of the surrounding environment # set temps to the temp of the surrounding environment
self.t = self.t_env # deg C temp of oven self.t = 255 # self.t_env # deg C temp of oven
self.t_h = self.t_env #deg C temp of heating element self.t_h = self.t_env #deg C temp of heating element
super().__init__() super().__init__()
@ -643,6 +659,28 @@ class Profile():
def get_duration(self): def get_duration(self):
return max([t for (t, x) in self.data]) return max([t for (t, x) in self.data])
# x = (y-y1)(x2-x1)/(y2-y1) + x1
@staticmethod
def find_x_given_y_on_line_from_two_points(y, point1, point2):
if point1[0] > point2[0]: return 0 # time2 before time1 makes no sense in kiln segment
if point1[1] >= point2[1]: return 0 # Zero will crach. Negative temeporature slope, we don't want to seek a time.
x = (y - point1[1]) * (point2[0] -point1[0] ) / (point2[1] - point1[1]) + point1[0]
return x
def find_next_time_from_temperature(self, temperature):
time = 0 # The seek function will not do anything if this returns zero, no useful intersection was found
for index, point2 in enumerate(self.data):
if point2[1] >= temperature:
if index > 0: # Zero here would be before the first segment
if self.data[index - 1][1] <= temperature: # We have an intersection
time = self.find_x_given_y_on_line_from_two_points(temperature, self.data[index - 1], point2)
if time == 0:
if self.data[index - 1][1] == point2[1]: # It's a flat segment that matches the temperature
time = self.data[index - 1][0]
break
return time
def get_surrounding_points(self, time): def get_surrounding_points(self, time):
if time > self.get_duration(): if time > self.get_duration():
return (None, None) return (None, None)