Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions css/dropdown.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@
padding: 0;
position: absolute;
visibility: hidden;
right: 8px;
}

.dropdown-menu li {
list-style: none;
float: none;
display: inline
display: inline;
}

.dropdown-menu li a {
display: block;
padding: 5px 12px;
text-decoration: none;
white-space: nowrap;
width: auto;
background: #BBBBBB;
color: #24313C
color: #24313C;
padding: 2px 10px;
}

.dropdown-menu li a:hover {
Expand Down
27 changes: 21 additions & 6 deletions css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ body {
height: 100%;
}

#chartContainer svg {
width: 100%;
height: 100%;
}

.container {
overflow: hidden;
height: auto;
Expand Down Expand Up @@ -85,13 +90,16 @@ body {

.span1{width: 20%; float: left; padding-top: 3%; line-height: 50%;}

.span2{width: 40%; margin-left: 35%}
.span2{margin-left: 35%; float: right;}

.bgButton {
#noButton {
padding: 2px;
}

#bgButton {
background: #ff2035;
color: #000000;
width: auto;
margin: 3px auto;
border: 2px solid #DDD;
border-right: 2px solid #ccc;
border-bottom: 2px solid #ccc;
Expand All @@ -108,10 +116,11 @@ body {
-ms-user-select: none;
user-select: none;
cursor: default;
margin-right: 37px;
}

.bgButton:active {
margin: 10px auto;
background: #850406;
border: 2px solid #999;
box-shadow: none;
-moz-box-shadow: none;
Expand All @@ -124,6 +133,12 @@ body {
margin: 10px auto;
}

#silenceBtn {
font-size: 200%;
#silenceBtn, #silenceBtn * {
font-size: 70%;
}

#testAlarms {
font-size: 20%;
color: blue;
text-decoration: none;
}
25 changes: 13 additions & 12 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,20 @@
<body>
<div class='container'>
<div class='row-fluid heading'>
<div class='span1' style='font-size: 400%'>
<span id='currentTime'>???</span><br>
<span style='font-size: 35%'><span id='watchers'>0</span> watcher(s)</span>
<div class='span1' style='font-size: 600%'>
<div id='currentTime'>---</div>
<div style='font-size: 25%; line-height: 300%'>
<span id='lastEntry'>---</span>
</div>
</div>
<div class='span2'>
<div id='noButton' style='font-size: 800%'>
<span id='currentBG'>???</span>
<span style='font-size: 20%'>mg/dL</span>
<div class='span2 current' style='font-size: 900%'>
<div id='noButton'>
<span class='currentBG'>---</span>
<span class="currentDirection">-</span><a id="testAlarms" href="#">&#10003;&#9834;</a>
</div>
<div class='bgButton' id='bgButton' style='font-size: 800%' hidden='true'>
<span id='bgValue'>???</span>
<span style='font-size: 20%'>mg/dL</span>
<div id='bgButton' hidden='true'>
<span class='currentBG'>---</span>
<span class="currentDirection">-</span>
</div>
<ul class="dropdown-menu" id="silenceBtn">
<li><a href="#" data-snooze-time="1200000">Silence for 20 minutes</a></li>
Expand All @@ -35,8 +37,7 @@
<div id='chartContainer'></div>
</div>
</div>
<audio id='audio' loop><source src='audio/alarm.ogg' type='audio/ogg'/></audio>
<audio id='audio2' loop><source src='audio/alarm2.ogg' type='audio/ogg'/></audio>
<audio id='audio' loop src='audio/alarm.mp3' type='audio/mp3'></audio>
<script src='/socket.io/socket.io.js'></script>
<script src='/bower_components/d3/d3.min.js'></script>
<script src='/bower_components/jquery/dist/jquery.min.js'></script>
Expand Down
99 changes: 77 additions & 22 deletions js/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
"use strict";

var treatments,
padding = { top: 20, right: 10, bottom: 30, left: 10},
opacity = {current: 1, DAY: 1, NIGHT: 0.5},
padding = {top: 20, right: 10, bottom: 80, left: 10},
opacity = {current: 1, DAY: 1, NIGHT: 0.8},
now = Date.now(),
data = [],
dateFn = function (d) { return new Date(d.date)},
Expand All @@ -19,7 +19,13 @@
brushTimer,
brushInProgress = false,
clip,
FOCUS_DATA_RANGE_MS = 12600000; // 3.5 hours of actual data
FOCUS_DATA_RANGE_MS = 12600000, // 3.5 hours of actual data
audio = document.getElementById('audio'),
alarmInProgress = false,
currentAlarmType = null,
alarmSound = 'alarm.mp3',
urgentAlarmSound = 'alarm2.mp3';


// create svg and g to contain the chart contents
var charts = d3.select('#chartContainer').append('svg')
Expand Down Expand Up @@ -98,9 +104,9 @@
// get the desired opacity for context chart based on the brush extent
function highlightBrushPoints(data) {
if (data.date.getTime() >= brush.extent()[0].getTime() && data.date.getTime() <= brush.extent()[1].getTime()) {
return 1
return 1;
} else {
return 0.2
return 0.5;
}
}

Expand Down Expand Up @@ -574,8 +580,30 @@
if (d.length > 1) {
// change the next line so that it uses the prediction if the signal gets lost (max 1/2 hr)
if (d[0].length) {
$('#currentBG').text(d[0][d[0].length - 1].y);
$('#bgValue').text(d[0][d[0].length - 1].y);
var current = d[0][d[0].length - 1];
var secsSinceLast = (Date.now() - new Date(current.x).getTime()) / 1000;
var currentBG = current.y;

//TODO: currently these are filtered on the server
//TODO: use icons for these magic values
switch (current.y) {
case 0: currentBG = '??0'; break; //None
case 1: currentBG = '?SN'; break; //SENSOR_NOT_ACTIVE
case 2: currentBG = '??2'; break; //MINIMAL_DEVIATION
case 3: currentBG = '?NA'; break; //NO_ANTENNA
case 5: currentBG = '?NC'; break; //SENSOR_NOT_CALIBRATED
case 6: currentBG = '?CD'; break; //COUNTS_DEVIATION
case 7: currentBG = '??7'; break; //?
case 8: currentBG = '??8'; break; //?
case 9: currentBG = '?AD'; break; //ABSOLUTE_DEVIATION
case 10: currentBG = '?PD'; break; //POWER_DEVIATION
case 12: currentBG = '?RF'; break; //BAD_RF
}

$('#lastEntry').text(timeAgo(secsSinceLast)).toggleClass('current', secsSinceLast < 10 * 60);
$('.container .currentBG').text(currentBG);
$('.container .currentDirection').html(current.direction);
$('.container .current').toggleClass('high', current.y > 180).toggleClass('low', current.y < 70)
}
data = d[0].map(function (obj) { return { date: new Date(obj.x), sgv: obj.y, color: 'grey'} });
data = data.concat(d[1].map(function (obj) { return { date: new Date(obj.x), sgv: obj.y, color: 'blue'} }));
Expand Down Expand Up @@ -619,23 +647,26 @@
$('#watchers').text(watchers);
});

