adding restart profile functionality

kiln-profiles
jbruce12000 2022-06-19 16:20:44 -04:00
rodzic 0e53f23083
commit 4db8e30515
3 zmienionych plików z 84 dodań i 6 usunięć

Wyświetl plik

@ -13,7 +13,7 @@ log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s'
### Server
listening_ip = "0.0.0.0"
listening_port = 8081
listening_port = 8082
### Cost Estimate
kwh_rate = 0.1319 # Rate in currency_type to calculate cost to run job
@ -65,7 +65,7 @@ sensor_time_wait = 2
# your specific kiln. Note that the integral pid_ki is
# inverted so that a smaller number means more integral action.
pid_kp = 25 # Proportional 25,200,200
pid_ki = 20 # Integral
pid_ki = 10 # Integral
pid_kd = 200 # Derivative
@ -82,10 +82,10 @@ stop_integral_windup = True
# Simulation parameters
simulate = True
sim_t_env = 60.0 # deg C
sim_c_heat = 100.0 # J/K heat capacity of heat element
sim_c_heat = 500.0 # J/K heat capacity of heat element
sim_c_oven = 5000.0 # J/K heat capacity of oven
sim_p_heat = 5450.0 # W heating power of oven
sim_R_o_nocool = 0.1 # K/W thermal resistance oven -> environment
sim_R_o_nocool = 0.5 # K/W thermal resistance oven -> environment
sim_R_o_cool = 0.05 # K/W " with cooling
sim_R_ho_noair = 0.1 # K/W thermal resistance heat element -> oven
sim_R_ho_air = 0.05 # K/W " with internal air circulation
@ -121,7 +121,7 @@ kiln_must_catch_up = True
# or 100% off because the kiln is too hot. No integral builds up
# outside the window. The bigger you make the window, the more
# integral you will accumulate.
pid_control_window = 10 #degrees
pid_control_window = 5 #degrees
# thermocouple offset
# If you put your thermocouple in ice water and it reads 36F, you can
@ -151,3 +151,15 @@ ac_freq_50hz = False
# - too many errors in a short period from thermocouple
# and some people just want to ignore all of that and just log the emergencies but do not quit
ignore_emergencies = False
########################################################################
# automatic restarts - if you have a power brown-out and the raspberry pi
# reboots, this restarts your kiln where it left off in the firing profile.
# This only happens if power comes back before automatic_restart_window
# is exceeded (in minutes). The kiln-controller.py process must start
# automatically on boot-up for this to work.
automatic_restarts = True
automatic_restart_window = 15 # max minutes since power outage
automatic_restart_state_file = "/tmp/kiln_controller_state.json"

Wyświetl plik

@ -42,6 +42,8 @@ else:
log.info("this is a real kiln")
oven = RealOven()
ovenWatcher = OvenWatcher(oven)
# this ovenwatcher is used in the oven class for restarts
oven.set_ovenwatcher(ovenWatcher)
@app.route('/')
def index():

Wyświetl plik

@ -5,6 +5,7 @@ import datetime
import logging
import json
import config
import os
log = logging.getLogger(__name__)
@ -290,9 +291,72 @@ class Oven(threading.Thread):
}
return state
def save_state(self):
with open(config.automatic_restart_state_file, 'w', encoding='utf-8') as f:
json.dump(self.get_state(), f, ensure_ascii=False, indent=4)
def state_file_is_old(self):
'''returns True is state files is older than 15 mins default
False if younger
True if state file cannot be opened or does not exist
'''
if os.path.isfile(config.automatic_restart_state_file):
state_age = os.path.getmtime(config.automatic_restart_state_file)
now = time.time()
if((now - state_age)/60 <= config.automatic_restart_window):
return False
return True
def automatic_restart(self):
'''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:
return
if self.state == "RUNNING":
# save state every duty cycle (2s by default)
self.save_state()
return
# check if within window (use file timestamp and setting)
if self.state_file_is_old():
log.info("restart not possible. outside restart window")
return
# restart the last known profile where it died
self.restart()
def restart(self):
if os.path.isfile(config.automatic_restart_state_file):
with open(config.automatic_restart_state_file) as infile: d = json.load(infile)
else:
log.info("restart not possible. no state file found.")
return
# check if last profile finished
if d["totaltime"] - d["runtime"] > 60:
startat = d["runtime"]/60
filename = "%s.json" % (d["profile"])
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))
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):
self.ovenwatcher = watcher
def run(self):
while True:
if self.state == "IDLE":
self.automatic_restart()
time.sleep(1)
continue
if self.state == "RUNNING":
@ -302,7 +366,7 @@ class Oven(threading.Thread):
self.heat_then_cool()
self.reset_if_emergency()
self.reset_if_schedule_ended()
self.automatic_restart()
class SimulatedOven(Oven):