testing temperature streaming

master
James Gao 2014-10-19 19:02:12 -07:00
rodzic 0459d84a00
commit 769202e41b
4 zmienionych plików z 269 dodań i 95 usunięć

Wyświetl plik

@ -1,19 +1,46 @@
import time
import json
import tornado.ioloop
import tornado.web
cwd = os.path.split(os.path.abspath(__file__))[0]
class MainHandler(tornado.web.RequestHandler):
def initialize(self, monitor):
self.monitor = monitor
def get(self):
self.write("<!doctype html><head><meta http-equiv='refresh' content='5' ></head><p>Current temperature: %.2f&deg;C, %.2f&deg;F"%read_temp())
class ClientSocket(websocket.WebSocketHandler):
def initialize(self, parent):
self.parent = parent
def open(self):
self.parent.sockets.append(self)
def on_close(self):
self.parent.sockets.remove(self)
class WebApp(object):
def __init__(self, handlers, port=8888):
self.handlers = [
(r"/ws/", ClientSocket, dict(parent=self)),
(r"/(.*)", tornado.web.StaticFileHandler, dict(path=cwd)),
]
self.sockets = []
self.port = port
def send(self, data):
jsondat = json.dumps(data)
for sock in self.sockets:
socket.write_message(jsondat)
def run(self):
self.app = tornado.web.Application(self.handlers, gzip=True)
self.app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
if __name__ == "__main__":
application = tornado.web.Application([
(r"/", MainHandler, dict(monitor=mon)),
])
import thermo
monitor = thermo.Monitor()
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
app = WebApp([])
def send_temp(time, temp):
app.send(dict(time=time, temp=temp))
monitor.callback = send_temp
monitor.start()
app.run()

Wyświetl plik