// load alarms
var alarmSound = document.getElementById('audio');
var urgentAlarmSound = document.getElementById('audio2');

// alarm state
var alarmInProgress = false;
var currentAlarmType = null;
$('#testAlarms').click(function(event) {
event.preventDefault();
audio.src = 'audio/alarm.mp3';
audio.load();
audio.play();
setTimeout(function() {
audio.pause();
}, 4000);
});

function generateAlarm(alarmType) {
function generateAlarm(file) {
alarmInProgress = true;
alarmType.load();
alarmType.play();
audio.src = 'audio/' + file;
audio.load();
audio.play();
var element = document.getElementById('bgButton');
element.hidden = '';
var element1 = document.getElementById('noButton');
element1.hidden = 'true';
$('#bgValue').text($('#currentBG').text());
$('.container .currentBG').text();
}

function stopAlarm(isClient, silenceTime) {
Expand All @@ -644,15 +675,39 @@
element.hidden = 'true';
element = document.getElementById('noButton');
element.hidden = '';
alarmSound.pause();
urgentAlarmSound.pause();
audio.pause();

// only emit ack if client invoke by button press
if (isClient) {
socket.emit('ack', currentAlarmType, silenceTime);
socket.emit('ack', currentAlarmType || 'alarm', silenceTime);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

function timeAgo(offset) {
var parts = {},
MINUTE = 60,
HOUR = 3600,
DAY = 86400,
WEEK = 604800;

if (offset <= MINUTE) parts = { lablel: 'now' };
if (offset <= MINUTE * 2) parts = { label: '1 min ago' };
else if (offset < (MINUTE * 60)) parts = { value: Math.round(Math.abs(offset / MINUTE)), label: 'mins' };
else if (offset < (HOUR * 2)) parts = { label: '1 hr ago' };
else if (offset < (HOUR * 24)) parts = { value: Math.round(Math.abs(offset / HOUR)), label: 'hrs' };
else if (offset < DAY) parts = { label: '1 day ago' };
else if (offset < (DAY * 7)) parts = { value: Math.round(Math.abs(offset / DAY)), label: 'day' };
else if (offset < (WEEK * 52)) parts = { value: Math.round(Math.abs(offset / WEEK)), label: 'week' };
else parts = { label: 'a long time ago' };

if (parts.value)
return parts.value + ' ' + parts.label + ' ago';
else
return parts.label;

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//draw a compact visualization of a treatment (carbs, insulin)
Expand Down
25 changes: 23 additions & 2 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,23 @@ DB.collection = DB.collection || process.env.CUSTOMCONNSTR_mongo_collection;
var DB_URL = DB.url;
var DB_COLLECTION = DB.collection;

var dir2Char = {
'NONE': '&#8700;',
'DoubleUp': '&#8648;',
'SingleUp': '&#8593;',
'FortyFiveUp': '&#8599;',
'Flat': '&#8594;',
'FortyFiveDown': '&#8600;',
'SingleDown': '&#8595;',
'DoubleDown': '&#8650;',
'NOT COMPUTABLE': '-',
'RATE OUT OF RANGE': '&#8622;'
};

function directionToChar(direction) {
return dir2Char[direction] || '-';
}

var Alarm = function(_typeName, _threshold) {
this.typeName = _typeName;
this.silenceTime = FORTY_MINUTES;
Expand Down Expand Up @@ -139,6 +156,7 @@ function update() {
obj.y = element.sgv;
obj.x = element.date;
obj.d = element.dateString;
obj.direction = directionToChar(element.direction);
cgmData.push(obj);
}
});
Expand Down Expand Up @@ -217,8 +235,9 @@ function loadData() {

// compute current loss
var avgLoss = 0;
for (var i = 0; i <= 6; i++) {
avgLoss += 1 / 6 * Math.pow(log10(predicted[i].y / 120), 2);
var size = Math.min(predicted.length - 1, 6);
for (var j = 0; j <= size; j++) {
avgLoss += 1 / size * Math.pow(log10(predicted[j].y / 120), 2);
}

if (avgLoss > alarms['urgent_alarm'].threshold) {
Expand All @@ -231,6 +250,8 @@ function loadData() {

// get data from database and setup to update every minute
function kickstart ( ) {
//TODO: test server to see how data is stored (timestamps, entry values, etc)
//TODO: check server settings to configure alerts, entry units, etc
update( );
return update;
}
Expand Down