diff --git a/index.js b/index.js index e69de29..f2571c6 100644 --- a/index.js +++ b/index.js @@ -0,0 +1,6 @@ + +var generate = require ('./lib/iob/index'); + +var iob = {}; + +module.exports = { iob: { generate: generate } } ; \ No newline at end of file diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js index e1d9ee8..00ff135 100644 --- a/lib/iob/calculate.js +++ b/lib/iob/calculate.js @@ -1,45 +1,40 @@ function iobCalc(treatment, time, dia) { - var diaratio = dia / 3; + var diaratio = 3.0 / dia; var peak = 75 ; var end = 180 ; //var sens = profile_data.sens; if (typeof time === 'undefined') { - var time = new Date(); + time = new Date(); } + var results = {}; + if (treatment.insulin) { - var bolusTime=new Date(treatment.date); - var minAgo=(time-bolusTime)/1000/60 * diaratio; + var bolusTime = new Date(treatment.date); + var minAgo = diaratio * (time-bolusTime) / 1000 / 60; + var iobContrib = 0; + var activityContrib = 0; - if (minAgo < 0) { - var iobContrib=0; - var activityContrib=0; - } - else if (minAgo < peak) { + if (minAgo < peak) { var x = (minAgo/5 + 1); - var iobContrib=treatment.insulin*(1-0.001852*x*x+0.001852*x); - //var activityContrib=sens*treatment.insulin*(2/dia/60/peak)*minAgo; - var activityContrib=treatment.insulin*(2/dia/60/peak)*minAgo; - } - else if (minAgo < end) { - var x = (minAgo-peak)/5; - var iobContrib=treatment.insulin*(0.001323*x*x - .054233*x + .55556); - //var activityContrib=sens*treatment.insulin*(2/dia/60-(minAgo-peak)*2/dia/60/(60*dia-peak)); - var activityContrib=treatment.insulin*(2/dia/60-(minAgo-peak)*2/dia/60/(60*dia-peak)); - } - else { - var iobContrib=0; - var activityContrib=0; + iobContrib = treatment.insulin * (1 - 0.001852 * x * x + 0.001852 * x); + //activityContrib=sens*treatment.insulin*(2/dia/60/peak)*minAgo; + activityContrib = treatment.insulin * (2 / dia / 60 / peak) * minAgo; + } else if (minAgo < end) { + var y = (minAgo-peak)/5; + iobContrib = treatment.insulin * (0.001323 * y * y - .054233 * y + .55556); + //activityContrib=sens*treatment.insulin*(2/dia/60-(minAgo-peak)*2/dia/60/(60*dia-peak)); + activityContrib = treatment.insulin * (2 / dia / 60 - (minAgo - peak) * 2 / dia / 60 / (60 * dia - peak)); } - return { + + results = { iobContrib: iobContrib, activityContrib: activityContrib }; } - else { - return ''; - } + + return results; } exports = module.exports = iobCalc; diff --git a/lib/iob/history.js b/lib/iob/history.js index 81fee85..f7777eb 100644 --- a/lib/iob/history.js +++ b/lib/iob/history.js @@ -7,7 +7,7 @@ function calcTempTreatments (inputs) { var tempHistory = []; var tempBoluses = []; var now = new Date(); - var timeZone = now.toString().match(/([-\+][0-9]+)\s/)[1] + var timeZone = now.toString().match(/([-\+][0-9]+)\s/)[1]; for (var i=0; i < pumpHistory.length; i++) { var current = pumpHistory[i]; //if(pumpHistory[i].date < time) { @@ -19,7 +19,7 @@ function calcTempTreatments (inputs) { temp.started_at = new Date(tz(current.timestamp)); //temp.date = current.date temp.date = temp.started_at.getTime(); - temp.insulin = current.amount + temp.insulin = current.amount; tempBoluses.push(temp); } else if (pumpHistory[i]._type == "TempBasal") { if (current.temp == 'percent') { @@ -43,7 +43,8 @@ function calcTempTreatments (inputs) { tempHistory.push(temp); } //} - }; + } + tempHistory.sort(function (a, b) { if (a.date > b.date) { return 1 } if (a.date < b.date) { return -1; } return 0; }); for (var i=0; i+1 < tempHistory.length; i++) { if (tempHistory[i].date + tempHistory[i].duration*60*1000 > tempHistory[i+1].date) { tempHistory[i].duration = (tempHistory[i+1].date - tempHistory[i].date)/60/1000; @@ -51,7 +52,7 @@ function calcTempTreatments (inputs) { } var tempBolusSize; var now = new Date(); - var timeZone = now.toString().match(/([-\+][0-9]+)\s/)[1] + var timeZone = now.toString().match(/([-\+][0-9]+)\s/)[1]; for (var i=0; i < tempHistory.length; i++) { if (tempHistory[i].duration > 0) { var netBasalRate = tempHistory[i].rate-profile_data.current_basal; diff --git a/lib/iob/index.js b/lib/iob/index.js index e50f4e6..f8ac98c 100644 --- a/lib/iob/index.js +++ b/lib/iob/index.js @@ -7,7 +7,6 @@ var sum = require('./total'); function generate (inputs) { var treatments = find_insulin(inputs); - treatments.sort(function (a, b) { return a.date > b.date }); var opts = { treatments: treatments diff --git a/lib/iob/total.js b/lib/iob/total.js index eade937..28d8180 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -4,7 +4,8 @@ function iobTotal(opts, time) { var treatments = opts.treatments; var profile_data = opts.profile; var iob = 0; - var bolusiob = 0; + var bolussnooze = 0; + var basaliob = 0; var activity = 0; if (!treatments) return {}; //if (typeof time === 'undefined') { @@ -12,25 +13,30 @@ function iobTotal(opts, time) { //} treatments.forEach(function(treatment) { - if(treatment.date < time.getTime( )) { + if(treatment.date <= time.getTime( )) { var dia = profile_data.dia; var tIOB = iobCalc(treatment, time, dia); if (tIOB && tIOB.iobContrib) iob += tIOB.iobContrib; if (tIOB && tIOB.activityContrib) activity += tIOB.activityContrib; - // keep track of bolus IOB separately for snoozes, but decay it three times as fast + // keep track of bolus IOB separately for snoozes, but decay it twice as fast if (treatment.insulin >= 0.2 && treatment.started_at) { - var bIOB = iobCalc(treatment, time, dia*2) + //use half the dia for double speed bolus snooze + var bIOB = iobCalc(treatment, time, dia / 2); //console.log(treatment); //console.log(bIOB); - if (bIOB && bIOB.iobContrib) bolusiob += bIOB.iobContrib; + if (bIOB && bIOB.iobContrib) bolussnooze += bIOB.iobContrib; + } else { + var aIOB = iobCalc(treatment, time, dia); + if (aIOB && aIOB.iobContrib) basaliob += aIOB.iobContrib; } } }); return { - iob: iob, - activity: activity, - bolusiob: bolusiob + iob: Math.round( iob * 1000 ) / 1000, + activity: Math.round( activity * 10000 ) / 10000, + bolussnooze: Math.round( bolussnooze * 1000 ) / 1000, + basaliob: Math.round( basaliob * 1000 ) / 1000, }; } diff --git a/package.json b/package.json index 9c52c30..e3e9a94 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,14 @@ "url": "https://github.com/nightscout/dcalc/issues" }, "homepage": "https://github.com/nightscout/dcalc", + "dependencies": { + "timezone": "0.0.47", + "lodash": "^3.9.1", + "moment": "2.10.6" + }, "devDependencies": { - "mocha": "^2.3.3", + "chai": "^3.4.1", + "mocha": "^2.3.4", "should": "^7.1.1" } } diff --git a/tests/index.js b/tests/index.js index e69de29..6af075e 100644 --- a/tests/index.js +++ b/tests/index.js @@ -0,0 +1,92 @@ + +var should = require('chai').should(); + +var dcalc = require('../index'); +var iob = dcalc.iob; + +describe('#generate', function() { + + it('should calculate IOB', function() { + + var now = Date.now() + , timestamp = new Date(now).toISOString() + , inputs = { + clock: timestamp + , history: [{ + _type: 'Bolus' + , amount: 1 + , timestamp: timestamp + }] + , profile: { + dia: 3 + } + }; + + var rightAfterBolus = iob.generate(inputs); + + console.log(rightAfterBolus); + + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = iob.generate(hourLaterInputs); + hourLater.iob.should.be.lessThan(1); + hourLater.bolussnooze.should.be.lessThan(.5); + hourLater.iob.should.be.greaterThan(0); + + var afterDIAInputs = inputs; + afterDIAInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); + var afterDIA = iob.generate(afterDIAInputs); + + afterDIA.iob.should.equal(0); + afterDIA.bolussnooze.should.equal(0); + + }); + + it('should calculate IOB using a 4 hour duration', function() { + + var now = Date.now() + , timestamp = new Date(now).toISOString() + , inputs = { + clock: timestamp + , history: [{ + _type: 'Bolus' + , amount: 1 + , timestamp: timestamp + }] + , profile: { + dia: 4 + } + }; + + var rightAfterBolus = iob.generate(inputs); //require('../lib/iob')(inputs); + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolussnooze.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = iob.generate(hourLaterInputs); + + hourLater.iob.should.be.lessThan(1); + hourLater.bolussnooze.should.be.lessThan(.5); + hourLater.iob.should.be.greaterThan(0); + + var after3hInputs = inputs; + after3hInputs.clock = new Date(now + (3 * 60 * 60 * 1000)).toISOString(); + var after3h = iob.generate(after3hInputs); + after3h.iob.should.be.greaterThan(0); + + var after4hInputs = inputs; + after4hInputs.clock = new Date(now + (4 * 60 * 60 * 1000)).toISOString(); + var after4h = iob.generate(after4hInputs); + after4h.iob.should.equal(0); + + }); + + + +}); + +