Support incremental download of sensor data.
authorPat Thoyts <patthoyts@users.sourceforge.net>
Mon, 16 May 2016 11:59:44 +0000 (12:59 +0100)
committerPat Thoyts <patthoyts@users.sourceforge.net>
Mon, 16 May 2016 11:59:44 +0000 (12:59 +0100)
Break up the data download into 1 day chunks and display all in the top
overview plot and let the user update the lower plot.

static/sensor-hub.html

index 1aa39fa5eb10aa9cb7f35e39bd4c9053a215afb6..801efa55280b3868130cab343b6a51b89c331384 100644 (file)
@@ -27,6 +27,8 @@ div.loading { background: rgba(255,255,255,.8) url('loading.gif') 50% 50% no-rep
 <div id="overview" style="height:80px;"></div>
 <div id="graph" style="height:400px;"></div>
 <p>Download view data as <a href="#" onclick="on_download('text')">ASCII</a> or <a href="#" onclick="on_download('json')">JSON</a></p>
+<p><a href="#" onclick="fetch_more_days(7)">Fetch another week</a>: update with an additional weeks historical data.</p>
+<p><a href="#" onclick="fetch_more_days(30)">Fetch another 30 days</a>: update with an additional month historical data.</p>
 <p id="result"/>
 <div id="tooltip"></div>
 </div><!-- /content -->
@@ -93,36 +95,10 @@ function on_received_recent(recent) {
     r.appendTo(t);
     t.appendTo('#result');
 }
-function on_draw_graph(data) {
-    document.custom.data = data;
-    if (data.response == "error") {
-        $("#status").text(data.message);
-        return;
-    }
-    var now = new Date();
-    var plotA = [];
-    var plotB = [];
-    var plotC = [];
-
-    var colors = ["#a040b0","#00a040","#0040a0"];
-    var plotdata = [];
-    $.each(data.result[10].sensors, function(n, sensor) {
-        plotdata.push({data: [], label: sensor.id, color: colors[n]});
-    });
-    $.each(data.result, function(i,item) {
-        var t = item.timestamp*1000;
-        $.each(item.sensors, function(n, sensor) {
-            var v = sensor.value;
-            if (v < -100)
-                v = plotdata[n].data[plotdata[n].data.length - 1];
-            plotdata[n].data.push([t,v]);
-        });
-    });
-    $('#status').html('');
-    if (typeof(document.custom.recent) != typeof(undefined)) {
-        $('#timestamp').html("Last collection at " + displayTime(document.custom.recent.response.timestamp * 1000));
-    }
-    var options = {
+function graph_init() {
+    document.custom.graph_main = {plot: {}, options: {}};
+    document.custom.graph_overview = {plot: {}, options: {}};
+    document.custom.graph_main.options = {
         series: {
             shadowSize: 0,
             bars: { show: false },
@@ -134,9 +110,7 @@ function on_draw_graph(data) {
         xaxis: { mode: "time", timezone: "browser", timeformat: "%d-%b<br/>%H:%M" },
         yaxis: { }
     };
-    var plot = $.plot($('#graph'), plotdata, options);
-    document.custom.graph = plot;
-    var ovopt = {
+    document.custom.graph_overview.options = {
         series: { lines: { show: true, lineWidth: 1 }, shadowSize: 0 },
         legend: { show: false },
         grid: { markings: weekend_markings },
@@ -144,8 +118,8 @@ function on_draw_graph(data) {
         yaxis: { ticks: [], autoscaleMargin: 0.1 },
         selection: { mode: "x" }
     };
-    var ovplot = $.plot("#overview", plotdata, ovopt);
     $("#graph").bind("plotselected", function (event, ranges) {
+        var plot = document.custom.graph_main.plot;
         $.each(plot.getXAxes(), function (_, axis) {
             var opts = axis.options;
             opts.min = ranges.xaxis.from;
@@ -154,28 +128,112 @@ function on_draw_graph(data) {
         plot.setupGrid();
         plot.draw();
         plot.clearSelection();
-        ovplot.setSelection(ranges, true); // avoid event loop
+        document.custom.graph_overview.plot.setSelection(ranges, true); // avoid event loop
     });
     $("#overview").bind("plotselected", function (event, ranges) {
-        plot.setSelection(ranges);
+        var plot = document.custom.graph_overview.plot;
+        var mainPlot = document.custom.graph_main.plot;
+        if (mainPlot.getData()[0].data.length != plot.getData()[0].data.length) {
+            mainPlot.setData(document.custom.plotdata);
+        }
+        $.each(plot.getXAxes(), function (_, axis) {
+            var opts = axis.options;
+            opts.min = ranges.xaxis.from;
+            opts.max = ranges.xaxis.to;
+        });
+        mainPlot.setSelection(ranges);
     });
 }
-function main() {
+function replot(both) {
+    var ovplot = $.plot("#overview", document.custom.plotdata, document.custom.graph_overview.options);
+    document.custom.graph_overview.plot = ovplot;
+    if (both) {
+        var plot = $.plot($('#graph'), document.custom.plotdata, document.custom.graph_main.options);
+        document.custom.graph_main.plot = plot;
+    }
+}
+function on_draw_graph(data) {
+    document.custom.data = data;
+    if (data.response == "error") {
+        $("#status").text(data.message);
+        return;
+    }
+    $('#status').html('');
+    if (typeof(document.custom.recent) != typeof(undefined)) {
+        $('#timestamp').html("Last collection at " + displayTime(document.custom.recent.response.timestamp * 1000));
+    }
+    graph_init();
+    add_data(data);
+    replot(true);
+}
+function on_received_sensors(data) {
+    // data is array of sensor names, create all the plotdata array elements
+    document.custom.plotdata = [];
+    document.custom.sensors = data.response;
+    $.each(data.response, function(n, sensorName) {
+        document.custom.plotdata.push({data: [], label: sensorName, color: document.custom.colors[n]});
+    });
+    fetch_initial_data();   
+}
+function add_data(data) {
+    var plotdata = []; // one element per sensor
+    $.each(document.custom.plotdata, function(n,plot) {
+       plotdata.push([]); 
+    });
+    var oldest = document.custom.oldest;
+    var newest = document.custom.newest;
+    // update each sensor in plotdata adding new values
+    $.each(data.result, function(i,item) {
+        var t = item.timestamp*1000;
+        if (newest < t) newest = t;
+        if (oldest > t) oldest = t;
+        $.each(item.sensors, function(n, sensor) {
+            var v = sensor.value;
+            if (v < -100)
+                v = plotdata[n][plotdata[n].length - 1];
+            plotdata[n].push([t,v]);
+        });
+    });
+    $.each(document.custom.plotdata, function(n,plot) {
+       document.custom.plotdata[n].data = plotdata[n].concat(plot.data); 
+    });
+    window.setTimeout(function() {replot(false);}, 20);
+    if (oldest < document.custom.oldest) {
+        if (((newest - oldest) / 1000 / (60*60*24)) < document.custom.days) {
+            var one_day = 60 * 60 * 24 * 1000;
+            window.setTimeout(function() {fetch_more((oldest - one_day)/1000, oldest/1000);}, 50);
+        }
+        document.custom.oldest = oldest;
+    }
+    document.custom.newest = newest;
+}
+function fetch_more_days(count) {
+    document.custom.days = document.custom.days + count;
+    var one_day = 60 * 60 * 24 * 1000;
+    var oldest = document.custom.oldest;
+    window.setTimeout(function() {fetch_more((oldest - one_day)/1000, oldest/1000);}, 50);
+}
+function fetch_more(from_unixtime, until_unixtime) {
+    when_from = (new Date(from_unixtime * 1000)).toISOString();
+    when_until = (new Date(until_unixtime * 1000)).toISOString();
     $.ajax({
-        url: 'recent',
+        url: 'since',
         dataType: 'json',
-        complete: function(jqqxhr, msg) { $('#result').removeClass("loading"); },
-        beforeSend: function(jqxhr, opt) { $('#result').addClass("loading"); },
-        success: on_received_recent,
-        error: function(jqqxhr, err, evt) { alert("recent: "+err); }
+        data: { from: when_from, until: when_until },
+        beforeSend: function (jqxhr, opts) { $('#status').text("fetching more data..."); },
+        complete: function(jqxhr,msg) { $('#status').text(""); },
+        error: function(jqxhr,err,evt) { $('#status').text("error: " + err); },
+        success: add_data,
     });
+}
+function fetch_initial_data() {
     var now = ((new Date() - 0) / 1000);
-    var when = now - (60 * 60 * 24 * 28); // 28 days
-    when = (new Date(when * 1000)).toISOString();
+    var when_from = now - (60 * 60 * 24 * 1); // 28 days
+    when_from = (new Date(when_from * 1000)).toISOString();
     $.ajax({
         url: 'since',
         dataType: 'json',
-        data: { when: when },
+        data: { from: when_from },
         beforeSend: function (jqxhr, opts) {
             $("#graph").addClass("loading");
             $("#overview").addClass("loading");
@@ -185,6 +243,26 @@ function main() {
         success: on_draw_graph,
     });
 }
+function main() {
+    document.custom = {plotdata: [], data: [], recent: {}, oldest: Infinity, newest: 0, days: 7};
+    document.custom.colors = ["#a040b0","#00a040","#0040a0"];
+    $.ajax({
+        url: 'recent',
+        dataType: 'json',
+        complete: function(xhr, msg) { $('#result').removeClass("loading"); },
+        beforeSend: function(xhr, opt) { $('#result').addClass("loading"); },
+        success: on_received_recent,
+        error: function(xhr, err, evt) { alert("recent: "+err); }
+    });
+    $.ajax({
+        url: 'sensors',
+        dataType: 'json',
+        data: {hostname: 'spd-office'},
+        success: on_received_sensors,
+        beforeSend: function(xhr,o) { $('#status').text("Fetching sensor list"); },
+        complete: function(xhr,msg) { $('#status').text(msg); }
+    })
+}
 $("#graph").bind("plothover", function(event, pos, item) {
     if (item) {
         var x = item.datapoint[0].toFixed(2),
@@ -198,7 +276,6 @@ $("#graph").bind("plothover", function(event, pos, item) {
     }
 });
 $(document).ready(function () {
-    document.custom = {};
     main();
 });
 </script>