adding restart profile functionality
This commit is contained in:
parent
0e53f23083
commit
4db8e30515
22
config.py
22
config.py
@ -13,7 +13,7 @@ log_format = '%(asctime)s %(levelname)s %(name)s: %(message)s'
|
|||||||
|
|
||||||
### Server
|
### Server
|
||||||
listening_ip = "0.0.0.0"
|
listening_ip = "0.0.0.0"
|
||||||
listening_port = 8081
|
listening_port = 8082
|
||||||
|
|
||||||
### Cost Estimate
|
### Cost Estimate
|
||||||
kwh_rate = 0.1319 # Rate in currency_type to calculate cost to run job
|
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
|
# your specific kiln. Note that the integral pid_ki is
|
||||||
# inverted so that a smaller number means more integral action.
|
# inverted so that a smaller number means more integral action.
|
||||||
pid_kp = 25 # Proportional 25,200,200
|
pid_kp = 25 # Proportional 25,200,200
|
||||||
pid_ki = 20 # Integral
|
pid_ki = 10 # Integral
|
||||||
pid_kd = 200 # Derivative
|
pid_kd = 200 # Derivative
|
||||||
|
|
||||||
|
|
||||||
@ -82,10 +82,10 @@ stop_integral_windup = True
|
|||||||
# Simulation parameters
|
# Simulation parameters
|
||||||
simulate = True
|
simulate = True
|
||||||
sim_t_env = 60.0 # deg C
|
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_c_oven = 5000.0 # J/K heat capacity of oven
|
||||||
sim_p_heat = 5450.0 # W heating power 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_o_cool = 0.05 # K/W " with cooling
|
||||||
sim_R_ho_noair = 0.1 # K/W thermal resistance heat element -> oven
|
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
|
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
|
# or 100% off because the kiln is too hot. No integral builds up
|
||||||
# outside the window. The bigger you make the window, the more
|
# outside the window. The bigger you make the window, the more
|
||||||
# integral you will accumulate.
|
# integral you will accumulate.
|
||||||
pid_control_window = 10 #degrees
|
pid_control_window = 5 #degrees
|
||||||
|
|
||||||
# thermocouple offset
|
# thermocouple offset
|
||||||
# If you put your thermocouple in ice water and it reads 36F, you can
|
# 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
|
# - 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
|
# and some people just want to ignore all of that and just log the emergencies but do not quit
|
||||||
ignore_emergencies = False
|
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"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -42,6 +42,8 @@ else:
|
|||||||
log.info("this is a real kiln")
|
log.info("this is a real kiln")
|
||||||
oven = RealOven()
|
oven = RealOven()
|
||||||
ovenWatcher = OvenWatcher(oven)
|
ovenWatcher = OvenWatcher(oven)
|
||||||
|
# this ovenwatcher is used in the oven class for restarts
|
||||||
|
oven.set_ovenwatcher(ovenWatcher)
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def index():
|
def index():
|
||||||
|
|||||||
66
lib/oven.py
66
lib/oven.py
@ -5,6 +5,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import config
|
import config
|
||||||
|
import os
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -290,9 +291,72 @@ class Oven(threading.Thread):
|
|||||||
}
|
}
|
||||||
return state
|
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):
|
def run(self):
|
||||||
while True:
|
while True:
|
||||||
if self.state == "IDLE":
|
if self.state == "IDLE":
|
||||||
|
self.automatic_restart()
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
continue
|
continue
|
||||||
if self.state == "RUNNING":
|
if self.state == "RUNNING":
|
||||||
@ -302,7 +366,7 @@ class Oven(threading.Thread):
|
|||||||
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):
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user