pep8 style fixes
This commit is contained in:
parent
3a145c29bc
commit
704efca972
116
oven.py
116
oven.py
@ -1,4 +1,10 @@
|
||||
import threading,time,random,datetime,logging,json
|
||||
import threading
|
||||
import time
|
||||
import random
|
||||
import datetime
|
||||
import logging
|
||||
import json
|
||||
|
||||
import config
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
@ -21,25 +27,29 @@ try:
|
||||
|
||||
gpio_available = True
|
||||
except ImportError:
|
||||
log.warning("Could not initialize GPIOs, oven operation will only be simulated!")
|
||||
msg = "Could not initialize GPIOs, oven operation will only be simulated!"
|
||||
log.warning(msg)
|
||||
gpio_available = False
|
||||
|
||||
class Oven (threading.Thread):
|
||||
STATE_IDLE = "IDLE"
|
||||
STATE_RUNNING = "RUNNING"
|
||||
|
||||
def __init__(self,simulate = False,time_step=0.5):
|
||||
class Oven (threading.Thread):
|
||||
STATE_IDLE = "IDLE"
|
||||
STATE_RUNNING = "RUNNING"
|
||||
|
||||
def __init__(self, simulate=False, time_step=0.5):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.simulate = simulate
|
||||
self.time_step = time_step
|
||||
self.reset()
|
||||
if simulate:
|
||||
self.temp_sensor = TempSensorSimulate(self,0.5,self.time_step)
|
||||
self.temp_sensor = TempSensorSimulate(self, 0.5, self.time_step)
|
||||
if sensor_available:
|
||||
self.temp_sensor = TempSensorReal(self.time_step)
|
||||
else:
|
||||
self.temp_sensor = TempSensorSimulate(self,self.time_step,self.time_step)
|
||||
self.temp_sensor = TempSensorSimulate(self,
|
||||
self.time_step,
|
||||
self.time_step)
|
||||
self.temp_sensor.start()
|
||||
self.start()
|
||||
|
||||
@ -54,10 +64,10 @@ class Oven (threading.Thread):
|
||||
self.set_heat(False)
|
||||
self.set_cool(False)
|
||||
self.set_air(False)
|
||||
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)
|
||||
|
||||
def run_profile(self, profile):
|
||||
log.info("Running profile %s"%profile.name)
|
||||
log.info("Running profile %s" % profile.name)
|
||||
self.profile = profile
|
||||
self.totaltime = profile.get_duration()
|
||||
self.state = Oven.STATE_RUNNING
|
||||
@ -75,12 +85,13 @@ class Oven (threading.Thread):
|
||||
if self.simulate:
|
||||
self.runtime += 0.5
|
||||
else:
|
||||
self.runtime = (datetime.datetime.now() - self.start_time).total_seconds()
|
||||
log.info("running at %.1f deg C (Target: %.1f) , heat %.2f, cool %.2f, air %.2f, door %s (%.1fs/%.0f)"%(self.temp_sensor.temperature,self.target,self.heat,self.cool,self.air,self.door,self.runtime,self.totaltime))
|
||||
runtime_delta = datetime.datetime.now() - self.start_time
|
||||
self.runtime = runtime_delta.total_seconds()
|
||||
log.info("running at %.1f deg C (Target: %.1f) , heat %.2f, cool %.2f, air %.2f, door %s (%.1fs/%.0f)" % (self.temp_sensor.temperature, self.target, self.heat, self.cool, self.air, self.door, self.runtime, self.totaltime))
|
||||
self.target = self.profile.get_target_temperature(self.runtime)
|
||||
pid = self.pid.compute(self.target, self.temp_sensor.temperature)
|
||||
|
||||
log.info("pid: %.3f"%pid)
|
||||
log.info("pid: %.3f" % pid)
|
||||
|
||||
self.set_cool(pid <= -1)
|
||||
self.set_heat(pid > 0)
|
||||
@ -92,18 +103,17 @@ class Oven (threading.Thread):
|
||||
# self.set_heat(False)
|
||||
# self.set_cool(self.temp_sensor.temperature > self.target)
|
||||
|
||||
if self.temp_sensor.temperature>200:
|
||||
if self.temp_sensor.temperature > 200:
|
||||
self.set_air(False)
|
||||
elif self.temp_sensor.temperature<180:
|
||||
elif self.temp_sensor.temperature < 180:
|
||||
self.set_air(True)
|
||||
|
||||
if self.runtime >= self.totaltime:
|
||||
self.reset()
|
||||
|
||||
time.sleep(self.time_step)
|
||||
|
||||
|
||||
def set_heat(self,value):
|
||||
def set_heat(self, value):
|
||||
if value:
|
||||
self.heat = 1.0
|
||||
if gpio_available:
|
||||
@ -113,7 +123,7 @@ class Oven (threading.Thread):
|
||||
if gpio_available:
|
||||
GPIO.output(config.gpio_heat, GPIO.HIGH)
|
||||
|
||||
def set_cool(self,value):
|
||||
def set_cool(self, value):
|
||||
if value:
|
||||
self.cool = 1.0
|
||||
if gpio_available:
|
||||
@ -123,7 +133,7 @@ class Oven (threading.Thread):
|
||||
if gpio_available:
|
||||
GPIO.output(config.gpio_cool, GPIO.HIGH)
|
||||
|
||||
def set_air(self,value):
|
||||
def set_air(self, value):
|
||||
if value:
|
||||
self.air = 1.0
|
||||
if gpio_available:
|
||||
@ -141,7 +151,7 @@ class Oven (threading.Thread):
|
||||
'state': self.state,
|
||||
'heat': self.heat,
|
||||
'cool': self.cool,
|
||||
'air' : self.air,
|
||||
'air': self.air,
|
||||
'totaltime': self.totaltime,
|
||||
'door': self.door
|
||||
}
|
||||
@ -155,29 +165,30 @@ class Oven (threading.Thread):
|
||||
|
||||
|
||||
class TempSensor(threading.Thread):
|
||||
def __init__(self,time_step):
|
||||
def __init__(self, time_step):
|
||||
threading.Thread.__init__(self)
|
||||
self.daemon = True
|
||||
self.temperature = 0
|
||||
self.time_step = time_step
|
||||
|
||||
|
||||
|
||||
class TempSensorReal(TempSensor):
|
||||
def __init__(self,time_step):
|
||||
TempSensor.__init__(self,time_step)
|
||||
self.thermocouple = MAX31855(config.gpio_sensor_cs,
|
||||
config.gpio_sensor_clock,
|
||||
config.gpio_sensor_data,
|
||||
"c"
|
||||
)
|
||||
def __init__(self, time_step):
|
||||
TempSensor.__init__(self, time_step)
|
||||
self.thermocouple = MAX31855(config.gpio_sensor_cs,
|
||||
config.gpio_sensor_clock,
|
||||
config.gpio_sensor_data,
|
||||
"c")
|
||||
|
||||
def run(self):
|
||||
while True:
|
||||
self.temperature = self.thermocouple.get()
|
||||
time.sleep(self.time_step)
|
||||
|
||||
|
||||
class TempSensorSimulate(TempSensor):
|
||||
def __init__(self,oven,time_step,sleep_time):
|
||||
TempSensor.__init__(self,time_step)
|
||||
def __init__(self, oven, time_step, sleep_time):
|
||||
TempSensor.__init__(self, time_step)
|
||||
self.oven = oven
|
||||
self.sleep_time = sleep_time
|
||||
|
||||
@ -189,10 +200,10 @@ class TempSensorSimulate(TempSensor):
|
||||
R_o_nocool = config.sim_R_o_nocool
|
||||
R_o_cool = config.sim_R_o_cool
|
||||
R_ho_noair = config.sim_R_ho_noair
|
||||
R_ho_air = config.sim_R_ho_air
|
||||
R_ho_air = config.sim_R_ho_air
|
||||
|
||||
t = t_env #deg C temp in oven
|
||||
t_h = t #deg C temp of heat element
|
||||
t = t_env # deg C temp in oven
|
||||
t_h = t # deg C temp of heat element
|
||||
while True:
|
||||
#heating energy
|
||||
Q_h = p_heat * self.time_step * self.oven.heat
|
||||
@ -209,9 +220,8 @@ class TempSensorSimulate(TempSensor):
|
||||
p_ho = (t_h - t) / R_ho
|
||||
|
||||
#temperature change of oven and heat el
|
||||
t += p_ho *self.time_step / c_oven
|
||||
t_h -= p_ho *self.time_step / c_heat
|
||||
|
||||
t += p_ho * self.time_step / c_oven
|
||||
t_h -= p_ho * self.time_step / c_heat
|
||||
|
||||
#energy flux oven -> env
|
||||
if self.oven.cool:
|
||||
@ -220,24 +230,25 @@ class TempSensorSimulate(TempSensor):
|
||||
p_env = (t - t_env) / R_o_nocool
|
||||
|
||||
#temperature change of oven by cooling to env
|
||||
t -= p_env *self.time_step / c_oven
|
||||
log.debug("energy sim: -> %dW heater: %.0f -> %dW oven: %.0f -> %dW env"%(int(p_heat * self.oven.heat),t_h,int(p_ho),t,int(p_env)))
|
||||
t -= p_env * self.time_step / c_oven
|
||||
log.debug("energy sim: -> %dW heater: %.0f -> %dW oven: %.0f -> %dW env" % (int(p_heat * self.oven.heat), t_h, int(p_ho), t, int(p_env)))
|
||||
self.temperature = t
|
||||
|
||||
time.sleep(self.sleep_time)
|
||||
|
||||
|
||||
class Profile():
|
||||
def __init__(self,json_data):
|
||||
def __init__(self, json_data):
|
||||
obj = json.loads(json_data)
|
||||
self.name = obj["name"]
|
||||
self.data = sorted(obj["data"])
|
||||
|
||||
def get_duration(self):
|
||||
return max([t for (t,x) in self.data])
|
||||
return max([t for (t, x) in self.data])
|
||||
|
||||
def get_surrounding_points(self,time):
|
||||
def get_surrounding_points(self, time):
|
||||
if time > self.get_duration():
|
||||
return (None,None)
|
||||
return (None, None)
|
||||
|
||||
prev_point = None
|
||||
next_point = None
|
||||
@ -248,27 +259,28 @@ class Profile():
|
||||
next_point = self.data[i]
|
||||
break
|
||||
|
||||
return (prev_point,next_point)
|
||||
return (prev_point, next_point)
|
||||
|
||||
def is_rising(self,time):
|
||||
(prev_point,next_point) = self.get_surrounding_points(time)
|
||||
def is_rising(self, time):
|
||||
(prev_point, next_point) = self.get_surrounding_points(time)
|
||||
if prev_point and next_point:
|
||||
return prev_point[1] < next_point[1]
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_target_temperature(self,time):
|
||||
def get_target_temperature(self, time):
|
||||
if time > self.get_duration():
|
||||
return 0
|
||||
|
||||
(prev_point,next_point) = self.get_surrounding_points(time)
|
||||
(prev_point, next_point) = self.get_surrounding_points(time)
|
||||
|
||||
incl = float(next_point[1] - prev_point[1]) / float(next_point[0] - prev_point[0])
|
||||
temp = prev_point[1] + (time - prev_point[0]) * incl
|
||||
return temp
|
||||
|
||||
|
||||
class PID():
|
||||
def __init__(self,ki=1,kp=1,kd=1):
|
||||
def __init__(self, ki=1, kp=1, kd=1):
|
||||
self.ki = ki
|
||||
self.kp = kp
|
||||
self.kd = kd
|
||||
@ -276,17 +288,17 @@ class PID():
|
||||
self.iterm = 0
|
||||
self.lastErr = 0
|
||||
|
||||
def compute(self,setpoint,ispoint):
|
||||
def compute(self, setpoint, ispoint):
|
||||
now = datetime.datetime.now()
|
||||
timeDelta = (now - self.lastNow).total_seconds()
|
||||
|
||||
error = float(setpoint - ispoint)
|
||||
self.iterm += (error * timeDelta * self.ki)
|
||||
self.iterm=sorted([-1,self.iterm,1])[1]
|
||||
self.iterm = sorted([-1, self.iterm, 1])[1]
|
||||
dErr = (error - self.lastErr) / timeDelta
|
||||
|
||||
output = self.kp * error + self.iterm + self.kd * dErr
|
||||
output = sorted([-1,output,1])[1]
|
||||
output = sorted([-1, output, 1])[1]
|
||||
self.lastErr = error
|
||||
self.lastNow = now
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import os,logging,json
|
||||
import os
|
||||
import logging
|
||||
import json
|
||||
|
||||
import bottle
|
||||
from gevent.pywsgi import WSGIServer
|
||||
@ -11,7 +13,7 @@ except:
|
||||
print "Copy config.py.EXAMPLE to config.py and adapt it for your setup."
|
||||
exit(1)
|
||||
|
||||
logging.basicConfig(level = config.log_level, format = config.log_format)
|
||||
logging.basicConfig(level=config.log_level, format=config.log_format)
|
||||
log = logging.getLogger("picoreflowd")
|
||||
log.info("Starting picoreflowd")
|
||||
|
||||
@ -22,22 +24,29 @@ app = bottle.Bottle()
|
||||
oven = Oven()
|
||||
ovenWatcher = OvenWatcher(oven)
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
profile_path = os.path.join(script_dir, "storage", "profiles")
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return bottle.redirect('/picoreflow/index.html')
|
||||
|
||||
|
||||
@app.route('/picoreflow/:filename#.*#')
|
||||
def send_static(filename):
|
||||
log.debug("serving %s"%filename)
|
||||
log.debug("serving %s" % filename)
|
||||
return bottle.static_file(filename, root='./public/')
|
||||
|
||||
|
||||
def get_websocket_from_request():
|
||||
env = bottle.request.environ;
|
||||
env = bottle.request.environ
|
||||
wsock = env.get('wsgi.websocket')
|
||||
if not wsock:
|
||||
abort(400, 'Expected WebSocket request.')
|
||||
return wsock
|
||||
|
||||
|
||||
@app.route('/control')
|
||||
def handle_control():
|
||||
wsock = get_websocket_from_request()
|
||||
@ -45,7 +54,7 @@ def handle_control():
|
||||
while True:
|
||||
try:
|
||||
message = wsock.receive()
|
||||
log.info("Received (control): %s"% message)
|
||||
log.info("Received (control): %s" % message)
|
||||
msgdict = json.loads(message)
|
||||
if msgdict.get("cmd") == "RUN":
|
||||
log.info("RUN command received")
|
||||
@ -61,7 +70,7 @@ def handle_control():
|
||||
if profile_obj:
|
||||
profile_json = json.dumps(profile_obj)
|
||||
profile = Profile(profile_json)
|
||||
simulated_oven = Oven(simulate=True,time_step=0.05)
|
||||
simulated_oven = Oven(simulate=True, time_step=0.05)
|
||||
simulation_watcher = OvenWatcher(simulated_oven)
|
||||
simulation_watcher.add_observer(wsock)
|
||||
#simulated_oven.run_profile(profile)
|
||||
@ -73,6 +82,7 @@ def handle_control():
|
||||
break
|
||||
log.info("websocket (control) closed")
|
||||
|
||||
|
||||
@app.route('/storage')
|
||||
def handle_storage():
|
||||
wsock = get_websocket_from_request()
|
||||
@ -82,7 +92,7 @@ def handle_storage():
|
||||
message = wsock.receive()
|
||||
if not message:
|
||||
break
|
||||
log.debug("websocket (storage) received: %s"%message)
|
||||
log.debug("websocket (storage) received: %s" % message)
|
||||
|
||||
try:
|
||||
msgdict = json.loads(message)
|
||||
@ -95,14 +105,14 @@ def handle_storage():
|
||||
elif msgdict.get("cmd") == "PUT":
|
||||
log.info("PUT command received")
|
||||
profile_obj = msgdict.get('profile')
|
||||
force = msgdict.get('force',False)
|
||||
force = msgdict.get('force', False)
|
||||
if profile_obj:
|
||||
#del msgdict["cmd"]
|
||||
if save_profile(profile_obj,force):
|
||||
msgdict["resp"]="OK"
|
||||
if save_profile(profile_obj, force):
|
||||
msgdict["resp"] = "OK"
|
||||
else:
|
||||
msgdict["resp"]="FAIL"
|
||||
log.debug("websocket (storage) sent: %s"%message)
|
||||
msgdict["resp"] = "FAIL"
|
||||
log.debug("websocket (storage) sent: %s" % message)
|
||||
|
||||
wsock.send(json.dumps(msgdict))
|
||||
wsock.send(get_profiles())
|
||||
@ -110,6 +120,7 @@ def handle_storage():
|
||||
break
|
||||
log.info("websocket (storage) closed")
|
||||
|
||||
|
||||
@app.route('/status')
|
||||
def handle_status():
|
||||
wsock = get_websocket_from_request()
|
||||
@ -123,41 +134,42 @@ def handle_status():
|
||||
break
|
||||
log.info("websocket (status) closed")
|
||||
|
||||
script_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
profile_path = os.path.join(script_dir,"storage","profiles")
|
||||
|
||||
def get_profiles():
|
||||
try :
|
||||
try:
|
||||
profile_files = os.listdir(profile_path)
|
||||
except :
|
||||
except:
|
||||
profile_files = []
|
||||
profiles = []
|
||||
for filename in profile_files:
|
||||
with open(os.path.join(profile_path,filename), 'r') as f:
|
||||
with open(os.path.join(profile_path, filename), 'r') as f:
|
||||
profiles.append(json.load(f))
|
||||
return json.dumps(profiles)
|
||||
|
||||
|
||||
def save_profile(profile, force=False):
|
||||
profile_json = json.dumps(profile)
|
||||
filename = profile['name']+".json"
|
||||
filepath = os.path.join(profile_path,filename)
|
||||
filepath = os.path.join(profile_path, filename)
|
||||
if not force and os.path.exists(filepath):
|
||||
log.error("Could not write, %s already exists"%filepath)
|
||||
log.error("Could not write, %s already exists" % filepath)
|
||||
return False
|
||||
with open(filepath, 'w+') as f:
|
||||
f.write(profile_json)
|
||||
f.close()
|
||||
log.info("Wrote %s"%filepath)
|
||||
log.info("Wrote %s" % filepath)
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
ip = config.listening_ip
|
||||
port = config.listening_port
|
||||
log.info("listening on %s:%d"%(ip,port))
|
||||
log.info("listening on %s:%d" % (ip, port))
|
||||
|
||||
server = WSGIServer((ip,port), app,
|
||||
handler_class=WebSocketHandler)
|
||||
server = WSGIServer((ip, port), app,
|
||||
handler_class=WebSocketHandler)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user