kopia lustrzana https://github.com/jamesgao/kiln_controller
move files around, add local js/css, start profiles
rodzic
3ac85ba18b
commit
5034ed1ce1
|
@ -1,5 +1,6 @@
|
|||
import time
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
import traceback
|
||||
import inspect
|
||||
|
@ -8,15 +9,7 @@ import tornado.ioloop
|
|||
import tornado.web
|
||||
from tornado import websocket
|
||||
|
||||
cwd = os.path.split(os.path.abspath(__file__))[0]
|
||||
|
||||
class ManagerHandler(tornado.web.RequestHandler):
|
||||
def initialize(self, manager):
|
||||
self.manager = manager
|
||||
|
||||
class MainHandler(ManagerHandler):
|
||||
def get(self):
|
||||
return self.render("template.html", state=self.manager.state.__class__.__name__)
|
||||
import paths
|
||||
|
||||
class ClientSocket(websocket.WebSocketHandler):
|
||||
def initialize(self, parent):
|
||||
|
@ -28,12 +21,46 @@ class ClientSocket(websocket.WebSocketHandler):
|
|||
def on_close(self):
|
||||
self.parent.clients.remove(self)
|
||||
|
||||
class ManagerHandler(tornado.web.RequestHandler):
|
||||
def initialize(self, manager):
|
||||
self.manager = manager
|
||||
|
||||
class MainHandler(ManagerHandler):
|
||||
def get(self):
|
||||
files = os.listdir(paths.profile_path)
|
||||
fixname = lambda x: os.path.splitext(x)[0].replace("_", " ")
|
||||
profiles = dict((fname, fixname(fname)) for fname in files)
|
||||
return self.render(os.path.join(paths.html_templates, "main.html"),
|
||||
state=self.manager.state.__class__.__name__,
|
||||
profiles=profiles,
|
||||
)
|
||||
|
||||
class DataRequest(ManagerHandler):
|
||||
def get(self):
|
||||
data = list(self.manager.history)
|
||||
output = [dict(time=ts.time, temp=ts.temp) for ts in data]
|
||||
self.write(json.dumps(output))
|
||||
|
||||
class ProfileHandler(tornado.web.RequestHandler):
|
||||
def get(self, name):
|
||||
try:
|
||||
with open(os.path.join(paths.profile_path, name)) as fp:
|
||||
self.write(fp.read())
|
||||
except IOError:
|
||||
self.write_error(404)
|
||||
|
||||
def post(self, name):
|
||||
try:
|
||||
schedule = self.get_argument("schedule")
|
||||
fname = os.path.join(paths.profile_path, name)
|
||||
with open(fname, 'w') as fp:
|
||||
json.dump(schedule, fp)
|
||||
self.write(dict(type="success"))
|
||||
except IOError:
|
||||
self.write_error(404)
|
||||
except Exception as e:
|
||||
self.write(dict(type="error", error=repr(e), msg=traceback.format_exc()))
|
||||
|
||||
class DoAction(ManagerHandler):
|
||||
def _run(self, name, argfunc):
|
||||
func = getattr(self.manager.state, name)
|
||||
|
@ -68,16 +95,17 @@ class DoAction(ManagerHandler):
|
|||
self._run(action, self.get_argument)
|
||||
self.write(json.dumps(dict(type="success")))
|
||||
except Exception as e:
|
||||
self.write(json.dumps(dict(type="error", error=repr(e), msg=traceback.format_exc())))
|
||||
self.write(json.dumps(dict(type="error", error=repr(e), msg=traceback.format_exc())))
|
||||
|
||||
class WebApp(object):
|
||||
def __init__(self, manager, port=8888):
|
||||
self.handlers = [
|
||||
(r'/', MainHandler, dict(manager=manager)),
|
||||
(r"/ws/", ClientSocket, dict(parent=self)),
|
||||
(r"/temperature.json", DataRequest, dict(manager=manager)),
|
||||
(r"/do/(.*)", DoAction, dict(manager=manager)),
|
||||
(r"/(.*)", tornado.web.StaticFileHandler, dict(path=cwd)),
|
||||
(r"^/$", MainHandler, dict(manager=manager)),
|
||||
(r"^/ws/?$", ClientSocket, dict(parent=self)),
|
||||
(r"^/temperature.json$", DataRequest, dict(manager=manager)),
|
||||
(r"^/do/(.*)/?$", DoAction, dict(manager=manager)),
|
||||
(r"^/profile/?(.*)$", ProfileHandler),
|
||||
(r"^/(.*)$", tornado.web.StaticFileHandler, dict(path=paths.html_static)),
|
||||
]
|
||||
self.clients = []
|
||||
self.port = port
|
||||
|
|
|
@ -84,10 +84,11 @@ class Cooling(State):
|
|||
return Running, kwargs
|
||||
|
||||
class Running(State):
|
||||
def __init__(self, parent, history, **kwargs):
|
||||
def __init__(self, parent, history, start_time=None, **kwargs):
|
||||
super(Running, self).__init__(parent)
|
||||
self.start_time = start_time
|
||||
self.profile = manager.Profile(therm=self.parent.therm, regulator=self.parent.regulator,
|
||||
callback=self._notify, **kwargs)
|
||||
callback=self._notify, start_time=start_time **kwargs)
|
||||
self.history = history
|
||||
|
||||
def _notify(self, therm, setpoint, out):
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,31 +1,34 @@
|
|||
var tempgraph = (function(module) {
|
||||
module.Monitor = function(initial) {
|
||||
this.temperature = initial;
|
||||
this.profile = null;
|
||||
//default to F
|
||||
this.scalefunc = module.temp_to_F;
|
||||
this.temp_suffix = "°F"
|
||||
this.temp_prefix = ""
|
||||
|
||||
this.graph = new tempgraph.Graph();
|
||||
this.graph = new module.Graph();
|
||||
this._mapped = this.temperature.map(this._map_temp.bind(this));
|
||||
this.graph.plot(this._mapped, "temperature", false);
|
||||
|
||||
this.update_temp(this.last());
|
||||
this.updateTemp(this.last());
|
||||
this._bindUI();
|
||||
}
|
||||
module.Monitor.prototype.update_temp = function(data) {
|
||||
module.Monitor.prototype.updateTemp = function(data) {
|
||||
var now = new Date(data.time*1000.);
|
||||
var temp = this.scalefunc(data.temp);
|
||||
|
||||
var hourstr = now.getHours() % 12;
|
||||
hourstr = hourstr == 0 ? 12 : hourstr;
|
||||
var minstr = now.getMinutes();
|
||||
minstr = minstr.length < 2 ? "0"+minstr : minstr;
|
||||
var nowstr = hourstr + ":" + minstr + (now.getHours() >= 12 ? " pm" : " am");
|
||||
var nowstr = module.format_time(now);
|
||||
|
||||
var tempstr = Math.round(temp*100) / 100;
|
||||
$("#current_time").text(nowstr);
|
||||
$("#current_temp").text(this.temp_prefix+tempstr+this.temp_suffix);
|
||||
|
||||
if (this.profile) {
|
||||
var finish = module.format_time(this.profile.time_finish(now));
|
||||
$("#profile_time_finish").text(finish);
|
||||
}
|
||||
|
||||
//Adjust x and ylims
|
||||
if (now > this.last().time) {
|
||||
this.temperature.push(data);
|
||||
|
@ -60,10 +63,14 @@ var tempgraph = (function(module) {
|
|||
}
|
||||
}
|
||||
}
|
||||
module.Monitor.prototype.update_UI = function(packet) {
|
||||
|
||||
}
|
||||
module.Monitor.prototype.setProfile = function(profile) {
|
||||
module.Monitor.prototype.setProfile = function(schedule, start_time) {
|
||||
this.profile = new module.Profile(schedule, start_time);
|
||||
var start = this.profile.time_start === undefined ?
|
||||
"Not started" : module.format_time(start_time);
|
||||
$("#profile_time_total").text(this.profile.time_total);
|
||||
$("#profile_time_start").text(start);
|
||||
//$("#profile_time_finish") = this.profile.time_finish();
|
||||
$("#profile_info, #profile_actions").hide().removeClass("hidden").slideDown();
|
||||
}
|
||||
module.Monitor.prototype.last = function() {
|
||||
return this.temperature[this.temperature.length-1];
|
||||
|
@ -103,17 +110,19 @@ var tempgraph = (function(module) {
|
|||
return {x:new Date(d.time*1000), y:this.scalefunc(d.temp)};
|
||||
}
|
||||
|
||||
module.Monitor.prototype.set_state = function(name) {
|
||||
module.Monitor.prototype.setState = function(name) {
|
||||
if (name == "Lit") {
|
||||
$("#ignite_button").addClass("disabled");
|
||||
$("#current_output").removeAttr("disabled");
|
||||
$("#stop_button").removeClass("disabled");
|
||||
$("#stop_button_navbar").removeClass("hidden disabled");
|
||||
$("#profile_select").removeClass("disabled");
|
||||
} else if (name == "Idle" || name == "Cooling") {
|
||||
$("#ignite_button").removeClass("disabled");
|
||||
$("#current_output").attr("disabled", "disabled");
|
||||
$("#stop_button").addClass("disabled");
|
||||
$("#stop_button_navbar").addClass("hidden disabled");
|
||||
$("#profile_select").removeClass("disabled");
|
||||
}
|
||||
}
|
||||
module.Monitor.prototype._bindUI = function() {
|
||||
|
@ -121,6 +130,8 @@ var tempgraph = (function(module) {
|
|||
$("#temp_scale_F").click(function() { this.setScale("F");}.bind(this));
|
||||
//$("#temp_scale_C").click(function() { this.setScale("C");}.bind(this));
|
||||
|
||||
$("#profile_name").val("");
|
||||
|
||||
$("#ignite_button").click(function() {
|
||||
this._disable_all();
|
||||
$.getJSON("/do/ignite", function(data) {
|
||||
|
@ -149,9 +160,13 @@ var tempgraph = (function(module) {
|
|||
})
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
$("#profile_list a").click(function(e) {
|
||||
$("#profile_name").val($(e.target).text());
|
||||
var fname = $(e.target).attr("data-fname");
|
||||
$.getJSON("/profile/"+fname, function(data) {
|
||||
this.setProfile(data);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
|
||||
try {
|
||||
var sock = new WebSocket("ws://"+window.location.hostname+":"+window.location.port+"/ws/", "protocolOne");
|
||||
|
@ -159,9 +174,9 @@ var tempgraph = (function(module) {
|
|||
sock.onmessage = function(event) {
|
||||
var data = JSON.parse(event.data);
|
||||
if (data.type == "temperature")
|
||||
this.update_temp(data);
|
||||
this.updateTemp(data);
|
||||
else if (data.type == "state") {
|
||||
this.set_state(data.state);
|
||||
this.setState(data.state);
|
||||
}
|
||||
}.bind(this);
|
||||
} catch (e) {}
|
||||
|
@ -180,5 +195,15 @@ var tempgraph = (function(module) {
|
|||
return "Not implemented"
|
||||
}
|
||||
|
||||
module.format_time = function(now) {
|
||||
if (!(now instanceof Date))
|
||||
now = new Date(now);
|
||||
var hourstr = now.getHours() % 12;
|
||||
hourstr = hourstr == 0 ? 12 : hourstr;
|
||||
var minstr = now.getMinutes();
|
||||
minstr = minstr < 10 ? "0"+minstr : minstr;
|
||||
return hourstr + ":" + minstr + (now.getHours() >= 12 ? " pm" : " am");
|
||||
}
|
||||
|
||||
return module;
|
||||
}(tempgraph || {}));
|
|
@ -0,0 +1,22 @@
|
|||
var tempgraph = (function(module) {
|
||||
module.Profile = function(schedule, start_time) {
|
||||
var end = schedule[schedule.length-1][0];
|
||||
var days = Math.floor(end / 60 / 60 / 24);
|
||||
var hours = Math.floor((end - days*60*60*24) / 60 / 60);
|
||||
var minutes = Math.ceil((end - days*60*60*24 - hours*60*60) / 60);
|
||||
var daystr = days > 0 ? days + " days, " : "";
|
||||
var hourstr = hours > 0 ? hours + " hours": "";
|
||||
var minstr = minutes > 0 ? ", "+minutes + " minutes.":".";
|
||||
this.length = end;
|
||||
this.time_total = daystr+hourstr+minstr;
|
||||
this.time_start = start_time;
|
||||
}
|
||||
module.Profile.prototype.time_finish = function(now) {
|
||||
if (this.time_start instanceof Date) {
|
||||
return new Date(this.time_start.getTime() + this.length*1000);
|
||||
}
|
||||
return new Date(now.getTime() + this.length*1000);
|
||||
}
|
||||
|
||||
return module;
|
||||
}(tempgraph || {}));
|
|
@ -8,10 +8,10 @@
|
|||
|
||||
<!-- Bootstrap -->
|
||||
<!-- Latest compiled and minified CSS -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap.min.css">
|
||||
|
||||
<!-- Optional theme -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
|
||||
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
|
@ -118,11 +118,13 @@
|
|||
</div>
|
||||
<div class="col-sm-4 col-md-4">
|
||||
<div class="input-group input-group-lg row-space">
|
||||
<input type="text" disabled="disabled" class="form-control" placeholder="Load profile">
|
||||
<input id="profile_name" type="text" disabled="disabled" class="form-control" placeholder="Load profile">
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"><span class="caret"></span></button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li><a href="#">...</a></li>
|
||||
<ul id="profile_list" class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
{% for fname, name in profiles.items() %}
|
||||
<li><a href="#" data-fname="{{fname}}">{{ name }}</a></li>
|
||||
{% end %}
|
||||
</ul>
|
||||
</div><!-- /btn-group -->
|
||||
</div><!-- /input-group -->
|
||||
|
@ -130,9 +132,11 @@
|
|||
<div class='panel-body'>
|
||||
<dl class='dl-horizontal'>
|
||||
<dt>Total time</dt>
|
||||
<dd></dd>
|
||||
<dd id="profile_time_total"></dd>
|
||||
<dt>Start time</dt>
|
||||
<dd id="profile_time_start"></dd>
|
||||
<dt>Finish at</dt>
|
||||
<dd></dd>
|
||||
<dd id="profile_time_finish"></dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -148,16 +152,17 @@
|
|||
|
||||
</div> <!-- /container -->
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
|
||||
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="temp_graph.js"></script>
|
||||
<script type="text/javascript" src="temp_monitor.js"></script>
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<script src="js/d3.v3.min.js" charset="utf-8"></script>
|
||||
<script type="text/javascript" src="js/temp_graph.js"></script>
|
||||
<script type="text/javascript" src="js/temp_profile.js"></script>
|
||||
<script type="text/javascript" src="js/temp_monitor.js"></script>
|
||||
<script type="text/javascript">
|
||||
var monitor;
|
||||
d3.json("temperature.json", function(error, data) {
|
||||
monitor = new tempgraph.Monitor(data);
|
||||
monitor.set_state("{{ state }}");
|
||||
monitor.setState("{{ state }}");
|
||||
});
|
||||
</script>
|
||||
</body>
|
Ładowanie…
Reference in New Issue