From 841b4f1e03010aeec07ddd0504f35b550223eecc Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 11 Jan 2015 20:23:44 -0800 Subject: [PATCH 01/31] adjust break point to better support display on iphone6+ in portrait mode --- static/css/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/css/main.css b/static/css/main.css index 9a0d4b8e6d9..39a356acf2f 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -257,7 +257,7 @@ div.tooltip { } } -@media (max-width: 700px) { +@media (max-width: 750px) { #bgButton { font-size: 120%; } From e7440425ac0d148215ea941146c3950e50625592 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 21:42:46 -0800 Subject: [PATCH 02/31] initial port from iob-cob branch --- lib/websocket.js | 26 ++++++++++++++++++++++--- static/js/client.js | 47 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 63 insertions(+), 10 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index c816db8625e..b3fa785da58 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -28,6 +28,7 @@ var dir2Char = { var cgmData = [], treatmentData = [], mbgData = [], + calData = [], patientData = []; function start ( ) { @@ -164,7 +165,18 @@ function update() { obj.d = element.dateString; obj.device = element.device; obj.direction = directionToChar(element.direction); + obj.filtered = element.filtered; + obj.unfiltered = element.unfiltered; + 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); } } }); @@ -191,6 +203,7 @@ function loadData() { actualCurrent, treatment = [], mbg = [], + cal = [], errorCode; if (cgmData) { @@ -204,7 +217,7 @@ function loadData() { // sgv less than or equal to 10 means error code // or warm up period code, so ignore actual = actual.filter(function (a) { - return a.y > 10; + return (a.y > 10 || a.unfiltered > 0); }) } @@ -222,6 +235,13 @@ function loadData() { }); } + if (calData) { + cal = calData.slice(calData.length-200, calData.length); + cal.sort(function(a, b) { + return a.x - b.x; + }); + } + if (actualCurrent && actualCurrent < 39) errorCode = actualCurrent; var actualLength = actual.length - 1; @@ -255,8 +275,8 @@ function loadData() { //TODO: need to consider when data being sent has less than the 2 day minimum // consolidate and send the data to the client - var shouldEmit = is_different(actual, predicted, mbg, treatment, errorCode); - patientData = [actual, predicted, mbg, treatment, errorCode]; + var shouldEmit = is_different(actual, predicted, mbg, treatment, errorCode, cal); + patientData = [actual, predicted, mbg, treatment, errorCode, cal]; console.log('patientData', patientData.length); if (shouldEmit) { emitData( ); diff --git a/static/js/client.js b/static/js/client.js index 8cd03eab2a0..9b4bee6b76a 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -30,6 +30,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , prevSGV , errorCode , treatments + , cal , padding = { top: 20, right: 10, bottom: 30, left: 10 } , opacity = {current: 1, DAY: 1, NIGHT: 0.5} , now = Date.now() @@ -95,7 +96,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; ]); - // lixgbg: Convert mg/dL BG value to metric mmol + // lixgbg: Convert mg/dL BG value to metric mmol function scaleBg(bg) { if (browserSettings.units == 'mmol') { return (Math.round((bg / 18) * 10) / 10).toFixed(1); @@ -103,6 +104,19 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; return bg; } } + + function rawIsigToRawBg(unfiltered, scale, intercept, slope, filtered, sgv) { + if (slope == 0 || unfiltered == 0 || scale ==0 || slope == null || unfiltered == null || scale == null) return 0; + else if (filtered == 0 || filtered == null || sgv < 30 || sgv == null) { + console.info("Skipping ratio adjustment for SGV " + sgv); + return scale*(unfiltered-intercept)/slope; + } + else { + var ratio = scale*(filtered-intercept)/slope / sgv; + return scale*(unfiltered-intercept)/slope / ratio; + } + } + // initial setup of chart when data is first made available function initializeCharts() { @@ -417,6 +431,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var dotRadius = function(type) { var radius = prevChartWidth > WIDTH_BIG_DOTS ? 4 : (prevChartWidth < WIDTH_SMALL_DOTS ? 2 : 3); if (type == 'mbg') radius *= 2; + else if (type == 'rawbg') radius = Math.min(2, radius - 1); return radius; }; @@ -1309,9 +1324,32 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; latestSGV = d[0][d[0].length - 1]; prevSGV = d[0][d[0].length - 2]; } - data = d[0].map(function (obj) { + + treatments = d[3]; + treatments.forEach(function (d) { + d.created_at = new Date(d.created_at); + }); + + cal = d[5][d[5].length-1]; + + var temp1 = [ ]; + if (cal) { + temp1 = d[0].map(function (obj) { + var rawBg = rawIsigToRawBg(obj.unfiltered + , cal.scale || [ ] + , cal.intercept + , cal.slope || [ ] + , obj.filtered + , obj.y); + return { date: new Date(obj.x-2*1000), y: rawBg, sgv: scaleBg(rawBg), color: 'white', type: 'rawbg'} + }); + } + var temp2 = d[0].map(function (obj) { return { date: new Date(obj.x), y: obj.y, sgv: scaleBg(obj.y), direction: obj.direction, color: sgvToColor(obj.y), type: 'sgv'} }); + data = []; + data = data.concat(temp1, temp2); + // TODO: This is a kludge to advance the time as data becomes stale by making old predictor clear (using color = 'none') // This shouldn't have to be sent and can be fixed by using xScale.domain([x0,x1]) function with // 2 days before now as x0 and 30 minutes from now for x1 for context plot, but this will be @@ -1327,11 +1365,6 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; d.color = 'transparent'; }); - treatments = d[3]; - treatments.forEach(function (d) { - d.created_at = new Date(d.created_at); - }); - if (!isInitialData) { isInitialData = true; initializeCharts(); From ccd917aee58ae473bf2bd0c89523995507349e96 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 22:56:20 -0800 Subject: [PATCH 03/31] only show raw bg if enabled --- lib/api/index.js | 1 + lib/api/status.js | 1 + static/index.html | 4 ++++ static/js/client.js | 4 +++- static/js/ui-utils.js | 13 ++++++++++++- 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/api/index.js b/lib/api/index.js index 9325bd124ec..4c9f215f706 100644 --- a/lib/api/index.js +++ b/lib/api/index.js @@ -24,6 +24,7 @@ function create (env, entries, settings, treatments, devicestatus) { } if (env.enable) { + app.enabledOptions = env.enable; env.enable.toLowerCase().split(' ').forEach(function (value) { var enable = value.trim(); console.info("enabling feature:", enable); diff --git a/lib/api/status.js b/lib/api/status.js index 76d4de06f39..d1c038ad2d5 100644 --- a/lib/api/status.js +++ b/lib/api/status.js @@ -13,6 +13,7 @@ function configure (app, wares) { var info = { status: 'ok' , apiEnabled: app.enabled('api') , careportalEnabled: app.enabled('api') && app.enabled('careportal') + , enabledOptions: app.enabledOptions , units: app.get('units') , head: wares.get_head( ) , version: app.get('version') diff --git a/static/index.html b/static/index.html index 934fdf1ff11..6a07f4fcfde 100644 --- a/static/index.html +++ b/static/index.html @@ -85,6 +85,10 @@

Nightscout

Night Mode
+
+
Show Raw BG Data
+
+
Custom Title
diff --git a/static/js/client.js b/static/js/client.js index 9b4bee6b76a..51be8d570c9 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -1333,7 +1333,8 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; cal = d[5][d[5].length-1]; var temp1 = [ ]; - if (cal) { + if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg == true) { + console.info(">>>>browserSettings.showRawbg", browserSettings.showRawbg); temp1 = d[0].map(function (obj) { var rawBg = rawIsigToRawBg(obj.unfiltered , cal.scale || [ ] @@ -1446,6 +1447,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , version: xhr.version , head: xhr.head , apiEnabled: xhr.apiEnabled + , enabledOptions: xhr.enabledOptions , thresholds: xhr.thresholds , alarm_types: xhr.alarm_types , units: xhr.units diff --git a/static/js/ui-utils.js b/static/js/ui-utils.js index bdb15c0d427..e4d0f68e812 100644 --- a/static/js/ui-utils.js +++ b/static/js/ui-utils.js @@ -36,6 +36,7 @@ function getBrowserSettings(storage) { "alarmLow": storage.get("alarmLow"), "alarmUrgentLow": storage.get("alarmUrgentLow"), "nightMode": storage.get("nightMode"), + "showRawbg": storage.get("showRawbg") "customTitle": storage.get("customTitle"), "theme": storage.get("theme"), "timeFormat": storage.get("timeFormat") @@ -61,6 +62,15 @@ function getBrowserSettings(storage) { json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode); $("#nightmode-browser").prop("checked", json.nightMode); + if (app.enabledOptions.indexOf('rawbg') == -1) { + json.showRawbg = false; + $("#show-rawbg-option").hide(); + } else { + $("#show-rawbg-option").show(); + json.showRawbg = setDefault(json.showRawbg, (app.enabledOptions.indexOf('rawbg-on') > -1)); + $("#show-rawbg").prop("checked", json.showRawbg); + } + if (json.customTitle) { $("h1.customTitle").text(json.customTitle); $("input#customTitle").prop("value", json.customTitle); @@ -72,7 +82,7 @@ function getBrowserSettings(storage) { } else { $("#theme-default-browser").prop("checked", true); } - + json.timeFormat = setDefault(json.timeFormat, defaultSettings.timeFormat); if (json.timeFormat == "24") { @@ -348,6 +358,7 @@ $("input#save").click(function(event) { "alarmLow": $("#alarm-low-browser").prop("checked"), "alarmUrgentLow": $("#alarm-urgentlow-browser").prop("checked"), "nightMode": $("#nightmode-browser").prop("checked"), + "showRawbg": $("#show-rawbg").prop("checked"), "customTitle": $("input#customTitle").prop("value"), "theme": $("input:radio[name=theme-browser]:checked").val(), "timeFormat": $("input:radio[name=timeformat-browser]:checked").val() From beba8b037910569c2be22714059accee3c1e188b Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 22:59:52 -0800 Subject: [PATCH 04/31] fixed typo --- static/js/ui-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/ui-utils.js b/static/js/ui-utils.js index e4d0f68e812..c5896ce18bf 100644 --- a/static/js/ui-utils.js +++ b/static/js/ui-utils.js @@ -36,7 +36,7 @@ function getBrowserSettings(storage) { "alarmLow": storage.get("alarmLow"), "alarmUrgentLow": storage.get("alarmUrgentLow"), "nightMode": storage.get("nightMode"), - "showRawbg": storage.get("showRawbg") + "showRawbg": storage.get("showRawbg"), "customTitle": storage.get("customTitle"), "theme": storage.get("theme"), "timeFormat": storage.get("timeFormat") From 30f56f5cc9c2bc3d504b162aec770d6822fa7cc1 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 23:04:03 -0800 Subject: [PATCH 05/31] added new enable option to README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e402869fd33..d51ccefedfb 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Use the [autoconfigure tool][autoconfigure] to sync an uploader to your config. #### Features/Labs - * `ENABLE` - Used to enable optional features, currently supports: `careportal` + * `ENABLE` - Used to enable optional features, currently supports: `careportal`, `rawbg` (also `rawbg-on` to auto show raw) * `API_SECRET` - A secret passphrase that must be at least 12 characters long, required to enable `POST` and `PUT`; also required for the Care Portal * `BG_HIGH` (`260`) - must be set using mg/dl units; the high BG outside the target range that is considered urgent * `BG_TARGET_TOP` (`180`) - must be set using mg/dl units; the top of the target range, also used to draw the line on the chart From 3daa7d985776a32bab7e82768854bffbf49dba9f Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 23:24:53 -0800 Subject: [PATCH 06/31] inital support for send raw bg data with /pebble --- lib/pebble.js | 53 ++++++++++++++++++++++++++++++++------------------- server.js | 2 +- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index 8299623466d..298b171578d 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -20,8 +20,7 @@ function directionToTrend (direction) { } function pebble (req, res) { - var FORTY_MINUTES = 2400000; - var cgmData = [ ]; + var ONE_DAY = 24 * 60 * 60 * 1000; var uploaderBattery; function requestMetric() { @@ -42,6 +41,9 @@ function pebble (req, res) { function get_latest (err, results) { var now = Date.now(); + var sgvData = [ ]; + var calData = [ ]; + results.forEach(function(element, index, array) { var next = null; if (index + 1 < results.length) { @@ -49,25 +51,33 @@ function pebble (req, res) { } if (element) { var obj = {}; - if (!element.sgv) return; - 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; + if (element.sgv) { + 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.y = element.sgv; + // obj.x = element.date; + obj.datetime = element.date; + obj.battery = uploaderBattery ? "" + uploaderBattery : undefined; + if (req.rawbg) { + obj.filtered = element.filtered; + obj.unfiltered = element.unfiltered; + obj.rssi = element.rssi; + } + // obj.date = element.date.toString( ); + sgvData.push(obj); + } else if (req.rawbg && element.type == 'cal') { + calData.push(element); } - // obj.y = element.sgv; - // obj.x = element.date; - obj.datetime = element.date; - obj.battery = uploaderBattery ? "" + uploaderBattery : undefined; - // obj.date = element.date.toString( ); - cgmData.push(obj); } }); - var result = { status: [ {now:now}], bgs: cgmData.slice(0, 1) }; + var result = { status: [ {now:now}], bgs: sgvData.slice(0, 1), cals: calData.slice(0, 1) }; res.setHeader('content-type', 'application/json'); res.write(JSON.stringify(result)); res.end( ); @@ -80,13 +90,16 @@ function pebble (req, res) { console.error("req.devicestatus.tail", err); } - req.entries.list({count: 2, find: { "sgv": { $exists: true }}}, get_latest); + var earliest_data = Date.now() - ONE_DAY; + var q = { find: {"date": {"$gte": earliest_data}} }; + req.entries.list(q, get_latest); }); } -function configure (entries, devicestatus) { +function configure (entries, devicestatus, env) { function middle (req, res, next) { req.entries = entries; req.devicestatus = devicestatus; + req.rawbg = env.enable.indexOf('rawbg') > -1; next( ); } return [middle, pebble]; diff --git a/server.js b/server.js index 660540c3747..b1a5dd8b244 100644 --- a/server.js +++ b/server.js @@ -71,7 +71,7 @@ app.enable('trust proxy'); // Allows req.secure test on heroku https connections app.use('/api/v1', api); // pebble data -app.get('/pebble', pebble(entriesStorage, devicestatusStorage)); +app.get('/pebble', pebble(entriesStorage, devicestatusStorage, env)); //app.get('/package.json', software); From b267ee86e33df55211053da70875d3c10f43f10f Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 29 Jan 2015 23:59:31 -0800 Subject: [PATCH 07/31] fixed retro error code bug that showed LOW incorrectly --- static/js/client.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/static/js/client.js b/static/js/client.js index 51be8d570c9..9c8f9c21738 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -284,7 +284,9 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var prevfocusPoint = nowData[nowData.length - 2]; //in this case the SGV is scaled - if (focusPoint.y < 40) { + if (focusPoint.y < 39) { + $('.container .currentBG').text(''); + } else if (focusPoint.y == 39) { $('.container .currentBG').text('LOW'); } else if (focusPoint.y > 400) { $('.container .currentBG').text('HIGH'); From f2509cc82b82f4b86bfb99d2f7e961a81d281cca Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 30 Jan 2015 17:44:50 -0800 Subject: [PATCH 08/31] added noise data when rawbg is enabled --- lib/pebble.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pebble.js b/lib/pebble.js index 298b171578d..f511d58a5cf 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -68,6 +68,7 @@ function pebble (req, res) { if (req.rawbg) { obj.filtered = element.filtered; obj.unfiltered = element.unfiltered; + obj.noise = element.noise; obj.rssi = element.rssi; } // obj.date = element.date.toString( ); From 0828424fa681d8e17f8305353ad8abb1cd2b120f Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 30 Jan 2015 17:45:35 -0800 Subject: [PATCH 09/31] refactoring how error codes are sent and displayed --- lib/websocket.js | 16 ++---- static/js/client.js | 126 +++++++++++++++++++++----------------------- 2 files changed, 64 insertions(+), 78 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index b3fa785da58..bba9704c6b6 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -213,12 +213,6 @@ function loadData() { }); actualCurrent = actual.length > 0 ? actual[actual.length - 1].y : null; - - // sgv less than or equal to 10 means error code - // or warm up period code, so ignore - actual = actual.filter(function (a) { - return (a.y > 10 || a.unfiltered > 0); - }) } if (treatmentData) { @@ -275,8 +269,8 @@ function loadData() { //TODO: need to consider when data being sent has less than the 2 day minimum // consolidate and send the data to the client - var shouldEmit = is_different(actual, predicted, mbg, treatment, errorCode, cal); - patientData = [actual, predicted, mbg, treatment, errorCode, cal]; + var shouldEmit = is_different(actual, predicted, mbg, treatment, cal); + patientData = [actual, predicted, mbg, treatment, cal]; console.log('patientData', patientData.length); if (shouldEmit) { emitData( ); @@ -331,7 +325,7 @@ function loadData() { } } - function is_different (actual, predicted, mbg, treatment, errorCode) { + function is_different (actual, predicted, mbg, treatment, cal) { if (patientData && patientData.length < 3) { return true; } @@ -340,14 +334,14 @@ function loadData() { , predicted: patientData[1].slice(-1).pop( ) , mbg: patientData[2].slice(-1).pop( ) , treatment: patientData[3].slice(-1).pop( ) - , errorCode: patientData.length >= 5 ? patientData[4] : 0 + , cal: patientData[4].slice(-1).pop( ) }; var last = { actual: actual.slice(-1).pop( ) , predicted: predicted.slice(-1).pop( ) , mbg: mbg.slice(-1).pop( ) , treatment: treatment.slice(-1).pop( ) - , errorCode: errorCode + , cal: cal.slice(-1).pop( ) }; // textual diff of objects diff --git a/static/js/client.js b/static/js/client.js index 9c8f9c21738..e85571443d1 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -28,7 +28,6 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , latestSGV , latestUpdateTime , prevSGV - , errorCode , treatments , cal , padding = { top: 20, right: 10, bottom: 30, left: 10 } @@ -215,6 +214,27 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; return brushExtent[1].getTime() - THIRTY_MINS_IN_MS < now && elementHidden != true; } + function errorCodeToDisplay(errorCode) { + var errorDisplay; + + switch (parseInt(errorCode)) { + case 0: errorDisplay = '??0'; break; //None + case 1: errorDisplay = '?SN'; break; //SENSOR_NOT_ACTIVE + case 2: errorDisplay = '??2'; break; //MINIMAL_DEVIATION + case 3: errorDisplay = '?NA'; break; //NO_ANTENNA + case 5: errorDisplay = '?NC'; break; //SENSOR_NOT_CALIBRATED + case 6: errorDisplay = '?CD'; break; //COUNTS_DEVIATION + case 7: errorDisplay = '??7'; break; //? + case 8: errorDisplay = '??8'; break; //? + case 9: errorDisplay = '⌛'; break; //ABSOLUTE_DEVIATION + case 10: errorDisplay = '???'; break; //POWER_DEVIATION + case 12: errorDisplay = '?RF'; break; //BAD_RF + default: errorDisplay = '?' + parseInt(errorCode) + '?'; break; + } + + return errorDisplay; + } + // function to call when context chart is brushed function brushed(skipTimer) { @@ -285,8 +305,8 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; //in this case the SGV is scaled if (focusPoint.y < 39) { - $('.container .currentBG').text(''); - } else if (focusPoint.y == 39) { + $('.container .currentBG').html(errorCodeToDisplay(focusPoint.y)); + } else if (focusPoint.y < 40) { $('.container .currentBG').text('LOW'); } else if (focusPoint.y > 400) { $('.container .currentBG').text('HIGH'); @@ -314,7 +334,12 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; $('.container .currentDelta') .text(retroDeltaString) .css('text-decoration','line-through'); - $('.container .currentDirection').html(focusPoint.direction) + + if (focusPoint.y < 39) { + $('.container .currentDirection').html('✖'); + } else { + $('.container .currentDirection').html(focusPoint.direction) + } } else { $('.container .currentBG') .text('---') @@ -346,38 +371,33 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; updateClockDisplay(); - if (errorCode) { - var errorDisplay; - - switch (parseInt(errorCode)) { - case 0: errorDisplay = '??0'; break; //None - case 1: errorDisplay = '?SN'; break; //SENSOR_NOT_ACTIVE - case 2: errorDisplay = '??2'; break; //MINIMAL_DEVIATION - case 3: errorDisplay = '?NA'; break; //NO_ANTENNA - case 5: errorDisplay = '?NC'; break; //SENSOR_NOT_CALIBRATED - case 6: errorDisplay = '?CD'; break; //COUNTS_DEVIATION - case 7: errorDisplay = '??7'; break; //? - case 8: errorDisplay = '??8'; break; //? - case 9: errorDisplay = '⌛'; break; //ABSOLUTE_DEVIATION - case 10: errorDisplay = '???'; break; //POWER_DEVIATION - case 12: errorDisplay = '?RF'; break; //BAD_RF - default: errorDisplay = '?' + parseInt(errorCode) + '?'; break; - } + var bgDelta = scaleBg(latestSGV.y) - scaleBg(prevSGV.y); + if (browserSettings.units == 'mmol') { + bgDelta = bgDelta.toFixed(1); + } - $('#lastEntry').text('CGM ERROR').removeClass('current').addClass('urgent'); + var bgDeltaString = bgDelta; + if (bgDelta >= 0) { + bgDeltaString = '+' + bgDelta; + } - $('.container .currentBG').html(errorDisplay) - .css('text-decoration', ''); - $('.container .currentDelta').text('') - .css('text-decoration',''); - $('.container .currentDirection').html('✖'); + if (browserSettings.units == 'mmol') { + bgDeltaString = bgDeltaString + ' mmol/L' + } else { + bgDeltaString = bgDeltaString + ' mg/dL' + } - var color = sgvToColor(errorCode); - $('.container #noButton .currentBG').css({color: color}); - $('.container #noButton .currentDirection').css({color: color}); + $('.container .currentBG').css('text-decoration', ''); - } else { + if (latestSGV.y < 39) { + bgDeltaString = ""; + + $('#lastEntry').text('CGM ERROR').removeClass('current').addClass('urgent'); + $('.container .currentBG').html(errorCodeToDisplay(latestSGV.y)); + $('.container .currentDelta').text('').css('text-decoration',''); + $('.container .currentDirection').html('✖'); + } else { updateTimeAgo(); //in this case the SGV is unscaled if (latestSGV.y < 40) { @@ -387,41 +407,16 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; } else { $('.container .currentBG').text(scaleBg(latestSGV.y)); } - - var bgDelta = scaleBg(latestSGV.y) - scaleBg(prevSGV.y); - if (browserSettings.units == 'mmol') { - bgDelta = bgDelta.toFixed(1); - } - - var bgDeltaString = bgDelta; - if (bgDelta >= 0) { - bgDeltaString = '+' + bgDelta; - } - - if (browserSettings.units == 'mmol') { - bgDeltaString = bgDeltaString + ' mmol/L' - } else { - bgDeltaString = bgDeltaString + ' mg/dL' - } - - $('.container .currentBG').css('text-decoration', ''); - $('.container .currentDelta') - .text(bgDeltaString) - .css('text-decoration',''); $('.container .currentDirection').html(latestSGV.direction); + } - var color = sgvToColor(latestSGV.y); - $('.container #noButton .currentBG').css({color: color}); - $('.container #noButton .currentDirection').css({color: color}); - - // bgDelta and retroDelta to follow sgv color - // instead of Scott Leibrand's wip/iob-cob settings below + $('.container .currentDelta').text(bgDeltaString).css('text-decoration',''); - // var deltaColor = deltaToColor(bgDelta); - // $('.container #noButton .currentDelta').css({color: deltaColor}); + var color = sgvToColor(latestSGV.y); + $('.container #noButton .currentBG').css({color: color}); + $('.container #noButton .currentDirection').css({color: color}); - $('.container #noButton .currentDelta').css({color: color}); - } + $('.container #noButton .currentDelta').css({color: color}); } xScale.domain(brush.extent()); @@ -1318,8 +1313,6 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; socket.on('sgv', function (d) { if (d.length > 1) { - errorCode = d.length >= 5 ? d[4] : undefined; - // change the next line so that it uses the prediction if the signal gets lost (max 1/2 hr) if (d[0].length) { latestUpdateTime = Date.now(); @@ -1332,11 +1325,10 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; d.created_at = new Date(d.created_at); }); - cal = d[5][d[5].length-1]; + cal = d[4][d[4].length-1]; var temp1 = [ ]; if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg == true) { - console.info(">>>>browserSettings.showRawbg", browserSettings.showRawbg); temp1 = d[0].map(function (obj) { var rawBg = rawIsigToRawBg(obj.unfiltered , cal.scale || [ ] @@ -1394,7 +1386,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; //with predicted alarms, latestSGV may still be in target so to see if the alarm // is for a LOW we can only check if it's <= the top of the target function isAlarmForLow() { - return !!errorCode || latestSGV.y <= app.thresholds.bg_target_top; + return latestSGV.y <= app.thresholds.bg_target_top; } socket.on('alarm', function () { From 60ef5bd0f0bf343a850bfb014d405d6456f0ef43 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 30 Jan 2015 18:13:44 -0800 Subject: [PATCH 10/31] fixed bg delta bug, and added support for optional count param that can be used to get more data --- lib/pebble.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/pebble.js b/lib/pebble.js index f511d58a5cf..641c1587ef6 100644 --- a/lib/pebble.js +++ b/lib/pebble.js @@ -45,13 +45,16 @@ function pebble (req, res) { var calData = [ ]; results.forEach(function(element, index, array) { - var next = null; - if (index + 1 < results.length) { - next = results[index + 1]; - } 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) { @@ -61,10 +64,7 @@ function pebble (req, res) { obj.trend = directionToTrend(element.direction); obj.direction = element.direction; } - // obj.y = element.sgv; - // obj.x = element.date; obj.datetime = element.date; - obj.battery = uploaderBattery ? "" + uploaderBattery : undefined; if (req.rawbg) { obj.filtered = element.filtered; obj.unfiltered = element.unfiltered; @@ -78,7 +78,14 @@ function pebble (req, res) { } } }); - var result = { status: [ {now:now}], bgs: sgvData.slice(0, 1), cals: calData.slice(0, 1) }; + + var count = parseInt(req.query.count) || 1; + + var bgs = sgvData.slice(0, count); + //for compatibility we're keeping battery here, but it would be better somewhere else + bgs[0].battery = uploaderBattery ? "" + uploaderBattery : undefined; + + var result = { status: [ {now:now}], bgs: bgs, cals: calData.slice(0, count) }; res.setHeader('content-type', 'application/json'); res.write(JSON.stringify(result)); res.end( ); From 1c723b364e89aed629c6382f708fd1b5e7a25943 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 31 Jan 2015 09:49:47 -0800 Subject: [PATCH 11/31] simple test to make sure the /status.json endpoint handles the enable options correctly --- tests/api.status.test.js | 42 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/api.status.test.js diff --git a/tests/api.status.test.js b/tests/api.status.test.js new file mode 100644 index 00000000000..f6a811d0f54 --- /dev/null +++ b/tests/api.status.test.js @@ -0,0 +1,42 @@ + +var request = require('supertest'); +var should = require('should'); + +describe('Status REST api', function ( ) { + var api = require('../lib/api/'); + before(function (done) { + var env = require('../env')( ); + env.enable = "careportal rawbg"; + env.api_secret = 'this is my long pass phrase'; + this.wares = require('../lib/middleware/')(env); + var store = require('../lib/storage')(env); + this.app = require('express')( ); + this.app.enable('api'); + var self = this; + store(function ( ) { + var entriesStorage = require('../lib/entries').storage(env.mongo_collection, store); + self.app.use('/api', api(env, entriesStorage)); + done(); + }); + }); + + it('should be a module', function ( ) { + api.should.be.ok; + + }); + + it('/status.json', function (done) { + request(this.app) + .get('/api/status.json') + .expect(200) + .end(function (err, res) { + res.body.apiEnabled.should.equal(true); + res.body.careportalEnabled.should.equal(true); + res.body.enabledOptions.should.equal('careportal rawbg'); + done( ); + }); + }); + + +}); + From 9c1018490a69e4af5b7dffae8a598fad1bc296bf Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 31 Jan 2015 10:42:41 -0800 Subject: [PATCH 12/31] clean up --- tests/api.status.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/api.status.test.js b/tests/api.status.test.js index f6a811d0f54..dc6cfbd9f4b 100644 --- a/tests/api.status.test.js +++ b/tests/api.status.test.js @@ -22,7 +22,6 @@ describe('Status REST api', function ( ) { it('should be a module', function ( ) { api.should.be.ok; - }); it('/status.json', function (done) { From a689039fed5bf9146a20f6b6fb769dcd24c8e5d0 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 31 Jan 2015 10:43:03 -0800 Subject: [PATCH 13/31] tests for the /pebble endpoint --- tests/pebble.test.js | 168 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 tests/pebble.test.js diff --git a/tests/pebble.test.js b/tests/pebble.test.js new file mode 100644 index 00000000000..ea0f9c19e0f --- /dev/null +++ b/tests/pebble.test.js @@ -0,0 +1,168 @@ + +var request = require('supertest'); +var should = require('should'); + +//Mock entries +var entries = { + list: function(q, callback) { + var results = [ + { device: 'dexcom', + date: 1422727301000, + dateString: 'Sat Jan 31 10:01:41 PST 2015', + sgv: 82, + direction: 'Flat', + type: 'sgv', + filtered: 113984, + unfiltered: 111920, + rssi: 179, + noise: 1 + }, + { device: 'dexcom', + date: 1422647711000, + dateString: 'Fri Jan 30 11:55:11 PST 2015', + slope: 895.8571693029189, + intercept: 34281.06876195567, + scale: 1, + type: 'cal' + }, + { device: 'dexcom', + date: 1422727001000, + dateString: 'Sat Jan 31 09:56:41 PST 2015', + sgv: 84, + direction: 'Flat', + type: 'sgv', + filtered: 115680, + unfiltered: 113552, + rssi: 179, + noise: 1 + }, + { device: 'dexcom', + date: 1422726701000, + dateString: 'Sat Jan 31 09:51:41 PST 2015', + sgv: 86, + direction: 'Flat', + type: 'sgv', + filtered: 117808, + unfiltered: 114640, + rssi: 169, + noise: 1 + }, + { device: 'dexcom', + date: 1422726401000, + dateString: 'Sat Jan 31 09:46:41 PST 2015', + sgv: 88, + direction: 'Flat', + type: 'sgv', + filtered: 120464, + unfiltered: 116608, + rssi: 175, + noise: 1 + }, + { device: 'dexcom', + date: 1422726101000, + dateString: 'Sat Jan 31 09:41:41 PST 2015', + sgv: 91, + direction: 'Flat', + type: 'sgv', + filtered: 124048, + unfiltered: 118880, + rssi: 174, + noise: 1 + } + ]; + callback(null, results); + } +}; + +//Mock devicestatus +var devicestatus = { + last: function(callback) { + callback(null, {uploaderBattery: 100}); + } +}; + +describe('Pebble Endpoint without Raw', function ( ) { + var pebble = require('../lib/pebble'); + before(function (done) { + var env = require('../env')( ); + env.enable = ""; + this.app = require('express')( ); + this.app.enable('api'); + this.app.use('/pebble', pebble(entries, devicestatus, env)); + done(); + }); + + it('should be a module', function ( ) { + pebble.should.be.ok; + }); + + it('/pebble', function (done) { + request(this.app) + .get('/pebble?count=2') + .expect(200) + .end(function (err, res) { + var bgs = res.body.bgs; + bgs.length.should.equal(2); + var bg = bgs[0]; + bg.sgv.should.equal('82'); + bg.bgdelta.should.equal(-2); + bg.trend.should.equal(4); + bg.direction.should.equal('Flat'); + bg.datetime.should.equal(1422727301000); + (bg.filtered == null).should.be.true; + (bg.unfiltered == null).should.be.true; + (bg.noise == null).should.be.true; + (bg.rssi == null).should.be.true; + bg.battery.should.equal('100'); + + res.body.cals.length.should.equal(0); + done( ); + }); + }); +}); + + +describe('Pebble Endpoint with Raw', function ( ) { + var pebbleRaw = require('../lib/pebble'); + before(function (done) { + var envRaw = require('../env')( ); + envRaw.enable = "rawbg"; + this.appRaw = require('express')( ); + this.appRaw.enable('api'); + this.appRaw.use('/pebble', pebbleRaw(entries, devicestatus, envRaw)); + done(); + }); + + it('should be a module', function ( ) { + pebbleRaw.should.be.ok; + }); + + it('/pebble', function (done) { + request(this.appRaw) + .get('/pebble?count=2') + .expect(200) + .end(function (err, res) { + var bgs = res.body.bgs; + bgs.length.should.equal(2); + var bg = bgs[0]; + bg.sgv.should.equal('82'); + bg.bgdelta.should.equal(-2); + bg.trend.should.equal(4); + bg.direction.should.equal('Flat'); + bg.datetime.should.equal(1422727301000); + bg.filtered.should.equal(113984); + bg.unfiltered.should.equal(111920); + bg.noise.should.equal(1); + bg.rssi.should.equal(179); + bg.battery.should.equal('100'); + + res.body.cals.length.should.equal(1); + var cal = res.body.cals[0]; + cal.slope.should.equal(895.8571693029189); + cal.intercept.should.equal(34281.06876195567); + cal.scale.should.equal(1); + done( ); + }); + }); + +}); \ No newline at end of file From 30ee5f79f71b0a4e1c761e7352b3323108068914 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 31 Jan 2015 11:20:12 -0800 Subject: [PATCH 14/31] more status tests --- tests/api.status.test.js | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/api.status.test.js b/tests/api.status.test.js index dc6cfbd9f4b..c668bba9f2d 100644 --- a/tests/api.status.test.js +++ b/tests/api.status.test.js @@ -36,6 +36,37 @@ describe('Status REST api', function ( ) { }); }); + it('/status.html', function (done) { + request(this.app) + .get('/api/status.html') + .end(function(err, res) { + res.type.should.equal('text/html'); + res.statusCode.should.equal(200); + done() + }); + }); + + it('/status.js', function (done) { + request(this.app) + .get('/api/status.js') + .end(function(err, res) { + res.type.should.equal('application/javascript'); + res.statusCode.should.equal(200); + res.text.should.startWith('this.serverSettings ='); + done() + }); + }); + + it('/status.png', function (done) { + request(this.app) + .get('/api/status.png') + .end(function(err, res) { + res.headers.location.should.equal('http://img.shields.io/badge/Nightscout-OK-green.png'); + res.statusCode.should.equal(302); + done() + }); + }); + }); From 333125039f8cd28901e37ed625676a628a577211 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 31 Jan 2015 15:11:44 -0800 Subject: [PATCH 15/31] use cleaner should.not.exist syntax --- tests/pebble.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/pebble.test.js b/tests/pebble.test.js index ea0f9c19e0f..d86aa3b68f9 100644 --- a/tests/pebble.test.js +++ b/tests/pebble.test.js @@ -109,10 +109,10 @@ describe('Pebble Endpoint without Raw', function ( ) { bg.trend.should.equal(4); bg.direction.should.equal('Flat'); bg.datetime.should.equal(1422727301000); - (bg.filtered == null).should.be.true; - (bg.unfiltered == null).should.be.true; - (bg.noise == null).should.be.true; - (bg.rssi == null).should.be.true; + should.not.exist(bg.filtered); + should.not.exist(bg.unfiltered); + should.not.exist(bg.noise); + should.not.exist(bg.rssi); bg.battery.should.equal('100'); res.body.cals.length.should.equal(0); From 42d1636c377db549bf6630c422dba1c9c5922850 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 1 Feb 2015 19:25:58 -0800 Subject: [PATCH 16/31] support for new 3-way raw options; lots of reformatting to match client.js --- static/js/ui-utils.js | 481 +++++++++++++++++++++--------------------- 1 file changed, 244 insertions(+), 237 deletions(-) diff --git a/static/js/ui-utils.js b/static/js/ui-utils.js index c5896ce18bf..594dc99b730 100644 --- a/static/js/ui-utils.js +++ b/static/js/ui-utils.js @@ -1,23 +1,23 @@ -"use strict"; +'use strict'; var drawerIsOpen = false; var treatmentDrawerIsOpen = false; var defaultSettings = { - "units": "mg/dl", - "alarmUrgentHigh": true, - "alarmHigh": true, - "alarmLow": true, - "alarmUrgentLow": true, - "nightMode": false, - "theme": "default", - "timeFormat": "12" + 'units': 'mg/dl', + 'alarmUrgentHigh': true, + 'alarmHigh': true, + 'alarmLow': true, + 'alarmUrgentLow': true, + 'nightMode': false, + 'theme': 'default', + 'timeFormat': '12' }; function getBrowserSettings(storage) { - var json = {}; + var json = {}; function scaleBg(bg) { - if (json.units == "mmol") { + if (json.units == 'mmol') { return (Math.round((bg / 18) * 10) / 10).toFixed(1); } else { return bg; @@ -29,81 +29,86 @@ function getBrowserSettings(storage) { } try { - var json = { - "units": storage.get("units"), - "alarmUrgentHigh": storage.get("alarmUrgentHigh"), - "alarmHigh": storage.get("alarmHigh"), - "alarmLow": storage.get("alarmLow"), - "alarmUrgentLow": storage.get("alarmUrgentLow"), - "nightMode": storage.get("nightMode"), - "showRawbg": storage.get("showRawbg"), - "customTitle": storage.get("customTitle"), - "theme": storage.get("theme"), - "timeFormat": storage.get("timeFormat") - }; - - // Default browser units to server units if undefined. - json.units = setDefault(json.units, app.units); - if (json.units == "mmol") { - $("#mmol-browser").prop("checked", true); - } else { - $("#mgdl-browser").prop("checked", true); - } + var json = { + 'units': storage.get('units'), + 'alarmUrgentHigh': storage.get('alarmUrgentHigh'), + 'alarmHigh': storage.get('alarmHigh'), + 'alarmLow': storage.get('alarmLow'), + 'alarmUrgentLow': storage.get('alarmUrgentLow'), + 'nightMode': storage.get('nightMode'), + 'showRawbg': storage.get('showRawbg'), + 'customTitle': storage.get('customTitle'), + 'theme': storage.get('theme'), + 'timeFormat': storage.get('timeFormat') + }; + + // Default browser units to server units if undefined. + json.units = setDefault(json.units, app.units); + if (json.units == 'mmol') { + $('#mmol-browser').prop('checked', true); + } else { + $('#mgdl-browser').prop('checked', true); + } json.alarmUrgentHigh = setDefault(json.alarmUrgentHigh, defaultSettings.alarmUrgentHigh); - json.alarmHigh = setDefault(json.alarmHigh, defaultSettings.alarmHigh); - json.alarmLow = setDefault(json.alarmLow, defaultSettings.alarmLow); - json.alarmUrgentLow = setDefault(json.alarmUrgentLow, defaultSettings.alarmUrgentLow); - $("#alarm-urgenthigh-browser").prop("checked", json.alarmUrgentHigh).next().text('Urgent High Alarm' + appendThresholdValue(app.thresholds.bg_high)); - $("#alarm-high-browser").prop("checked", json.alarmHigh).next().text('High Alarm' + appendThresholdValue(app.thresholds.bg_target_top)); - $("#alarm-low-browser").prop("checked", json.alarmLow).next().text('Low Alarm' + appendThresholdValue(app.thresholds.bg_target_bottom)); - $("#alarm-urgentlow-browser").prop("checked", json.alarmUrgentLow).next().text('Urgent Low Alarm' + appendThresholdValue(app.thresholds.bg_low)); + json.alarmHigh = setDefault(json.alarmHigh, defaultSettings.alarmHigh); + json.alarmLow = setDefault(json.alarmLow, defaultSettings.alarmLow); + json.alarmUrgentLow = setDefault(json.alarmUrgentLow, defaultSettings.alarmUrgentLow); + $('#alarm-urgenthigh-browser').prop('checked', json.alarmUrgentHigh).next().text('Urgent High Alarm' + appendThresholdValue(app.thresholds.bg_high)); + $('#alarm-high-browser').prop('checked', json.alarmHigh).next().text('High Alarm' + appendThresholdValue(app.thresholds.bg_target_top)); + $('#alarm-low-browser').prop('checked', json.alarmLow).next().text('Low Alarm' + appendThresholdValue(app.thresholds.bg_target_bottom)); + $('#alarm-urgentlow-browser').prop('checked', json.alarmUrgentLow).next().text('Urgent Low Alarm' + appendThresholdValue(app.thresholds.bg_low)); - json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode); - $("#nightmode-browser").prop("checked", json.nightMode); + json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode); + $('#nightmode-browser').prop('checked', json.nightMode); if (app.enabledOptions.indexOf('rawbg') == -1) { json.showRawbg = false; - $("#show-rawbg-option").hide(); + $('#show-rawbg-option').hide(); } else { - $("#show-rawbg-option").show(); - json.showRawbg = setDefault(json.showRawbg, (app.enabledOptions.indexOf('rawbg-on') > -1)); - $("#show-rawbg").prop("checked", json.showRawbg); + $('#show-rawbg-option').show(); + if (json.showRawbg === false) { + json.showRawbg = 'never'; + } else if (json.showRawbg === true) { + json.showRawbg = 'noise'; + } + json.showRawbg = setDefault(json.showRawbg, (app.enabledOptions.indexOf('rawbg-on') > -1 ? 'noise' : 'never')); + $('#show-rawbg-' + json.showRawbg).prop('checked', true); } - if (json.customTitle) { - $("h1.customTitle").text(json.customTitle); - $("input#customTitle").prop("value", json.customTitle); - document.title = "Nightscout: " + json.customTitle; - } + if (json.customTitle) { + $('h1.customTitle').text(json.customTitle); + $('input#customTitle').prop('value', json.customTitle); + document.title = 'Nightscout: ' + json.customTitle; + } - if (json.theme == "colors") { - $("#theme-colors-browser").prop("checked", true); + if (json.theme == 'colors') { + $('#theme-colors-browser').prop('checked', true); } else { - $("#theme-default-browser").prop("checked", true); + $('#theme-default-browser').prop('checked', true); } - json.timeFormat = setDefault(json.timeFormat, defaultSettings.timeFormat); - - if (json.timeFormat == "24") { - $("#24-browser").prop("checked", true); - } else { - $("#12-browser").prop("checked", true); - } - } - catch(err) { + json.timeFormat = setDefault(json.timeFormat, defaultSettings.timeFormat); + + if (json.timeFormat == '24') { + $('#24-browser').prop('checked', true); + } else { + $('#12-browser').prop('checked', true); + } + } + catch(err) { console.error(err); - showLocalstorageError(); - } + showLocalstorageError(); + } - return json; + return json; } function setDefault(variable, defaultValue) { - if (typeof(variable) === "object") { - return defaultValue; - } - return variable; + if (typeof(variable) === 'object') { + return defaultValue; + } + return variable; } function storeInBrowser(data) { @@ -117,125 +122,127 @@ function storeInBrowser(data) { } function getQueryParms() { - var params = {}; - if (location.search) { - location.search.substr(1).split("&").forEach(function(item) { - params[item.split("=")[0]] = item.split("=")[1].replace(/[_\+]/g, " "); - }); - } - return params; + var params = {}; + if (location.search) { + location.search.substr(1).split('&').forEach(function(item) { + params[item.split('=')[0]] = item.split('=')[1].replace(/[_\+]/g, ' '); + }); + } + return params; } function isTouch() { - try{ document.createEvent("TouchEvent"); return true; } - catch(e){ return false; } + try { document.createEvent('TouchEvent'); return true; } + catch (e) { return false; } } function closeDrawer(callback) { - $("#container").animate({marginLeft: "0px"}, 300, callback); - $("#chartContainer").animate({marginLeft: "0px"}, 300); - $("#drawer").animate({right: "-300px"}, 300, function() { - $("#drawer").css("display", "none"); - }); - drawerIsOpen = false; + $('#container').animate({marginLeft: '0px'}, 300, callback); + $('#chartContainer').animate({marginLeft: '0px'}, 300); + $('#drawer').animate({right: '-300px'}, 300, function() { + $('#drawer').css('display', 'none'); + }); + drawerIsOpen = false; } function openDrawer() { - drawerIsOpen = true; - $("#container").animate({marginLeft: "-300px"}, 300); - $("#chartContainer").animate({marginLeft: "-300px"}, 300); - $("#drawer").css("display", "block").animate({right: "0"}, 300); + drawerIsOpen = true; + $('#container').animate({marginLeft: '-300px'}, 300); + $('#chartContainer').animate({marginLeft: '-300px'}, 300); + $('#drawer').css('display', 'block').animate({right: '0'}, 300); } function closeTreatmentDrawer(callback) { - $("#container").animate({marginLeft: "0px"}, 400, callback); - $("#chartContainer").animate({marginLeft: "0px"}, 400); - $("#treatmentDrawer").animate({right: "-300px"}, 400, function() { - $("#treatmentDrawer").css("display", "none"); - }); - treatmentDrawerIsOpen = false; + $('#container').animate({marginLeft: '0px'}, 400, callback); + $('#chartContainer').animate({marginLeft: '0px'}, 400); + $('#treatmentDrawer').animate({right: '-300px'}, 400, function() { + $('#treatmentDrawer').css('display', 'none'); + }); + treatmentDrawerIsOpen = false; } + function openTreatmentDrawer() { - treatmentDrawerIsOpen = true; - $("#container").animate({marginLeft: "-300px"}, 400); - $("#chartContainer").animate({marginLeft: "-300px"}, 400); - $("#treatmentDrawer").css("display", "block").animate({right: "0"}, 400); - - $('#eventType').val('BG Check').focus(); - $('#glucoseValue').val('').attr('placeholder', 'Value in ' + browserSettings.units); - $('#meter').prop('checked', true); - $('#carbsGiven').val(''); - $('#insulinGiven').val(''); - $('#preBolus').val(0); - $('#notes').val(''); - $('#enteredBy').val(browserStorage.get("enteredBy") || ''); - $("#nowtime").prop('checked', true); - $('#eventTimeValue').val(currentTime()); + treatmentDrawerIsOpen = true; + $('#container').animate({marginLeft: '-300px'}, 400); + $('#chartContainer').animate({marginLeft: '-300px'}, 400); + $('#treatmentDrawer').css('display', 'block').animate({right: '0'}, 400); + + $('#eventType').val('BG Check').focus(); + $('#glucoseValue').val('').attr('placeholder', 'Value in ' + browserSettings.units); + $('#meter').prop('checked', true); + $('#carbsGiven').val(''); + $('#insulinGiven').val(''); + $('#preBolus').val(0); + $('#notes').val(''); + $('#enteredBy').val(browserStorage.get('enteredBy') || ''); + $('#nowtime').prop('checked', true); + $('#eventTimeValue').val(currentTime()); } function currentTime() { - var now = new Date(); - var hours = now.getHours(); - var minutes = now.getMinutes(); + var now = new Date(); + var hours = now.getHours(); + var minutes = now.getMinutes(); - if (hours<10) hours = "0" + hours; - if (minutes<10) minutes = "0" + minutes; + if (hours<10) hours = '0' + hours; + if (minutes<10) minutes = '0' + minutes; - return ""+ hours + ":" + minutes; + return ''+ hours + ':' + minutes; } function formatTime(date) { - var hours = date.getHours(); - var minutes = date.getMinutes(); - var ampm = hours >= 12 ? 'pm' : 'am'; - hours = hours % 12; - hours = hours ? hours : 12; // the hour '0' should be '12' - minutes = minutes < 10 ? '0' + minutes : minutes; - return hours + ':' + minutes + ' ' + ampm; + var hours = date.getHours(); + var minutes = date.getMinutes(); + var ampm = hours >= 12 ? 'pm' : 'am'; + hours = hours % 12; + hours = hours ? hours : 12; // the hour '0' should be '12' + minutes = minutes < 10 ? '0' + minutes : minutes; + return hours + ':' + minutes + ' ' + ampm; } function closeNotification() { - var notify = $("#notification"); - notify.hide(); - notify.find("span").html(""); + var notify = $('#notification'); + notify.hide(); + notify.find('span').html(''); } + function showNotification(note, type) { - var notify = $("#notification"); - notify.hide(); + var notify = $('#notification'); + notify.hide(); - // Notification types: "info", "warn", "success", "urgent". - // - default: "urgent" - notify.removeClass("info warn urgent"); - notify.addClass(type ? type : "urgent"); + // Notification types: 'info', 'warn', 'success', 'urgent'. + // - default: 'urgent' + notify.removeClass('info warn urgent'); + notify.addClass(type ? type : 'urgent'); - notify.find("span").html(note); - notify.css("left", "calc(50% - " + (notify.width() / 2) + "px)"); - notify.show(); + notify.find('span').html(note); + notify.css('left', 'calc(50% - ' + (notify.width() / 2) + 'px)'); + notify.show(); } function showLocalstorageError() { - var msg = "Settings are disabled.

Please enable cookies so you may customize your Nightscout site." - $(".browserSettings").html("Settings"+msg+""); - $("#save").hide(); + var msg = 'Settings are disabled.

Please enable cookies so you may customize your Nightscout site.' + $('.browserSettings').html('Settings'+msg+''); + $('#save').hide(); } function treatmentSubmit(event) { var data = {}; - data.enteredBy = document.getElementById("enteredBy").value; - data.eventType = document.getElementById("eventType").value; - data.glucose = document.getElementById("glucoseValue").value; + data.enteredBy = document.getElementById('enteredBy').value; + data.eventType = document.getElementById('eventType').value; + data.glucose = document.getElementById('glucoseValue').value; data.glucoseType = $('#treatment-form input[name=glucoseType]:checked').val(); - data.carbs = document.getElementById("carbsGiven").value; - data.insulin = document.getElementById("insulinGiven").value; - data.preBolus = document.getElementById("preBolus").value; - data.notes = document.getElementById("notes").value; + data.carbs = document.getElementById('carbsGiven').value; + data.insulin = document.getElementById('insulinGiven').value; + data.preBolus = document.getElementById('preBolus').value; + data.notes = document.getElementById('notes').value; var eventTimeDisplay = ''; - if ($('#treatment-form input[name=nowOrOther]:checked').val() != "now") { - var value = document.getElementById("eventTimeValue").value; + if ($('#treatment-form input[name=nowOrOther]:checked').val() != 'now') { + var value = document.getElementById('eventTimeValue').value; var eventTimeParts = value.split(':'); data.eventTime = new Date(); data.eventTime.setHours(eventTimeParts[0]); @@ -245,7 +252,7 @@ function treatmentSubmit(event) { eventTimeDisplay = formatTime(data.eventTime); } - var dataJson = JSON.stringify(data, null, " "); + var dataJson = JSON.stringify(data, null, ' '); var ok = window.confirm( 'Please verify that the data entered is correct: ' + @@ -261,11 +268,11 @@ function treatmentSubmit(event) { if (ok) { var xhr = new XMLHttpRequest(); - xhr.open("POST", "/api/v1/treatments/", true); + xhr.open('POST', '/api/v1/treatments/', true); xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8'); xhr.send(dataJson); - browserStorage.set("enteredBy", data.enteredBy); + browserStorage.set('enteredBy', data.enteredBy); closeTreatmentDrawer(); } @@ -279,121 +286,121 @@ function treatmentSubmit(event) { var querystring = getQueryParms(); function Dropdown(el) { - this.ddmenuitem = 0; + this.ddmenuitem = 0; - this.$el = $(el); - var that = this; + this.$el = $(el); + var that = this; - $(document).click(function() { that.close(); }); + $(document).click(function() { that.close(); }); } Dropdown.prototype.close = function () { - if (this.ddmenuitem) { - this.ddmenuitem.css('visibility', 'hidden'); - this.ddmenuitem = 0; - } + if (this.ddmenuitem) { + this.ddmenuitem.css('visibility', 'hidden'); + this.ddmenuitem = 0; + } }; Dropdown.prototype.open = function (e) { - this.close(); - this.ddmenuitem = $(this.$el).css('visibility', 'visible'); - e.stopPropagation(); + this.close(); + this.ddmenuitem = $(this.$el).css('visibility', 'visible'); + e.stopPropagation(); }; -$("#drawerToggle").click(function(event) { +$('#drawerToggle').click(function(event) { //close other drawers if(treatmentDrawerIsOpen) { - closeTreatmentDrawer(); - treatmentDrawerIsOpen = false; - } - - if(drawerIsOpen) { - closeDrawer(); - drawerIsOpen = false; - } else { - openDrawer(); - drawerIsOpen = true; - } - event.preventDefault(); + closeTreatmentDrawer(); + treatmentDrawerIsOpen = false; + } + + if(drawerIsOpen) { + closeDrawer(); + drawerIsOpen = false; + } else { + openDrawer(); + drawerIsOpen = true; + } + event.preventDefault(); }); -$("#treatmentDrawerToggle").click(function(event) { +$('#treatmentDrawerToggle').click(function(event) { //close other drawers if(drawerIsOpen) { - closeDrawer(); - drawerIsOpen = false; - } - - if(treatmentDrawerIsOpen) { - closeTreatmentDrawer(); - treatmentDrawerIsOpen = false; - } else { - openTreatmentDrawer(); - treatmentDrawerIsOpen = true; - } - event.preventDefault(); + closeDrawer(); + drawerIsOpen = false; + } + + if(treatmentDrawerIsOpen) { + closeTreatmentDrawer(); + treatmentDrawerIsOpen = false; + } else { + openTreatmentDrawer(); + treatmentDrawerIsOpen = true; + } + event.preventDefault(); }); -$("#treatmentDrawer").find("button").click(treatmentSubmit); +$('#treatmentDrawer').find('button').click(treatmentSubmit); -$("#eventTime input:radio").change(function (){ - if ($("#othertime").attr("checked")) { - $("#eventTimeValue").focus(); - } +$('#eventTime input:radio').change(function (){ + if ($('#othertime').attr('checked')) { + $('#eventTimeValue').focus(); + } }); -$("#eventTimeValue").focus(function () { - $("#othertime").attr("checked", "checked"); +$('#eventTimeValue').focus(function () { + $('#othertime').attr('checked', 'checked'); }); -$("#notification").click(function(event) { - closeNotification(); - event.preventDefault(); +$('#notification').click(function(event) { + closeNotification(); + event.preventDefault(); }); -$("input#save").click(function(event) { - storeInBrowser({ - "units": $("input:radio[name=units-browser]:checked").val(), - "alarmUrgentHigh": $("#alarm-urgenthigh-browser").prop("checked"), - "alarmHigh": $("#alarm-high-browser").prop("checked"), - "alarmLow": $("#alarm-low-browser").prop("checked"), - "alarmUrgentLow": $("#alarm-urgentlow-browser").prop("checked"), - "nightMode": $("#nightmode-browser").prop("checked"), - "showRawbg": $("#show-rawbg").prop("checked"), - "customTitle": $("input#customTitle").prop("value"), - "theme": $("input:radio[name=theme-browser]:checked").val(), - "timeFormat": $("input:radio[name=timeformat-browser]:checked").val() - }); - - event.preventDefault(); - - // reload for changes to take effect - // -- strip '#' so form submission does not fail - var url = window.location.href; - url = url.replace(/#$/, ""); - window.location = url; +$('input#save').click(function(event) { + storeInBrowser({ + 'units': $('input:radio[name=units-browser]:checked').val(), + 'alarmUrgentHigh': $('#alarm-urgenthigh-browser').prop('checked'), + 'alarmHigh': $('#alarm-high-browser').prop('checked'), + 'alarmLow': $('#alarm-low-browser').prop('checked'), + 'alarmUrgentLow': $('#alarm-urgentlow-browser').prop('checked'), + 'nightMode': $('#nightmode-browser').prop('checked'), + 'showRawbg': $('input:radio[name=show-rawbg]:checked').val(), + 'customTitle': $('input#customTitle').prop('value'), + 'theme': $('input:radio[name=theme-browser]:checked').val(), + 'timeFormat': $('input:radio[name=timeformat-browser]:checked').val() + }); + + event.preventDefault(); + + // reload for changes to take effect + // -- strip '#' so form submission does not fail + var url = window.location.href; + url = url.replace(/#$/, ''); + window.location = url; }); $(function() { - // Tooltips can remain in the way on touch screens. - var notTouchScreen = (!isTouch()); - if (notTouchScreen) { - $(".tip").tipsy(); - } else { - // Drawer info tips should be displayed on touchscreens. - $("#drawer").find(".tip").tipsy(); - } - $.fn.tipsy.defaults = { - fade: true, - gravity: "n", - opacity: 0.75 - } - - if (querystring.notify) { - showNotification(querystring.notify, querystring.notifytype); - } - - if (querystring.drawer) { - openDrawer(); - } + // Tooltips can remain in the way on touch screens. + var notTouchScreen = (!isTouch()); + if (notTouchScreen) { + $('.tip').tipsy(); + } else { + // Drawer info tips should be displayed on touchscreens. + $('#drawer').find('.tip').tipsy(); + } + $.fn.tipsy.defaults = { + fade: true, + gravity: 'n', + opacity: 0.75 + } + + if (querystring.notify) { + showNotification(querystring.notify, querystring.notifytype); + } + + if (querystring.drawer) { + openDrawer(); + } }); From 55e3451184fbb7080787fde6e6115d6309ed4866 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 1 Feb 2015 19:26:58 -0800 Subject: [PATCH 17/31] support for 3-way raw display: never, always, and only when there is noise (default) --- lib/websocket.js | 1 + static/index.html | 4 +++- static/js/client.js | 42 ++++++++++++++++++++++++------------------ 3 files changed, 28 insertions(+), 19 deletions(-) diff --git a/lib/websocket.js b/lib/websocket.js index bba9704c6b6..49d10bedbc4 100644 --- a/lib/websocket.js +++ b/lib/websocket.js @@ -167,6 +167,7 @@ function update() { 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) { diff --git a/static/index.html b/static/index.html index 6a07f4fcfde..64a94203b70 100644 --- a/static/index.html +++ b/static/index.html @@ -87,7 +87,9 @@

Nightscout

Show Raw BG Data
-
+
+
+
Custom Title
diff --git a/static/js/client.js b/static/js/client.js index e85571443d1..e569d5388b6 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -104,15 +104,26 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; } } - function rawIsigToRawBg(unfiltered, scale, intercept, slope, filtered, sgv) { - if (slope == 0 || unfiltered == 0 || scale ==0 || slope == null || unfiltered == null || scale == null) return 0; - else if (filtered == 0 || filtered == null || sgv < 30 || sgv == null) { + function rawIsigToRawBg(entry, cal) { + + var unfiltered = parseInt(entry.unfiltered) || 0 + , filtered = parseInt(entry.filtered) || 0 + , sgv = entry.y + , noise = entry.noise || 0 + , scale = parseFloat(cal.scale) || 0 + , intercept = parseFloat(cal.intercept) || 0 + , slope = parseFloat(cal.slope) || 0; + + if (slope == 0 || unfiltered == 0 || scale == 0) { + return 0; + } else if (noise < 2 && browserSettings.showRawbg != 'always') { + return 0; + } else if (filtered == 0 || sgv < 40) { console.info("Skipping ratio adjustment for SGV " + sgv); - return scale*(unfiltered-intercept)/slope; - } - else { - var ratio = scale*(filtered-intercept)/slope / sgv; - return scale*(unfiltered-intercept)/slope / ratio; + return scale * (unfiltered - intercept) / slope; + } else { + var ratio = scale * (filtered - intercept) / slope / sgv; + return scale * ( unfiltered - intercept) / slope / ratio; } } @@ -1328,16 +1339,11 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; cal = d[4][d[4].length-1]; var temp1 = [ ]; - if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg == true) { - temp1 = d[0].map(function (obj) { - var rawBg = rawIsigToRawBg(obj.unfiltered - , cal.scale || [ ] - , cal.intercept - , cal.slope || [ ] - , obj.filtered - , obj.y); - return { date: new Date(obj.x-2*1000), y: rawBg, sgv: scaleBg(rawBg), color: 'white', type: 'rawbg'} - }); + if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && (browserSettings.showRawbg == 'always' || browserSettings.showRawbg == 'noise')) { + temp1 = d[0].map(function (entry) { + var rawBg = rawIsigToRawBg(entry, cal); + return { date: new Date(entry.x - 2 * 1000), y: rawBg, sgv: scaleBg(rawBg), color: 'white', type: 'rawbg'} + }).filter(function(entry) { return entry.y > 0}); } var temp2 = d[0].map(function (obj) { return { date: new Date(obj.x), y: obj.y, sgv: scaleBg(obj.y), direction: obj.direction, color: sgvToColor(obj.y), type: 'sgv'} From 21a32d25cc7f78e245a6cd8b49e36c984943c3c3 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Wed, 4 Feb 2015 12:44:55 -0800 Subject: [PATCH 18/31] default enabledOptions to an empty string --- static/js/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/client.js b/static/js/client.js index e569d5388b6..5fb41d1731b 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -1447,7 +1447,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , version: xhr.version , head: xhr.head , apiEnabled: xhr.apiEnabled - , enabledOptions: xhr.enabledOptions + , enabledOptions: xhr.enabledOptions || '' , thresholds: xhr.thresholds , alarm_types: xhr.alarm_types , units: xhr.units From e2e0714aeb927bdd7f5877cb4ebbd6e6f32d5455 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Wed, 4 Feb 2015 17:04:55 -0800 Subject: [PATCH 19/31] added Noise level to the SGV tooltip when raw bg can be displayed --- static/js/client.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/static/js/client.js b/static/js/client.js index 5fb41d1731b..9c8eaa3bca1 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -246,6 +246,19 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; return errorDisplay; } + function noiseCodeToDisplay(noise) { + var display = 'Not Set'; + switch (parseInt(noise)) { + case 1: display = 'Clean'; break; + case 2: display = 'Light'; break; + case 3: display = 'Medium'; break; + case 4: display = 'Heavy'; break; + case 5: display = 'Unknown'; break; + } + + return display; + } + // function to call when context chart is brushed function brushed(skipTimer) { @@ -468,10 +481,16 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var device = d.device && d.device.toLowerCase(); var bgType = (d.type == 'sgv' ? 'CGM' : (device == 'dexcom' ? 'Calibration' : 'Meter')); + var noiseLabel = ''; + + if (app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg != 'never') { + noiseLabel = noiseCodeToDisplay(d.noise); + } tooltip.transition().duration(TOOLTIP_TRANS_MS).style('opacity', .9); tooltip.html('' + bgType + ' BG: ' + d.sgv + (d.type == 'mbg' ? '
Device: ' + d.device : '') + + (noiseLabel ? '
Noise: ' + noiseLabel : '') + '
Time: ' + formatTime(d.date)) .style('left', (d3.event.pageX) + 'px') .style('top', (d3.event.pageY - 28) + 'px'); @@ -1338,6 +1357,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; cal = d[4][d[4].length-1]; + var temp1 = [ ]; if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && (browserSettings.showRawbg == 'always' || browserSettings.showRawbg == 'noise')) { temp1 = d[0].map(function (entry) { @@ -1346,7 +1366,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; }).filter(function(entry) { return entry.y > 0}); } var temp2 = d[0].map(function (obj) { - return { date: new Date(obj.x), y: obj.y, sgv: scaleBg(obj.y), direction: obj.direction, color: sgvToColor(obj.y), type: 'sgv'} + return { date: new Date(obj.x), y: obj.y, sgv: scaleBg(obj.y), direction: obj.direction, color: sgvToColor(obj.y), type: 'sgv', noise: obj.noise} }); data = []; data = data.concat(temp1, temp2); From bebb5f7e1839186beb6ccd5622a0fa68bc45659e Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Thu, 5 Feb 2015 07:48:13 -0800 Subject: [PATCH 20/31] only show noise for sgv's --- static/js/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/js/client.js b/static/js/client.js index 9c8eaa3bca1..8de699cadbe 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -483,7 +483,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var bgType = (d.type == 'sgv' ? 'CGM' : (device == 'dexcom' ? 'Calibration' : 'Meter')); var noiseLabel = ''; - if (app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg != 'never') { + if (d.type == 'sgv' && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg != 'never') { noiseLabel = noiseCodeToDisplay(d.noise); } From e442ecfb81978a89b30a85d70162ed557455cf3b Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Fri, 6 Feb 2015 22:13:04 -0800 Subject: [PATCH 21/31] simplified css media queries; improved alarm display in portrait mode --- static/css/main.css | 20 +------------------- static/js/client.js | 4 ++-- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/static/css/main.css b/static/css/main.css index 39a356acf2f..2909bc1d778 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -161,7 +161,6 @@ body { cursor: default; font-size: 75%; margin-top: 15px; - margin-right: 37px; width: auto; user-select: none; @@ -246,9 +245,6 @@ div.tooltip { width: 50%; } - #bgButton { - font-size: 120%; - } .dropdown-menu { font-size: 60% !important; } @@ -258,9 +254,6 @@ div.tooltip { } @media (max-width: 750px) { - #bgButton { - font-size: 120%; - } .dropdown-menu { font-size: 60% !important; } @@ -284,10 +277,6 @@ div.tooltip { font-size: 70%; } - #notification { - margin-top: 148px; - } - .status { text-align: center; margin-bottom: 0; @@ -307,10 +296,7 @@ div.tooltip { width: 100vw; } #bgButton { - font-size: 120%; - height: 142px; - margin-top: 1vw; - width: 98vw; + font-size: 100%; } .dropdown-menu { font-size: 60% !important; @@ -365,10 +351,6 @@ div.tooltip { padding-bottom: 20px; } - #bgButton { - font-size: 70% !important; - } - #currentTime { font-size: 85%; } diff --git a/static/js/client.js b/static/js/client.js index 8de699cadbe..b1e7b14b186 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -17,7 +17,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , FORMAT_TIME_12 = '%I:%M' , FORMAT_TIME_24 = '%H:%M%' , FORMAT_TIME_SCALE = '%I %p' - , WIDTH_TIME_HIDDEN = 500 + , WIDTH_TIME_HIDDEN = 400 , WIDTH_SMALL_DOTS = WIDTH_TIME_HIDDEN , WIDTH_BIG_DOTS = 800 , MINUTES_SINCE_LAST_UPDATE_WARN = 10 @@ -982,7 +982,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; if (querystring.mute != 'true') { audio.play(); } else { - showNotification('Alarm is muted per your request. (?mute=true)'); + showNotification('Alarm was muted (?mute=true)'); } } From 8dd460a7413e930698124fa1a9b381f63b7b0aa2 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sat, 7 Feb 2015 23:21:23 -0800 Subject: [PATCH 22/31] fixed HIGH/LOW dispay on phablets; moved time hide/show from js to css --- static/css/main.css | 6 ++++++ static/js/client.js | 17 +++-------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/static/css/main.css b/static/css/main.css index 2909bc1d778..77be14605ae 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -243,6 +243,7 @@ div.tooltip { .bgStatus { width: 50%; + font-size: 650%; } .dropdown-menu { @@ -313,6 +314,11 @@ div.tooltip { margin-left: 0; width: 100%; } + + #container.alarming .time { + display: none; + } + .timebox { text-align: none; width: auto; diff --git a/static/js/client.js b/static/js/client.js index b1e7b14b186..c9b773d67ea 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -17,8 +17,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; , FORMAT_TIME_12 = '%I:%M' , FORMAT_TIME_24 = '%H:%M%' , FORMAT_TIME_SCALE = '%I %p' - , WIDTH_TIME_HIDDEN = 400 - , WIDTH_SMALL_DOTS = WIDTH_TIME_HIDDEN + , WIDTH_SMALL_DOTS = 400 , WIDTH_BIG_DOTS = 800 , MINUTES_SINCE_LAST_UPDATE_WARN = 10 , MINUTES_SINCE_LAST_UPDATE_URGENT = 20; @@ -289,14 +288,6 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; // get slice of data so that concatenation of predictions do not interfere with subsequent updates var focusData = data.slice(); - if (alarmInProgress) { - if (jqWindow.width() > WIDTH_TIME_HIDDEN) { - $('.time').show(); - } else { - $('.time').hide(); - } - } - var nowDate = new Date(brushExtent[1] - THIRTY_MINS_IN_MS); // predict for retrospective data @@ -970,11 +961,9 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; bgButton.toggleClass('urgent', file == urgentAlarmSound); var noButton = $('#noButton'); noButton.hide(); + $('#container').addClass('alarming'); $('.container .currentBG').text(); - if (jqWindow.width() <= WIDTH_TIME_HIDDEN) { - $('.time').hide(); - } } function playAlarm(audio) { @@ -998,7 +987,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; $(this).removeClass('playing'); }); - $('.time').show(); + $('#container').removeClass('alarming'); // only emit ack if client invoke by button press if (isClient) { From 506cdcd28ace4fecadc5e5b1ceca071b517b7a45 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 8 Feb 2015 00:02:53 -0800 Subject: [PATCH 23/31] cleaned up setting checks for showing raw BGs (will make merging with iob-cob cleaner too) --- lib/api/index.js | 2 +- static/js/client.js | 10 ++++++++-- static/js/ui-utils.js | 34 ++++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/lib/api/index.js b/lib/api/index.js index 4c9f215f706..13ccb4c57ce 100644 --- a/lib/api/index.js +++ b/lib/api/index.js @@ -24,7 +24,7 @@ function create (env, entries, settings, treatments, devicestatus) { } if (env.enable) { - app.enabledOptions = env.enable; + app.enabledOptions = env.enable || ''; env.enable.toLowerCase().split(' ').forEach(function (value) { var enable = value.trim(); console.info("enabling feature:", enable); diff --git a/static/js/client.js b/static/js/client.js index b1e7b14b186..7b47d2d3f6d 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -104,6 +104,12 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; } } + function showRawBGs() { + return app.enabledOptions + && app.enabledOptions.indexOf('rawbg' > -1) + && (browserSettings.showRawbg == 'always' || browserSettings.showRawbg == 'noise'); + } + function rawIsigToRawBg(entry, cal) { var unfiltered = parseInt(entry.unfiltered) || 0 @@ -483,7 +489,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var bgType = (d.type == 'sgv' ? 'CGM' : (device == 'dexcom' ? 'Calibration' : 'Meter')); var noiseLabel = ''; - if (d.type == 'sgv' && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && browserSettings.showRawbg != 'never') { + if (d.type == 'sgv' && showRawBGs()) { noiseLabel = noiseCodeToDisplay(d.noise); } @@ -1359,7 +1365,7 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var temp1 = [ ]; - if (cal && app.enabledOptions && app.enabledOptions.indexOf('rawbg' > -1) && (browserSettings.showRawbg == 'always' || browserSettings.showRawbg == 'noise')) { + if (cal && showRawBGs()) { temp1 = d[0].map(function (entry) { var rawBg = rawIsigToRawBg(entry, cal); return { date: new Date(entry.x - 2 * 1000), y: rawBg, sgv: scaleBg(rawBg), color: 'white', type: 'rawbg'} diff --git a/static/js/ui-utils.js b/static/js/ui-utils.js index 594dc99b730..a99f08a61ab 100644 --- a/static/js/ui-utils.js +++ b/static/js/ui-utils.js @@ -13,6 +13,25 @@ var defaultSettings = { 'timeFormat': '12' }; +function rawBGsEnabled() { + return app.enabledOptions && app.enabledOptions.indexOf('rawbg') > -1; +} + +function initShowRawBG(currentValue) { + + var initValue = 'never'; + + if (currentValue === true) { + initValue = 'noise'; + } else if (currentValue == 'never' || currentValue == 'always' || currentValue == 'noise') { + initValue = currentValue; + } else { + initValue = app.enabledOptions.indexOf('rawbg-on') > -1 ? 'noise' : 'never'; + } + + return initValue; +} + function getBrowserSettings(storage) { var json = {}; @@ -62,18 +81,13 @@ function getBrowserSettings(storage) { json.nightMode = setDefault(json.nightMode, defaultSettings.nightMode); $('#nightmode-browser').prop('checked', json.nightMode); - if (app.enabledOptions.indexOf('rawbg') == -1) { - json.showRawbg = false; - $('#show-rawbg-option').hide(); - } else { + if (rawBGsEnabled()) { $('#show-rawbg-option').show(); - if (json.showRawbg === false) { - json.showRawbg = 'never'; - } else if (json.showRawbg === true) { - json.showRawbg = 'noise'; - } - json.showRawbg = setDefault(json.showRawbg, (app.enabledOptions.indexOf('rawbg-on') > -1 ? 'noise' : 'never')); + json.showRawbg = initShowRawBG(json.showRawbg); $('#show-rawbg-' + json.showRawbg).prop('checked', true); + } else { + json.showRawbg = 'never'; + $('#show-rawbg-option').hide(); } if (json.customTitle) { From d9cdb4d9dac006f97715a5341903f027f5c0ae09 Mon Sep 17 00:00:00 2001 From: Trusties13 Date: Mon, 9 Feb 2015 10:04:03 +1100 Subject: [PATCH 24/31] Update index.html Resolve syntax error in settings panel. --- static/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/index.html b/static/index.html index 934fdf1ff11..c61dbc2697a 100644 --- a/static/index.html +++ b/static/index.html @@ -75,7 +75,7 @@

Nightscout

-
Enable Alarms
+
Enable Alarms
From f41a511ef3978d756b4c842bc71624563fec510e Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 8 Feb 2015 17:27:06 -0800 Subject: [PATCH 25/31] don't round the predicted values when mmol display mode --- static/js/client.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/static/js/client.js b/static/js/client.js index b1e7b14b186..8c84ea64e15 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -1169,6 +1169,15 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var BG_REF = scaleBg(140); var BG_MIN = scaleBg(36); var BG_MAX = scaleBg(400); + + function roundIfMgDl(value) { + if (browserSettings.units == 'mmol') { + return value; + } else { + return Math.round(value); + } + } + // these are the one sigma limits for the first 13 prediction interval uncertainties (65 minutes) var CONE = [0.020, 0.041, 0.061, 0.081, 0.099, 0.116, 0.132, 0.146, 0.159, 0.171, 0.182, 0.192, 0.201]; // these are modified to make the cone much blunter @@ -1203,13 +1212,13 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; // Add 2000 ms so not same point as SG predicted[i * 2] = { date: new Date(dt + 2000), - sgv: Math.max(BG_MIN, Math.min(BG_MAX, Math.round(BG_REF * Math.exp((y[1] - 2 * CONE[i]))))), + sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundIfMgDl(BG_REF * Math.exp((y[1] - 2 * CONE[i]))))), color: predictedColor }; // Add 4000 ms so not same point as SG predicted[i * 2 + 1] = { date: new Date(dt + 4000), - sgv: Math.max(BG_MIN, Math.min(BG_MAX, Math.round(BG_REF * Math.exp((y[1] + 2 * CONE[i]))))), + sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundIfMgDl(BG_REF * Math.exp((y[1] + 2 * CONE[i]))))), color: predictedColor }; predicted.forEach(function (d) { From 48fab43e10a8e6976522c315c34f61ff15ce1223 Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Sun, 8 Feb 2015 21:25:31 -0800 Subject: [PATCH 26/31] for mmol round predicted points to a single decimal place --- static/js/client.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/js/client.js b/static/js/client.js index 8c84ea64e15..b84b5b9f820 100644 --- a/static/js/client.js +++ b/static/js/client.js @@ -1170,9 +1170,9 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; var BG_MIN = scaleBg(36); var BG_MAX = scaleBg(400); - function roundIfMgDl(value) { + function roundByUnits(value) { if (browserSettings.units == 'mmol') { - return value; + return value.toFixed(1); } else { return Math.round(value); } @@ -1212,13 +1212,13 @@ var app = {}, browserSettings = {}, browserStorage = $.localStorage; // Add 2000 ms so not same point as SG predicted[i * 2] = { date: new Date(dt + 2000), - sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundIfMgDl(BG_REF * Math.exp((y[1] - 2 * CONE[i]))))), + sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundByUnits(BG_REF * Math.exp((y[1] - 2 * CONE[i]))))), color: predictedColor }; // Add 4000 ms so not same point as SG predicted[i * 2 + 1] = { date: new Date(dt + 4000), - sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundIfMgDl(BG_REF * Math.exp((y[1] + 2 * CONE[i]))))), + sgv: Math.max(BG_MIN, Math.min(BG_MAX, roundByUnits(BG_REF * Math.exp((y[1] + 2 * CONE[i]))))), color: predictedColor }; predicted.forEach(function (d) { From 99d6fe1a0fe869c98f55aa8754850985831f509c Mon Sep 17 00:00:00 2001 From: Sulka Haro Date: Tue, 10 Feb 2015 09:40:40 +0200 Subject: [PATCH 27/31] Store display units with treatment objects, for unit conversion / checking on load. --- static/js/ui-utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/js/ui-utils.js b/static/js/ui-utils.js index a99f08a61ab..4a5e9fcf8e3 100644 --- a/static/js/ui-utils.js +++ b/static/js/ui-utils.js @@ -253,6 +253,7 @@ function treatmentSubmit(event) { data.insulin = document.getElementById('insulinGiven').value; data.preBolus = document.getElementById('preBolus').value; data.notes = document.getElementById('notes').value; + data.units = browserSettings.units; var eventTimeDisplay = ''; if ($('#treatment-form input[name=nowOrOther]:checked').val() != 'now') { From 600eabcd2c3c339a3ba193646739b2dbbb97addc Mon Sep 17 00:00:00 2001 From: Jason Calabrese Date: Tue, 10 Feb 2015 00:23:02 -0800 Subject: [PATCH 28/31] toggle bg-limit and error-code on the currentBG and use that to adjust font size since HIGH/LOW can get too wide --- static/css/main.css | 13 ++- static/index.html | 4 +- static/js/client.js | 212 ++++++++++++++++++++------------------------ 3 files changed, 107 insertions(+), 122 deletions(-) diff --git a/static/css/main.css b/static/css/main.css index 77be14605ae..ed5ef975b4c 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -57,7 +57,16 @@ body { .bgStatus .currentBG { text-decoration: line-through; } -.bgStatus .currentDelta { + +.bgStatus .currentBG.error-code { + font-size: 80%; +} + +.bgStatus .currentBG.bg-limit { + font-size: 80%; +} + +.bgStatus .currentDetails { font-size: 25%; text-decoration: line-through; display: block; @@ -67,7 +76,7 @@ body { .bgStatus.current .currentBG { text-decoration: none; } -.bgStatus.current .currentDelta { +.bgStatus.current .currentDetails { font-size: 25%; text-decoration: none; display: block; diff --git a/static/index.html b/static/index.html index f0867b97383..50379422e7f 100644 --- a/static/index.html +++ b/static/index.html @@ -30,13 +30,13 @@

Nightscout

--- - - -- + --