@ -5,7 +5,6 @@ var tempgraph = (function(module) {
show_axes: true,
}
module.Graph = function(options) {
//Options: margin, width, height, object
if (options === undefined)
options = module.graph_defaults;
@ -19,51 +18,69 @@ var tempgraph = (function(module) {
this.height = options.height ? options.height : $(this.obj).height() - this.margin.top - options.margin.bottom;
this.svg = d3.select(this.obj);
this.svg.append("defs").append("rect")
.attr("class", "pane")
.attr("width", this.width)
.attr("height", this.height);
this.axes = this.svg.append("g")
.attr("class", "axes")
this.svg.append("defs").append("clipPath").attr("id", "pane")
.append("rect")
.attr("width", this.width)
.attr("height", this.height);
var xfm = this.svg.append("g")
.attr("transform", "translate("+this.margin.left+","+this.margin.top+")")
.attr("clip-path", "url(#pane)");
/*xfm.append("rect")
.attr("style", "fill:#DDD")
.attr("width", this.width)
.attr("height", this.height);*/
this.x = d3.time.scale().range([0, this.width]);
this.y = d3.scale.linear().range([this.height, 0]);
this.zoom = d3.behavior.zoom().on("zoom", this.draw.bind(this));
this.zoom = d3.behavior.zoom().on("zoom", this.draw.bind(this))
.on("zoomend", this.recenter.bind(this));
if (options.show_axes === undefined || options.show_axes) {
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom");
this.y_axis = d3.svg.axis().scale(this.y).orient("left");
this.x_axis = d3.svg.axis().scale(this.x).orient("bottom")
.tickSize(this.height).tickSubdivide(true);
this.y_axis = d3.svg.axis().scale(this.y).orient("left")
.tickSize(this.width).tickSubdivide(true);
//setup axies labels and ticks
this.axes.append("g")
xfm.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + this.height + ")")
//.attr("transform", "translate(0," + this.height + ")")
.call(this.x_axis);
this.axes.append("g")
xfm.append("g")
.attr("class", "y axis")
.attr("transform", "translate("+this.width+", 0)")
.call(this.y_axis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("class", "ylabel")
.attr("transform", "translate(-"+this.width+",0)rotate(-90)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("Temperature (°F)");
}
this.axes = xfm.append("g")
.attr("class", "axes")
.attr("style", "clip-path:url(#pane)");
window.onresize = this.resize.bind(this);
this.lines = [];
this.lines = {};
};
module.Graph.prototype.plot = function(data, marker) {
module.Graph.prototype.plot = function(data, className, marker) {
this.x.domain(d3.extent(data, function(d) { return d.x; }));
this.y.domain(d3.extent(data, function(d) { return d.y; }));
this.zoom.x(this.x);
var line = d3.svg.line()
.x(function(d) { return this.x(d.x); }.bind(this))
.y(function(d) { return this.y(d.y); }.bind(this));
this.axes.append("path")
.datum(data)
.attr("class", "line")
.attr("class", className)
.attr("d", line);
if (marker !== undefined && marker) {
@ -75,11 +92,8 @@ var tempgraph = (function(module) {
.attr("cx", function(d) { return this.x(d.x); }.bind(this))
.attr("cy", function(d) { return this.y(d.y); }.bind(this));
}
this.lines.push({line:line, data:data, marker:marker});
this.x.domain(d3.extent(data, function(d) { return d.x; }));
this.y.domain(d3.extent(data, function(d) { return d.y; }));
this.zoom.x(this.x);
this.lines[className] = {line:line, data:data, marker:marker};
this.svg.call(this.zoom);
this.draw();
return line;
@ -88,18 +102,17 @@ var tempgraph = (function(module) {
this.svg.select("g.x.axis").call(this.x_axis);
this.svg.select("g.y.axis").call(this.y_axis);
var line, data, marker;
for (var i = 0; i < this.lines.length; i++) {
line = this.lines[i].line;
data = this.lines[i].data;
marker = this.lines[i].marker;
for (var name in this.lines) {
line = this.lines[name].line;
data = this.lines[name].data;
marker = this.lines[name].marker;
if (marker !== undefined) {
this.svg.selectAll(".dot").data(data)
.attr("cx", function(d) { return this.x(d.x)}.bind(this))
.attr("cy", function(d) { return this.y(d.y)}.bind(this));
}
this.svg.select("path.line").attr("d", line);
this.svg.select("path."+name).attr("d", line);
}
console.log("draw");
}
module.Graph.prototype.resize = function() {
var margin = this.margin;
@ -109,54 +122,48 @@ var tempgraph = (function(module) {
this.svg
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
this.svg.select("rect.pane")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
this.x.range([0, width]);
this.y.range([height, 0]);
this.width = width;
this.height = height;
this.draw();
console.log("resized");
}
module.Graph.prototype.update = function(line, data) {
for (var i = 0; i < this.lines.length; i++) {
if (this.lines[i].line === line) {
this.axes.select("path.line").datum(data).attr("d", line);
}
module.Graph.prototype.recenter = function() {
var extent = [], data, valid,
low = this.x.domain()[0], high=this.x.domain()[1];
for (var name in this.lines) {
data = this.lines[name].data;
valid = data.filter(function(d) { return low <= d.x && d.x <= high; })
extent = extent.concat(valid);
}
this.y.domain(d3.extent(extent, function(d) {return d.y;}));
this.draw();
}
module.Graph.prototype.update = function(className, data) {
this.lines[className].data = data;
this.axes.select("path."+className).datum(data)
.attr("d", this.lines[className].line);
this.draw();
}
module.Graph.prototype.xlim = function(min, max) {
if (min === undefined)
return this.x.domain();
this.x.domain([min, max]);
this.draw();
}
module.Graph.prototype.ylim = function(min, max) {
if (min === undefined)
return this.y.domain();
this.y.domain([min, max]);
this.draw();
}
module.Graph.prototype.ylabel = function(text) {
this.svg.select(".ylabel").text(text);
}
return module;
}(tempgraph || {}));
var data = d3.tsv("data.txt", function(error, data) {
data.forEach(function(d) {
d.x = new Date(d.time*1000.);
d.y = +d.temp*9/5+32;
});
graph = new tempgraph.Graph()
line = graph.plot(data, false);
});
function update() {
d3.tsv("data2.txt", function(error, data) {
data.forEach(function(d) {
d.x = new Date(d.time*1000.);
d.y = +d.temp;
});
var lim = d3.extent(data, function(d){return d.x;});
graph.xlim(lim[0], lim[1]);
graph.update(line, data);
console.log("done!");
})
}

Wyświetl plik

@ -0,0 +1,116 @@
var tempgraph = (function(module) {
module.Monitor = function(initial) {
this.temperature = initial;
//default to F
this.scalefunc = module.temp_to_F;
this.temp_suffix = "°F"
this.temp_prefix = ""
this._mapped = this.temperature.map(this._map_temp.bind(this));
this.graph = new tempgraph.Graph();
this.graph.plot(initial.map(this._map_temp.bind(this)), "temperature", false);
var latest = this.temperature[this.temperature.length-1];
this.update_temp({time:latest.x/1000., temp:latest.y});
this._bindUI();
}
module.Monitor.prototype.update_temp = function(data) {
var now = new Date(data.time*1000.);
var nowstr = now.getHours() % 12 + ":" + now.getMinutes() + (now.getHours() > 12 ? " pm" : " am");
var temp = this.scalefunc(data.temp);
$("#current_time").text(nowstr);
$("#current_temp").text(this.temp_prefix+temp+this.temp_suffix);
if (now > this.temperature[this.temperature.length-1].x) {
this.temperature.push({x:now, y:+data.temp});
this._mapped.push({x:now, y:temp});
var lims = this.graph.xlim();
if (now > lims[1]) {
var start = new Date(now.getTime() - lims[1].getTime() + lims[0].getTime());
this.graph.xlim(start, now);
}
this.graph.update("temperature", this._mapped);
}
if (data.output !== undefined) {
$("#current_output_text").text(data.output*100+"%");
$("#current_output").val(data.output*1000);
}
}
module.Monitor.prototype.update_UI = function(packet) {
}
module.Monitor.prototype.setProfile = function(profile) {
}
module.Monitor.prototype.setScale = function(scale) {
$("a#temp_scale_C").parent().removeClass("active");
$("a#temp_scale_F").parent().removeClass("active");
$("a#temp_scale_cone").parent().removeClass("active");
if (scale == "C") {
$("li a#temp_scale_C").parent().addClass("active");
this.scalefunc = module.temp_to_C;
this.graph.ylabel("Temperature (°C)")
this.temp_suffix = "°C";
this.temp_prefix = "";
} else if (scale == "F") {
$("li a#temp_scale_F").parent().addClass("active");
this.scalefunc = module.temp_to_F;
this.graph.ylabel("Temperature (°F)")
this.temp_suffix = "°F";
this.temp_prefix = "";
} else if (scale == "cone") {
$("li a#temp_scale_cone").parent().addClass("active");
this.scalefunc = module.temp_to_cone;
this.graph.ylabel("Temperature (Δ)");
this.temp_prefix = "Δ";
this.temp_suffix = "";
}
this._mapped = this.temperature.map(this._map_temp.bind(this));
this.graph.y.domain(d3.extent(this._mapped, function(d) { return d.y; }));
var latest = this.temperature[this.temperature.length-1];
this.update_temp({time:latest.x/1000., temp:latest.y});
this.graph.update("temperature", this._mapped);
}
module.Monitor.prototype._map_temp = function(d) {
return {x:d.x, y:this.scalefunc(d.y)};
}
module.Monitor.prototype._bindUI = function() {
/*
var sock = new WebSocket("ws://localhost/socket/", "protocolOne");
sock.onmessage = function(event) {
var data = JSON.parse(event.data);
this.update(data);
}
*/
$("#temp_scale_C").click(function() { this.setScale("C");}.bind(this));
$("#temp_scale_F").click(function() { this.setScale("F");}.bind(this));
//$("#temp_scale_C").click(function() { this.setScale("C");}.bind(this));
}
module.temp_to_C = function(temp) { return temp; }
module.temp_to_F = function(temp) {
return temp * 9 / 5 + 32;
}
module.temp_to_cone = function(temp) {
return "Not implemented"
}
return module;
}(tempgraph || {}));
d3.tsv("data.txt", function(error, data) {
var newdata = [], d;
for (var i = 0; i < data.length; i+=4) {
d = data[i];
newdata.push({x:new Date(d.time*1000), y:+d.temp});
}
monitor = new tempgraph.Monitor(newdata);
});

Wyświetl plik

@ -24,18 +24,19 @@
width:7% !important;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.line {
.temperature {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
.axis .tick{
stroke:#DDD;
stroke-width:.5px;
}
.domain{
display:none;
}
#graph {
width:100%;
@ -48,6 +49,17 @@
pointer-events: all;
}
#stop-button {
margin-left:10px;
margin-right:10px;
}
#current_temp {
font-weight:bold;
font-size:200%;
color:black;
}
</style>
<!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
@ -78,12 +90,13 @@
<ul class="nav navbar-nav navbar-right">
<li><a href="#" class="dropdown-toggle" data-toggle="dropdown"><div id="current_temp">Temperature</div></a>
<ul class="dropdown-menu" role="menu">
<li class="active"><a href="#">°F</a></li>
<li><a href="#">°C</a></li>
<li><a href="#">Δ</a></li>
</ul></li>
<li class="active"><a href="#" id="temp_scale_F">°F</a></li>
<li><a href="#" id="temp_scale_C">°C</a></li>
<li><a href="#" id="temp_scale_cone">Δ</a></li>
</ul>
</li>
<li><a href="#" id="current_time">Time</a></li>
<li><a href="#" id="current_output">0%</a></li>
<li><a href="#" id="current_output_text">0%</a></li>
<li><button id="stop-button" class="btn btn-primary navbar-btn hidden" href="#">Stop</button></li>
</ul>
</div><!--/.nav-collapse -->
@ -96,16 +109,19 @@
<div class="row">
<div class="col-sm-8 col-md-8 row-space">
<svg id="graph" class="row-space"></svg>
<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>
<div class="btn-group btn-group-justified row-space">
<div class="btn-group">
<button type="button" class="btn btn-primary disabled">Off</button>
<button type="button" class="btn btn-primary disabled"><span class="glyphicon glyphicon-stop"></span> Off</button>
</div>
<div class="btn-group output-slider">
<input type="range" min=0 max=1000 class="btn btn-default" />
<input id="current_output" type="range" min=0 max=1000 class="btn btn-default" />
</div>
<div class="btn-group">
<button type="button" class="btn btn-danger">Ignite</button>
<button type="button" class="btn btn-danger"><span class="glyphicon glyphicon-fire"></span> Ignite</button>
</div>
</div>
</div>
@ -119,10 +135,20 @@
</ul>
</div><!-- /btn-group -->
</div><!-- /input-group -->
<div class='btn-group btn-group-justified row-space'>
<a href="#" class="btn btn-primary disabled"> Start <span class="glyphicon glyphicon-play"></span></a>
<a href="#" class="btn btn-default disabled"> Pause <span class="glyphicon glyphicon-pause"></span></a>
<a href="#" class="btn btn-success disabled"> Save <span class="glyphicon glyphicon-floppy-disk"></span></a>
<div id='profile_info' class='panel panel-default hidden'>
<div class='panel-body'>
<dl class='dl-horizontal'>
<dt>Total time</dt>
<dd></dd>
<dt>Finish at</dt>
<dd></dd>
</dl>
</div>
</div>
<div id='profile_actions' class='btn-group btn-group-justified row-space hidden'>
<a href="#" class="btn btn-primary disabled"><span class="glyphicon glyphicon-play"></span> Start</a>
<a href="#" class="btn btn-default disabled"><span class="glyphicon glyphicon-pause"></span> Pause</a>
<a href="#" class="btn btn-success disabled"><span class="glyphicon glyphicon-floppy-disk"></span> Save</a>
</div>
<img src="http://placehold.it/640x480/" class="img-responsive" alt="webcam" />
</div>
@ -133,7 +159,5 @@
<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>
</body>
</html>