Always return the last Cal entry (don't worry about how old it might be) #476

Merged
merged 13 commits into from Mar 14, 2015
+259 −155
Split
View
@@ -1,3 +1,5 @@
+'use strict';
+
var DIRECTIONS = {
NONE: 0
, DoubleUp: 1
@@ -12,6 +14,7 @@ var DIRECTIONS = {
};
var iob = require("./iob")();
+var async = require('async');
function directionToTrend (direction) {
var trend = 8;
@@ -22,97 +25,125 @@ function directionToTrend (direction) {
}
function pebble (req, res) {
- var ONE_DAY = 24 * 60 * 60 * 1000;
- var useMetricBg = (req.query.units === "mmol");
- var uploaderBattery;
- var treatmentResults;
- var profileResult;
+ var ONE_DAY = 24 * 60 * 60 * 1000
+ , uploaderBattery
+ , treatmentResults
+ , profileResult
+ , sgvData = [ ]
+ , calData = [ ];
function scaleBg(bg) {
- if (useMetricBg) {
+ if (req.mmol) {
return (Math.round((bg / 18) * 10) / 10).toFixed(1);
- } else
+ } else {
return bg;
+ }
}
- function get_latest (err, results) {
+ function sendData () {
var now = Date.now();
- var sgvData = [ ];
- var calData = [ ];
-
- results.forEach(function(element, index, array) {
- if (element) {
- var obj = {};
- if (element.sgv) {
- var next = null;
- var sgvs = results.filter(function(d) {
- return !!d.sgv;
- });
- if (index + 1 < sgvs.length) {
- next = sgvs[index + 1];
- }
- obj.sgv = scaleBg(element.sgv).toString();
- obj.bgdelta = (next ? (scaleBg(element.sgv) - scaleBg(next.sgv) ) : 0);
- if (useMetricBg) {
- obj.bgdelta = obj.bgdelta.toFixed(1);
- }
- if ('direction' in element) {
- obj.trend = directionToTrend(element.direction);
- obj.direction = element.direction;
- }
- obj.datetime = element.date;
- if (req.rawbg) {
- obj.filtered = element.filtered;
- obj.unfiltered = element.unfiltered;
- obj.noise = element.noise;
- obj.rssi = element.rssi;
- }
- // obj.date = element.date.toString( );
- sgvData.push(obj);
- } else if (req.rawbg && element.type == 'cal') {
- calData.push(element);
- }
- }
- });
- var count = parseInt(req.query.count) || 1;
-
- var bgs = sgvData.slice(0, count);
//for compatibility we're keeping battery and iob here, but they would be better somewhere else
- bgs[0].battery = uploaderBattery ? "" + uploaderBattery : undefined;
- if (req.iob) {
- bgs[0].iob = iob.calcTotal(treatmentResults.slice(0, 20), profileResult, new Date(now)).display;
+ if (sgvData.length > 0) {
+ sgvData[0].battery = uploaderBattery ? "" + uploaderBattery : undefined;
+ if (req.iob) {
+ sgvData[0].iob = iob.calcTotal(treatmentResults.slice(0, 20), profileResult, new Date(now)).display;
+ }
}
- var result = { status: [ {now:now}], bgs: bgs, cals: calData.slice(0, count) };
+ var result = { status: [ {now: now} ], bgs: sgvData, cals: calData };
res.setHeader('content-type', 'application/json');
res.write(JSON.stringify(result));
res.end( );
- // collection.db.close();
}
- req.devicestatus.last(function(err, value) {
- if (!err && value) {
- uploaderBattery = value.uploaderBattery;
- } else {
- console.error("req.devicestatus.tail", err);
- }
- var earliest_data = Date.now() - ONE_DAY;
- loadTreatments(req, earliest_data, function (err, trs) {
- treatmentResults = trs;
- loadProfile(req, function (err, profileResults) {
- profileResults.forEach(function(profile) {
- if (profile) {
- if (profile.dia) {
- profileResult = profile;
+ var earliest_data = Date.now() - ONE_DAY;
+
+ async.parallel({
+ devicestatus: function (callback) {
+ req.devicestatus.last(function (err, value) {
+ if (!err && value) {
+ uploaderBattery = value.uploaderBattery;
+ } else {
+ console.error("req.devicestatus.tail", err);
}
- }
+ callback();
});
- var q = { find: {"date": {"$gte": earliest_data}} };
- req.entries.list(q, get_latest);
- });
- });
- });
+ }
+ , treatments: function(callback) {
+ loadTreatments(req, earliest_data, function (err, trs) {
+ treatmentResults = trs;
+ callback();
+ });
+ }
+ , profile: function(callback) {
+ loadProfile(req, function (err, profileResults) {
+ profileResults.forEach(function (profile) {
+ if (profile) {
+ if (profile.dia) {
+ profileResult = profile;
+ }
+ }
+ });
+ callback();
+ });
+ }
+ , cal: function(callback) {
+ if (req.rawbg) {
+ var cq = { count: req.count, find: {type: 'cal'} };
+ req.entries.list(cq, function (err, results) {
+ results.forEach(function (element) {
+ if (element) {
+ calData.push({
+ slope: Math.round(element.slope)
+ , intercept: Math.round(element.intercept)
+ , scale: Math.round(element.scale)
+ });
+ }
+ });
+ callback();
+ });
+ } else {
+ callback();
+ }
+ }
+ , entries: function(callback) {
+ var q = { count: req.count, find: { "sgv": { $exists: true }} };
+
+ req.entries.list(q, function(err, results) {
+ results.forEach(function(element, index) {
+ if (element) {
+ var obj = {};
+ var next = null;
+ var sgvs = results.filter(function(d) {
+ return !!d.sgv;
+ });
+ if (index + 1 < sgvs.length) {
+ next = sgvs[index + 1];
+ }
+ obj.sgv = scaleBg(element.sgv).toString();
+ obj.bgdelta = (next ? (scaleBg(element.sgv) - scaleBg(next.sgv) ) : 0);
+ if (req.mmol) {
+ obj.bgdelta = obj.bgdelta.toFixed(1);
+ }
+ if ('direction' in element) {
+ obj.trend = directionToTrend(element.direction);
+ obj.direction = element.direction;
+ }
+ obj.datetime = element.date;
+ if (req.rawbg) {
+ obj.filtered = element.filtered;
+ obj.unfiltered = element.unfiltered;
+ obj.noise = element.noise;
+ }
+ sgvData.push(obj);
+ }
+ });
+ callback();
+ });
+ }
+ }, sendData);
+
}
function loadTreatments(req, earliest_data, fn) {
@@ -140,6 +171,9 @@ function configure (entries, treatments, profile, devicestatus, env) {
req.devicestatus = devicestatus;
req.rawbg = env.enable && env.enable.indexOf('rawbg') > -1;
req.iob = env.enable && env.enable.indexOf('iob') > -1;
+ req.mmol = (req.query.units || env.DISPLAY_UNITS) === 'mmol';
+ req.count = parseInt(req.query.count) || 1;
+
next( );
}
return [middle, pebble];
View
@@ -1,3 +1,4 @@
+var async = require('async');
function websocket (env, server, entries, treatments, profiles) {
"use strict";
@@ -33,7 +34,12 @@ var dir2Char = {
patientData = [];
function start ( ) {
- io = require('socket.io').listen(server);
+ io = require('socket.io').listen(server, {
+ //these only effect the socket.io.js file that is sent to the client, but better than nothing
+ 'browser client minification': true,
+ 'browser client etag': true,
+ 'browser client gzip': true
+ });
}
// get data from database and setup to update every minute
function kickstart (fn) {
@@ -149,62 +155,80 @@ function update() {
mbgData = [];
profileData = [];
var earliest_data = now - TWO_DAYS;
- var q = { find: {"date": {"$gte": earliest_data}} };
- entries.list(q, function (err, results) {
- results.forEach(function(element, index, array) {
- if (element) {
- if (element.mbg) {
- var obj = {};
- obj.y = element.mbg;
- obj.x = element.date;
- obj.d = element.dateString;
- obj.device = element.device;
- mbgData.push(obj);
- } else if (element.sgv) {
- var obj = {};
- obj.y = element.sgv;
- obj.x = element.date;
- obj.d = element.dateString;
- obj.device = element.device;
- obj.direction = directionToChar(element.direction);
- obj.filtered = element.filtered;
- obj.unfiltered = element.unfiltered;
- obj.noise = element.noise;
- obj.rssi = element.rssi;
- cgmData.push(obj);
- } else if (element.slope) {
- var obj = {};
- obj.x = element.date;
- obj.d = element.dateString;
- obj.scale = element.scale;
- obj.intercept = element.intercept;
- obj.slope = element.slope;
- calData.push(obj);
- }
- }
- });
- var tq = { find: {"created_at": {"$gte": new Date(earliest_data).toISOString()}} };
- treatments.list(tq, function (err, results) {
- treatmentData = results.map(function(treatment) {
- var timestamp = new Date(treatment.timestamp || treatment.created_at);
- treatment.x = timestamp.getTime();
- return treatment;
- });
-
- profiles.list(function (err, results) {
- // There should be only one document in the profile collection with a DIA. If there are multiple, use the last one.
- results.forEach(function(element, index, array) {
- if (element) {
- if (element.dia) {
- profileData[0] = element;
+
+ async.parallel({
+ entries: function(callback) {
+ var q = { find: {"date": {"$gte": earliest_data}} };
+ entries.list(q, function (err, results) {
+ results.forEach(function (element) {
+ if (element) {
+ if (element.mbg) {
+ mbgData.push({
+ y: element.mbg
+ , x: element.date
+ , d: element.dateString
+ , device: element.device
+ });
+ } else if (element.sgv) {
+ cgmData.push({
+ y: element.sgv
+ , x: element.date
+ , d: element.dateString
+ , device: element.device
+ , direction: directionToChar(element.direction)
+ , filtered: element.filtered
+ , unfiltered: element.unfiltered
+ , noise: element.noise
+ , rssi: element.rssi
+ });
+ }
}
- }
- });
- // all done, do loadData
- loadData( );
- });
- });
- });
+ });
+ callback();
+ })
+ }
+ , cal: function(callback) {
+ var cq = { count: 1, find: {"type": "cal"} };
+ entries.list(cq, function (err, results) {
+ results.forEach(function (element) {
+ if (element) {
+ calData.push({
+ x: element.date
+ , d: element.dateString
+ , scale: element.scale
+ , intercept: element.intercept
+ , slope: element.slope
+ });
+ }
+ });
+ callback();
+ });
+ }
+ , treatments: function(callback) {
+ var tq = { find: {"created_at": {"$gte": new Date(earliest_data).toISOString()}} };
+ treatments.list(tq, function (err, results) {
+ treatmentData = results.map(function (treatment) {
+ var timestamp = new Date(treatment.timestamp || treatment.created_at);
+ treatment.x = timestamp.getTime();
+ return treatment;
+ });
+ callback();
+ });
+ }
+ , profile: function(callback) {
+ profiles.list(function (err, results) {
+ // There should be only one document in the profile collection with a DIA. If there are multiple, use the last one.
+ results.forEach(function(element, index, array) {
+ if (element) {
+ if (element.dia) {
+ profileData[0] = element;
+ }
+ }
+ });
+ callback();
+ });
+ }
+ }, loadData);
return update;
}
View
@@ -32,9 +32,11 @@
"node": "0.10.x"
},
"dependencies": {
+ "async": "^0.9.0",
"body-parser": "^1.4.3",
"bower": "^1.3.8",
"browserify-express": "^0.1.4",
+ "compression": "^1.4.2",
"errorhandler": "^1.1.1",
"event-stream": "~3.1.5",
"express": "^4.6.1",
Oops, something went wrong.