refactored restart code

This commit is contained in:
jbruce12000 2022-06-20 21:05:09 -04:00
parent 4601d92eeb
commit 7f5b1396b6
2 changed files with 35 additions and 46 deletions

View File

@ -163,5 +163,3 @@ ignore_emergencies = False
automatic_restarts = True automatic_restarts = True
automatic_restart_window = 15 # max minutes since power outage automatic_restart_window = 15 # max minutes since power outage
automatic_restart_state_file = "/home/jason/repos/kiln-controller/state/kiln_controller_state.json" automatic_restart_state_file = "/home/jason/repos/kiln-controller/state/kiln_controller_state.json"

View File

@ -193,9 +193,6 @@ class Oven(threading.Thread):
self.target = 0 self.target = 0
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)
# for restarts, save the IDLE state to the state file
if config.automatic_restarts == True:
self.save_state()
def run_profile(self, profile, startat=0): def run_profile(self, profile, startat=0):
self.reset() self.reset()
@ -224,6 +221,7 @@ class Oven(threading.Thread):
def abort_run(self): def abort_run(self):
self.reset() self.reset()
self.save_automatic_restart_state()
def kiln_must_catch_up(self): def kiln_must_catch_up(self):
'''shift the whole schedule forward in time by one time_step '''shift the whole schedule forward in time by one time_step
@ -314,78 +312,72 @@ class Oven(threading.Thread):
if os.path.isfile(config.automatic_restart_state_file): if os.path.isfile(config.automatic_restart_state_file):
state_age = os.path.getmtime(config.automatic_restart_state_file) state_age = os.path.getmtime(config.automatic_restart_state_file)
now = time.time() now = time.time()
if((now - state_age)/60 <= config.automatic_restart_window): minutes = (now - state_age)/60
if(minutes <= config.automatic_restart_window):
return False return False
return True return True
def save_automatic_restart_state(self):
def automatic_restart(self): # only save state if the feature is enabled
'''takes one of two actions
if RUNNING, saves state every duty cycle
if IDLE, checks and then starts last known good profile where it died
'''
# check if automatic_restart setting is True
if not config.automatic_restarts == True: if not config.automatic_restarts == True:
return return False
self.save_state()
if self.state == "RUNNING": def should_i_automatic_restart(self):
# save state every duty cycle (2s by default) # only automatic restart if the feature is enabled
self.save_state() if not config.automatic_restarts == True:
return return False
# check if within window (use file timestamp and setting)
if self.state_file_is_old(): if self.state_file_is_old():
log.info("restart not possible. outside restart window") log.info("restart not possible. state file too old.")
return return False
# restart the last known profile where it died
self.restart()
def restart(self):
if os.path.isfile(config.automatic_restart_state_file): if os.path.isfile(config.automatic_restart_state_file):
with open(config.automatic_restart_state_file) as infile: d = json.load(infile) with open(config.automatic_restart_state_file) as infile: d = json.load(infile)
else: else:
log.info("restart not possible. no state file found.") log.info("restart not possible. no state file found.")
return return False
# check if last profile finished if d["state"] != "RUNNING":
#if d["totaltime"] - d["runtime"] > 60: # this log statement is too noisy.
if d["state"] == "RUNNING": #log.info("restart not possible. state = %s" % (d["state"]))
startat = d["runtime"]/60 return False
filename = "%s.json" % (d["profile"]) return True
profile_path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'storage','profiles',filename))
log.info("restarting profile = %s at minute = %d" % (profile_path,startat)) def automatic_restart(self):
with open(profile_path) as infile: with open(config.automatic_restart_state_file) as infile: d = json.load(infile)
profile_json = json.dumps(json.load(infile)) startat = d["runtime"]/60
profile = Profile(profile_json) filename = "%s.json" % (d["profile"])
self.run_profile(profile,startat=startat) profile_path = os.path.abspath(os.path.join(os.path.dirname( __file__ ), '..', 'storage','profiles',filename))
self.ovenwatcher.record(profile)
log.info("restarting profile = %s at minute = %d" % (profile_path,startat))
with open(profile_path) as infile:
profile_json = json.dumps(json.load(infile))
profile = Profile(profile_json)
self.run_profile(profile,startat=startat)
self.ovenwatcher.record(profile)
def set_ovenwatcher(self,watcher): def set_ovenwatcher(self,watcher):
log.info("ovenwatcher set in oven class")
self.ovenwatcher = watcher self.ovenwatcher = watcher
def run(self): def run(self):
while True: while True:
if self.state == "IDLE": if self.state == "IDLE":
self.automatic_restart() if self.should_i_automatic_restart() == True:
self.automatic_restart()
time.sleep(1) time.sleep(1)
continue continue
if self.state == "RUNNING": if self.state == "RUNNING":
self.save_automatic_restart_state()
self.kiln_must_catch_up() self.kiln_must_catch_up()
self.update_runtime() self.update_runtime()
self.update_target_temp() self.update_target_temp()
self.heat_then_cool() self.heat_then_cool()
self.reset_if_emergency() self.reset_if_emergency()
self.reset_if_schedule_ended() self.reset_if_schedule_ended()
self.automatic_restart()
class SimulatedOven(Oven): class SimulatedOven(Oven):
def __init__(self): def __init__(self):
self.reset()
self.board = BoardSimulated() self.board = BoardSimulated()
self.t_env = config.sim_t_env self.t_env = config.sim_t_env
self.c_heat = config.sim_c_heat self.c_heat = config.sim_c_heat
self.c_oven = config.sim_c_oven self.c_oven = config.sim_c_oven
@ -398,8 +390,7 @@ class SimulatedOven(Oven):
self.t = self.t_env # deg C temp of oven self.t = 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
# call parent init super().__init__()
Oven.__init__(self)
# start thread # start thread
self.start() self.start()