diff --git a/bin/mm-format-oref0-glucose.sh b/bin/mm-format-oref0-glucose.sh new file mode 100755 index 000000000..099b93373 --- /dev/null +++ b/bin/mm-format-oref0-glucose.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Author: Ben West @bewest +# Maintainer: @tghoward + +# Written for decocare v0.0.18. Will need updating the the decocare json format changes. +HISTORY=${1-glucosehistory.json} +OUTPUT=${2-/dev/fd/1} +#TZ=${3-$(date +%z)} + +cat $HISTORY | \ + json -e "this.medtronic = this._type;" | \ + json -e "this.dateString = this.date + '$(date +%z)'" | \ + json -e "this.date = new Date(this.dateString).getTime();" | \ + json -e "this.type = (this.name == 'GlucoseSensorData') ? 'sgv' : 'pumpdata'" | \ + json -e "this.device = 'openaps://medtronic/pump/cgm'" \ + > $OUTPUT + diff --git a/bin/ns-dedupe-treatments.sh b/bin/ns-dedupe-treatments.sh index be1461190..307513f5d 100755 --- a/bin/ns-dedupe-treatments.sh +++ b/bin/ns-dedupe-treatments.sh @@ -76,6 +76,7 @@ done } export API_SECRET +test -n "$3" && API_SECRET=$3 case "$1" in --list) list $2 diff --git a/bin/ns-uploader-setup.sh b/bin/ns-uploader-setup.sh new file mode 100755 index 000000000..5b7ed964a --- /dev/null +++ b/bin/ns-uploader-setup.sh @@ -0,0 +1,134 @@ +#!/bin/bash + +# This script sets up a read-only openaps environment that uploads pump history data to nightscout +# by defining the required devices, reports, and aliases. +# +# Released under MIT license. See the accompanying LICENSE.txt file for +# full terms and conditions +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +die() { + echo "$@" + exit 1 +} + +self=$(basename $0) +if [[ $# -lt 2 ]]; then + openaps device show pump 2>/dev/null >/dev/null || die "Usage: $self " +fi +directory=`mkdir -p $1; cd $1; pwd` +serial=$2 + +echo -n Setting up oref0 in $directory for pump $serial + +if [[ $# -gt 3 ]]; then + diyps_url=$4 + echo -n ", DIYPS URL $diyps_url" +fi +echo + +read -p "Continue? " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + +( ( cd $directory 2>/dev/null && git status ) || ( openaps init $directory ) ) || die "Can't init $directory" +cd $directory || die "Can't cd $directory" + +#sudo cp ~/src/oref0/logrotate.openaps /etc/logrotate.d/openaps +sudo bash -c "curl -s https://raw.githubusercontent.com/openaps/oref0/master/logrotate.openaps > /etc/logrotate.d/openaps" +#sudo cp ~/src/oref0/logrotate.rsyslog /etc/logrotate.d/rsyslog +sudo bash -c "curl -s https://raw.githubusercontent.com/openaps/oref0/master/logrotate.rsyslog > /etc/logrotate.d/rsyslog" + +test -d /var/log/openaps || sudo mkdir /var/log/openaps && sudo chown $USER /var/log/openaps + +openaps vendor add openapscontrib.timezones + +# don't re-create devices if they already exist +openaps device show 2>/dev/null > /tmp/openaps-devices + +# add devices +grep -q pump.ini .gitignore 2>/dev/null || echo pump.ini >> .gitignore +git add .gitignore +grep pump /tmp/openaps-devices || openaps device add pump medtronic $serial || die "Can't add pump" +grep cgm /tmp/openaps-devices || openaps device add cgm dexcom || die "Can't add CGM" +git add cgm.ini +grep ns-glucose /tmp/openaps-devices || openaps device add ns-glucose process 'bash -c "curl -s $NIGHTSCOUT_HOST/api/v1/entries/sgv.json | json -e \"this.glucose = this.sgv\""' || die "Can't add ns-glucose" +git add ns-glucose.ini +grep oref0 /tmp/openaps-devices || openaps device add oref0 process oref0 || die "Can't add oref0" +git add oref0.ini +grep iob /tmp/openaps-devices || openaps device add iob process --require "pumphistory profile clock" oref0 calculate-iob || die "Can't add iob" +git add iob.ini +grep tz /tmp/openaps-devices || openaps device add tz timezones || die "Can't add tz" +git add tz.ini +#grep latest-treatments /tmp/openaps-devices || openaps device add latest-treatments process nightscout 'latest-openaps-treatment $NIGHTSCOUT_HOST' || die "Can't add latest-treatments" +#git add latest-treatments.ini + +# don't re-create reports if they already exist +openaps report show 2>/dev/null > /tmp/openaps-reports + +# add reports for frequently-refreshed monitoring data +ls monitor 2>/dev/null >/dev/null || mkdir monitor || die "Can't mkdir monitor" +grep monitor/glucose.json /tmp/openaps-reports || openaps report add monitor/glucose.json JSON cgm iter_glucose 5 || die "Can't add glucose.json" +grep monitor/ns-glucose.json /tmp/openaps-reports || openaps report add monitor/ns-glucose.json text ns-glucose shell || die "Can't add ns-glucose.json" +grep settings/model.json /tmp/openaps-reports || openaps report add settings/model.json JSON pump model || die "Can't add model" +grep monitor/clock.json /tmp/openaps-reports || openaps report add monitor/clock.json JSON pump read_clock || die "Can't add clock.json" +grep monitor/clock-zoned.json /tmp/openaps-reports || openaps report add monitor/clock-zoned.json JSON tz clock monitor/clock.json || die "Can't add clock-zoned.json" +grep monitor/temp_basal.json /tmp/openaps-reports || openaps report add monitor/temp_basal.json JSON pump read_temp_basal || die "Can't add temp_basal.json" +grep monitor/reservoir.json /tmp/openaps-reports || openaps report add monitor/reservoir.json JSON pump reservoir || die "Can't add reservoir.json" +grep monitor/pumphistory.json /tmp/openaps-reports || openaps report add monitor/pumphistory.json JSON pump iter_pump_hours 4 || die "Can't add pumphistory.json" +grep monitor/pumphistory-zoned.json /tmp/openaps-reports || openaps report add monitor/pumphistory-zoned.json JSON tz rezone monitor/pumphistory.json || die "Can't add pumphistory-zoned.json" +grep monitor/iob.json /tmp/openaps-reports || openaps report add monitor/iob.json text iob shell monitor/pumphistory-zoned.json settings/profile.json monitor/clock-zoned.json || die "Can't add iob.json" + +# add reports for infrequently-refreshed settings data +ls settings 2>/dev/null >/dev/null || mkdir settings || die "Can't mkdir settings" +grep settings/bg_targets.json /tmp/openaps-reports || openaps report add settings/bg_targets.json JSON pump read_bg_targets || die "Can't add bg_targets.json" +grep settings/insulin_sensitivities.json /tmp/openaps-reports || openaps report add settings/insulin_sensitivities.json JSON pump read_insulin_sensitivities || die "Can't add insulin_sensitivities.json" +grep settings/basal_profile.json /tmp/openaps-reports || openaps report add settings/basal_profile.json JSON pump read_selected_basal_profile || die "Can't add basal_profile.json" +grep settings/settings.json /tmp/openaps-reports || openaps report add settings/settings.json JSON pump read_settings || die "Can't add settings.json" + +# add aliases to get data +openaps alias add invoke "report invoke" || die "Can't add invoke" +openaps alias add preflight '! bash -c "rm -f monitor/clock.json && openaps report invoke monitor/clock.json >/dev/null 2>/dev/null && grep -q T monitor/clock.json && echo PREFLIGHT OK || ( mm-stick warmup || sudo oref0-reset-usb; echo PREFLIGHT FAIL; sleep 120; exit 1 )"' || die "Can't add preflight" +openaps alias add monitor-cgm "report invoke monitor/glucose.json" || die "Can't add monitor-cgm" +openaps alias add get-ns-glucose "report invoke monitor/ns-glucose.json" || die "Can't add get-ns-glucose" +openaps alias add monitor-pump "report invoke monitor/clock.json monitor/temp_basal.json monitor/pumphistory.json monitor/pumphistory-zoned.json monitor/clock-zoned.json" || die "Can't add monitor-pump" +openaps alias add get-settings "report invoke settings/model.json settings/bg_targets.json settings/insulin_sensitivities.json settings/basal_profile.json settings/settings.json" || die "Can't add get-settings" +openaps alias add get-bg '! bash -c "openaps monitor-cgm 2>/dev/null || ( openaps get-ns-glucose && grep -q glucose monitor/ns-glucose.json && mv monitor/ns-glucose.json monitor/glucose.json )"' || die "Can't add get-bg" +openaps alias add gather '! bash -c "rm monitor/*; ( openaps get-bg && openaps get-settings >/dev/null && openaps monitor-pump ) 2>/dev/null"' || die "Can't add gather" +openaps alias add wait-for-bg '! bash -c "cp monitor/glucose.json monitor/last-glucose.json; while(diff -q monitor/last-glucose.json monitor/glucose.json); do echo -n .; sleep 10; openaps get-bg >/dev/null; done"' + +# upload treatments to nightscout +ls upload 2>/dev/null >/dev/null || mkdir upload || die "Can't mkdir upload" +openaps alias add latest-ns-treatment-time '! bash -c "nightscout latest-openaps-treatment $NIGHTSCOUT_HOST | json created_at"' || die "Can't add latest-ns-treatment-time" +openaps alias add format-latest-nightscout-treatments '! bash -c "nightscout cull-latest-openaps-treatments monitor/pumphistory-zoned.json settings/model.json $(openaps latest-ns-treatment-time) > upload/latest-treatments.json"' || die "Can't add format-latest-nightscout-treatments" +openaps alias add upload-recent-treatments '! bash -c "openaps format-latest-nightscout-treatments && test $(json -f upload/latest-treatments.json -a created_at eventType | wc -l ) -gt 0 && (ns-upload $NIGHTSCOUT_HOST $API_SECRET treatments.json upload/latest-treatments.json ) || echo \"No recent treatments to upload\""' || die "Can't add upload-recent-treatments" +openaps alias add upload '! bash -c "openaps preflight && ( openaps monitor-pump && openaps upload-recent-treatments && openaps get-settings) 2>/dev/null >/dev/null && echo -n \"Uploaded; most recent treatment event @ \" && openaps latest-ns-treatment-time || echo \"Error; could not upload\""' || die "Can't add upload" + +read -p "Schedule oref1 (openaps nightscout uploader) in cron? " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + read -p "Nightscout hostname? " + NIGHTSCOUT_HOST=$REPLY + read -p "Hashed API secret? " + API_SECRET=$REPLY + read -p "Upload to $NIGHTSCOUT_HOST using API secret $API_SECRET, correct? " -n 1 -r + if [[ $REPLY =~ ^[Yy]$ ]]; then + (crontab -l; echo NIGHTSCOUT_HOST=$NIGHTSCOUT_HOST) | crontab - + (crontab -l; echo API_SECRET=$API_SECRET) | crontab - + fi + # add crontab entries + (crontab -l; crontab -l | grep -q PATH || echo 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin') | crontab - + (crontab -l; crontab -l | grep -q killall || echo '* * * * * killall -g --older-than 10m openaps') | crontab - + (crontab -l; crontab -l | grep -q "reset-git" || echo "* * * * * cd $directory && oref0-reset-git") | crontab - + (crontab -l; crontab -l | grep -q uploader || echo "* * * * * cd $directory && ( ps aux | grep -v grep | grep -q 'openaps ' && echo OpenAPS already running || openaps upload ) 2>&1 | tee -a /var/log/openaps/uploader.log") | crontab - + crontab -l +fi + +fi diff --git a/bin/oref0-calculate-iob.js b/bin/oref0-calculate-iob.js index edd43a74d..8a111de0d 100755 --- a/bin/oref0-calculate-iob.js +++ b/bin/oref0-calculate-iob.js @@ -21,16 +21,16 @@ var generate = require('oref0/lib/iob'); if (!module.parent) { - var iob_input = process.argv.slice(2, 3).pop() - var profile_input = process.argv.slice(3, 4).pop() - var clock_input = process.argv.slice(4, 5).pop() + var iob_input = process.argv.slice(2, 3).pop(); + var profile_input = process.argv.slice(3, 4).pop(); + var clock_input = process.argv.slice(4, 5).pop(); if (!iob_input || !profile_input) { console.log('usage: ', process.argv.slice(0, 2), ' '); process.exit(1); } - var cwd = process.cwd() + var cwd = process.cwd(); var all_data = require(cwd + '/' + iob_input); var profile_data = require(cwd + '/' + profile_input); var clock_data = require(cwd + '/' + clock_input); diff --git a/bin/oref0-determine-basal.js b/bin/oref0-determine-basal.js index 12844f726..2fab68f14 100755 --- a/bin/oref0-determine-basal.js +++ b/bin/oref0-determine-basal.js @@ -163,11 +163,12 @@ function init() { console.log(JSON.stringify(rT)); return rT; } - var threshold = profile.min_bg - 30; + // min_bg of 90 -> threshold of 70, 110 -> 80, and 130 -> 90 + var threshold = profile.min_bg - 0.5*(profile.min_bg-50); if (bg < threshold) { // low glucose suspend mode: BG is < ~80 rT.reason = "BG " + bg + "<" + threshold; - if ((glucose_status.delta < 0 && glucose_status.avgdelta < 0) || (glucose_status.delta < bgi && glucose_status.avgdelta < bgi)) { + if ((glucose_status.delta <= 0 && glucose_status.avgdelta <= 0) || (glucose_status.delta < bgi && glucose_status.avgdelta < bgi)) { // BG is still falling / rising slower than predicted console.error(rT.reason); return determinebasal.setTempBasal(0, 30, profile, rT, offline); @@ -191,7 +192,11 @@ function init() { rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; // if 5m or 15m avg BG is rising faster than BGI/2 if (glucose_status.delta > bgi/2 && glucose_status.avgdelta > bgi/2) { - rT.reason += ", but Delta " + tick + " > BGI " + bgi + " / 2"; + if (glucose_status.delta > glucose_status.avgdelta) { + rT.reason += ", but Delta " + tick + " > BGI " + bgi + " / 2"; + } else { + rT.reason += ", but Avg. Delta " + glucose_status.avgdelta + " > BGI " + bgi + " / 2"; + } if (currenttemp.duration > 0) { // if there is currently any temp basal running rT.reason = rT.reason += "; cancel"; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp @@ -205,14 +210,14 @@ function init() { if (snoozeBG > profile.min_bg) { // if adding back in the bolus contribution BG would be above min // if BG is falling and high-temped, or rising and low-temped, cancel // compare against zero here, not BGI, because BGI will be highly negative from boluses and no carbs - if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { + if (glucose_status.delta < 0 && currenttemp.duration > 0 && currenttemp.rate > profile.current_basal) { rT.reason += tick + ", and temp " + currenttemp.rate + " > basal " + profile.current_basal; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { + } else if (glucose_status.delta > 0 && currenttemp.duration > 0 && currenttemp.rate < profile.current_basal) { rT.reason += tick + ", and temp " + currenttemp.rate + " < basal " + profile.current_basal; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } - rT.reason += "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; + rT.reason += ", bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(rT.reason); console.log(JSON.stringify(rT)); return rT; @@ -225,7 +230,7 @@ function init() { rate = Math.round( rate * 1000 ) / 1000; // if required temp < existing temp basal if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 0 && rate > currenttemp.rate - 0.1)) { - rT.reason += "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; + rT.reason += ", temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; console.error(rT.reason); console.log(JSON.stringify(rT)); return rT; @@ -235,7 +240,11 @@ function init() { } // if eventual BG is above min but BG is falling faster than BGI/2 if (glucose_status.delta < bgi/2 || glucose_status.avgdelta < bgi/2) { - rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi + " / 2"; + if (glucose_status.delta < glucose_status.avgdelta) { + rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi + " / 2"; + } else { + rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Avg. Delta " + glucose_status.avgdelta + " < BGI " + bgi + " / 2"; + } if (currenttemp.duration > 0) { // if there is currently any temp basal running rT.reason = rT.reason += "; cancel"; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp @@ -292,7 +301,7 @@ function init() { rT.reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } - if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set + if (typeof currenttemp.duration == 'undefined' || currenttemp.duration == 0) { // no temp is set rT.reason += "no temp, setting " + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } diff --git a/bin/pebble.sh b/bin/pebble.sh deleted file mode 120000 index b6c619642..000000000 --- a/bin/pebble.sh +++ /dev/null @@ -1 +0,0 @@ -../../openaps-sh/pebble.sh \ No newline at end of file diff --git a/bin/pumpsettings.sh b/bin/pumpsettings.sh deleted file mode 120000 index 0c250cec3..000000000 --- a/bin/pumpsettings.sh +++ /dev/null @@ -1 +0,0 @@ -../../openaps-sh/pumpsettings.sh \ No newline at end of file diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js index e1d9ee842..00ff1358b 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 a37a20a72..66043922f 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,7 @@ function calcTempTreatments (inputs) { tempHistory.push(temp); } //} - }; + } tempHistory.sort(function (a, b) { return a.date > b.date }); for (var i=0; i+1 < tempHistory.length; i++) { if (tempHistory[i].date + tempHistory[i].duration*60*1000 > tempHistory[i+1].date) { @@ -52,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/total.js b/lib/iob/total.js index eade93722..8b2736651 100644 --- a/lib/iob/total.js +++ b/lib/iob/total.js @@ -12,14 +12,15 @@ 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 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; diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index 4c9c09255..422c0afe0 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -151,6 +151,33 @@ describe('determine-basal', function ( ) { output.reason.should.match(/no temp, setting/); }); + it('should temp to 0 when LOW w/ positive IOB', function () { + var glucose_status = {"delta":0,"glucose":39,"avgdelta":0}; + var iob_data = {"iob":1,"activity":0.01,"bolusiob":0.5}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.equal(0); + output.duration.should.equal(30); + output.reason.should.match(/BG 39<80/); + }); + + it('should temp to 0 when LOW w/ negative IOB', function () { + var glucose_status = {"delta":0,"glucose":39,"avgdelta":0}; + var iob_data = {"iob":-2.5,"activity":-0.03,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.equal(0); + output.duration.should.equal(30); + output.reason.should.match(/BG 39<80/); + }); + + it('should temp to 0 when LOW w/ no IOB', function () { + var glucose_status = {"delta":0,"glucose":39,"avgdelta":0}; + var iob_data = {"iob":0,"activity":0,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.equal(0); + output.duration.should.equal(30); + output.reason.should.match(/BG 39<80/); + }); + // low eventualBG it('should low-temp when eventualBG < min_bg', function () { @@ -168,7 +195,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); output.rate.should.equal(0); output.duration.should.equal(0); - output.reason.should.match(/Eventual BG.*<.*but Delta.*> BGI.*; cancel/); + output.reason.should.match(/Eventual BG.*<.*but.*Delta.*> BGI.*; cancel/); }); it('should low-temp when low and rising slower than BGI', function () { @@ -197,7 +224,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); output.rate.should.equal(0); output.duration.should.equal(0); - output.reason.should.match(/Eventual BG.*>.*but Delta.*< BGI.*; cancel/); + output.reason.should.match(/Eventual BG.*>.*but.*Delta.*< BGI.*; cancel/); }); it('should high-temp when high and falling slower than BGI', function () { @@ -216,5 +243,14 @@ describe('determine-basal', function ( ) { glucose_status.avgdelta.should.equal(10); }); + // meal assist / bolus snooze + it('should do nothing when low and rising after meal bolus', function () { + var glucose_status = {"delta":1,"glucose":80,"avgdelta":1}; + var iob_data = {"iob":0.5,"activity":-0.01,"bolusiob":1}; + var meal_data = {"dia_carbs":20,"dia_bolused":1}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + (typeof output.rate).should.equal('undefined'); + (typeof output.duration).should.equal('undefined'); + }); }); diff --git a/tests/iob.test.js b/tests/iob.test.js new file mode 100644 index 000000000..c5644c7ca --- /dev/null +++ b/tests/iob.test.js @@ -0,0 +1,83 @@ +'use strict'; + +require('should'); + +describe('IOB', 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 = require('../lib/iob')(inputs); + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolusiob.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs); + hourLater.iob.should.be.lessThan(1); + hourLater.bolusiob.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 = require('../lib/iob')(afterDIAInputs); + + afterDIA.iob.should.equal(0); + afterDIA.bolusiob.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 = require('../lib/iob')(inputs); + rightAfterBolus.iob.should.equal(1); + rightAfterBolus.bolusiob.should.equal(1); + + var hourLaterInputs = inputs; + hourLaterInputs.clock = new Date(now + (60 * 60 * 1000)).toISOString(); + var hourLater = require('../lib/iob')(hourLaterInputs); + hourLater.iob.should.be.lessThan(1); + hourLater.bolusiob.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 = require('../lib/iob')(after3hInputs); + after3h.iob.should.be.greaterThan(0); + + var after4hInputs = inputs; + after4hInputs.clock = new Date(now + (4 * 60 * 60 * 1000)).toISOString(); + var after4h = require('../lib/iob')(after4hInputs); + after4h.iob.should.equal(0); + + }); + + +}); \ No newline at end of file