Add very basic support for viewing probe readings as graph
can only view the last hour of readings, so far
This commit is contained in:
parent
c6b2f831e5
commit
0e13e5606a
66
tailbone/templates/tempmon/probes/graph.mako
Normal file
66
tailbone/templates/tempmon/probes/graph.mako
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
## -*- coding: utf-8; -*-
|
||||||
|
<%inherit file="/base.mako" />
|
||||||
|
|
||||||
|
<%def name="title()">Temperature Graph</%def>
|
||||||
|
|
||||||
|
<%def name="extra_javascript()">
|
||||||
|
${parent.extra_javascript()}
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
var ctx = $('#tempchart');
|
||||||
|
|
||||||
|
var chart = new Chart(ctx, {
|
||||||
|
type: 'scatter',
|
||||||
|
data: {
|
||||||
|
datasets: [{
|
||||||
|
label: "${probe.description}",
|
||||||
|
data: ${json.dumps(readings_data)|n}
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
scales: {
|
||||||
|
xAxes: [{
|
||||||
|
type: 'time',
|
||||||
|
time: {unit: 'minute'},
|
||||||
|
position: 'bottom'
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</%def>
|
||||||
|
|
||||||
|
<div class="form-wrapper">
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>Appliance</label>
|
||||||
|
<div class="field">
|
||||||
|
% if probe.appliance:
|
||||||
|
<a href="${url('tempmon.appliances.view', uuid=probe.appliance.uuid)}">${probe.appliance}</a>
|
||||||
|
% endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>Probe Location</label>
|
||||||
|
<div class="field">${probe.location}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="field-wrapper">
|
||||||
|
<label>Showing</label>
|
||||||
|
<div class="field">
|
||||||
|
<select name="showing-window" id="showing-window" auto-enhance="true">
|
||||||
|
<option value="last-hour">Last Hour</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<canvas id="tempchart" width="400" height="150"></canvas>
|
|
@ -41,6 +41,11 @@
|
||||||
## rendering methods
|
## rendering methods
|
||||||
##############################
|
##############################
|
||||||
|
|
||||||
|
<%def name="context_menu_items()">
|
||||||
|
${parent.context_menu_items()}
|
||||||
|
<li>${h.link_to("View Readings as Graph", action_url('graph', instance))}</li>
|
||||||
|
</%def>
|
||||||
|
|
||||||
<%def name="render_main_fields(form)">
|
<%def name="render_main_fields(form)">
|
||||||
${form.render_field_readonly('client')}
|
${form.render_field_readonly('client')}
|
||||||
${form.render_field_readonly('config_key')}
|
${form.render_field_readonly('config_key')}
|
||||||
|
|
|
@ -26,8 +26,11 @@ Views for tempmon probes
|
||||||
|
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from rattail.time import make_utc, localtime
|
||||||
from rattail_tempmon.db import model as tempmon
|
from rattail_tempmon.db import model as tempmon
|
||||||
|
|
||||||
import colander
|
import colander
|
||||||
|
@ -220,6 +223,46 @@ class TempmonProbeView(MasterView):
|
||||||
|
|
||||||
g.set_sort_defaults('taken', 'desc')
|
g.set_sort_defaults('taken', 'desc')
|
||||||
|
|
||||||
|
def graph(self):
|
||||||
|
probe = self.get_instance()
|
||||||
|
|
||||||
|
# figure out which readings we need to graph
|
||||||
|
# TODO: make this dynamic somehow
|
||||||
|
cutoff = make_utc() - datetime.timedelta(seconds=3600) # last hour
|
||||||
|
readings = self.Session.query(tempmon.Reading)\
|
||||||
|
.filter(tempmon.Reading.probe == probe)\
|
||||||
|
.filter(tempmon.Reading.taken >= cutoff)\
|
||||||
|
.order_by(tempmon.Reading.taken)\
|
||||||
|
.all()
|
||||||
|
|
||||||
|
# convert readings to data for scatter plot
|
||||||
|
data = [{
|
||||||
|
'x': localtime(self.rattail_config, reading.taken, from_utc=True).isoformat(),
|
||||||
|
'y': float(reading.degrees_f),
|
||||||
|
} for reading in readings]
|
||||||
|
|
||||||
|
context = {
|
||||||
|
'probe': probe,
|
||||||
|
'parent_title': six.text_type(probe),
|
||||||
|
'parent_url': self.get_action_url('view', probe),
|
||||||
|
'readings_data': data,
|
||||||
|
}
|
||||||
|
return self.render_to_response('graph', context)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def defaults(cls, config):
|
||||||
|
route_prefix = cls.get_route_prefix()
|
||||||
|
url_prefix = cls.get_url_prefix()
|
||||||
|
model_key = cls.get_model_key()
|
||||||
|
permission_prefix = cls.get_permission_prefix()
|
||||||
|
model_title_plural = cls.get_model_title_plural()
|
||||||
|
|
||||||
|
config.add_route('{}.graph'.format(route_prefix), '{}/{{{}}}/graph'.format(url_prefix, model_key))
|
||||||
|
config.add_view(cls, attr='graph', route_name='{}.graph'.format(route_prefix),
|
||||||
|
permission='{}.view'.format(permission_prefix))
|
||||||
|
|
||||||
|
cls._defaults(config)
|
||||||
|
|
||||||
|
|
||||||
def includeme(config):
|
def includeme(config):
|
||||||
TempmonProbeView.defaults(config)
|
TempmonProbeView.defaults(config)
|
||||||
|
|
Loading…
Reference in a new issue