From 0ba73501c696818915d0feb47b3cba3cefa9c7d5 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 02:12:25 -0700 Subject: [PATCH 001/131] new much smarter loop.sh --- bin/loop.sh | 184 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 133 insertions(+), 51 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 7534d2e..c4dfd50 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -25,7 +25,10 @@ die() { find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null # only one process can talk to the pump at a time -ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit +if ls /tmp/openaps.lock >/dev/null 2>/dev/null; then + ls -la /tmp/openaps.lock + die "/tmp/openaps.lock exists" +fi echo "No lockfile: continuing" touch /tmp/openaps.lock @@ -41,7 +44,7 @@ cd ~/openaps-dev && ( git status > /dev/null || ( mv ~/openaps-dev/.git /tmp/.gi openaps report show > /dev/null || cp openaps.ini.bak openaps.ini function finish { - rm /tmp/openaps.lock + rm /tmp/openaps.lock 2>/dev/null } trap finish EXIT @@ -50,28 +53,31 @@ trap finish EXIT # get glucose data, either from attached CGM or from Share getglucose() { echo "Querying CGM" - ( ( openaps report invoke glucose.json.new || openaps report invoke glucose.json.new ) && grep -v '"glucose": 5' glucose.json.new | grep glucose ) || share2-bridge file glucose.json.new - if diff -u glucose.json glucose.json.new; then + ( ( openaps report invoke glucose.json.new || openaps report invoke glucose.json.new ) 2>/dev/null && grep -v '"glucose": 5' glucose.json.new | grep -q glucose ) || share2-bridge file glucose.json.new 2>/dev/null >/dev/null + if diff -q glucose.json glucose.json.new; then echo No new glucose data + return 1; else grep glucose glucose.json.new | head -1 | awk '{print $2}' | while read line; do echo -n " $line "; done >> /var/log/openaps/easy.log \ && rsync -tu glucose.json.new glucose.json \ - && git commit -m"glucose.json has glucose data: committing" glucose.json + #&& git commit -m"glucose.json has glucose data: committing" glucose.json + return 0; fi } # get pump status (suspended, etc.) getpumpstatus() { echo "Checking pump status" - openaps status || echo -n "!" >> /var/log/openaps/easy.log + openaps status 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log grep -q status status.json.new && ( rsync -tu status.json.new status.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log } # query pump, and update pump data files if successful querypump() { - openaps pumpquery || openaps pumpquery || echo -n "!" >> /var/log/openaps/easy.log + ( openaps pumpquery || openaps pumpquery ) 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) findclocknew && grep T clock.json.new && ( rsync -tu clock.json.new clock.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log grep -q timestamp pumphistory.json.new && ( rsync -tu pumphistory.json.new pumphistory.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log upload + return 0 } # try to upload pumphistory data upload() { findpumphistory && ~/bin/openaps-mongo.sh && touch /tmp/openaps.online; } @@ -91,58 +97,134 @@ findrequestedtemp() { find requestedtemp.json -mmin -10 | egrep -q '.*'; } # write out current status to pebble.json pebble() { ~/openaps-js/bin/pebble.sh; } +bail() { + echo "$@" | tee -a /var/log/openaps/easy.log + return 1 +} -# main event loop - -getglucose -head -15 glucose.json - -numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) -if [[ $numprocs -gt 0 ]] ; then - die "Carelink USB already in use or not available." -fi - -getpumpstatus -echo "Querying pump" && querypump +actionrequired() { + #if diff -u reservoir.json reservoir.json.new; then + # if reservoir insulin remaining changes by more than 0.2U between runs, that probably indicates a bolus + if awk '{getline t<"reservoir.json.new"; if (($0-t) > 0.2 || ($0-t < -0.2)) print "Reservoir changed from " $0 " to " t}' reservoir.json | grep changed; then + echo "Reservoir status changed" + rsync -tu reservoir.json.new reservoir.json + return 0; + else + rsync -tu reservoir.json.new reservoir.json + # if a temp is needed based on current BG and temp + openaps invoke requestedtemp.online.json + grep rate requestedtemp.online.json + return $? + fi +} -upload +execute() { + getglucose + head -15 glucose.json | grep -B1 glucose -# get glucose again in case the pump queries took awhile -getglucose + numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) + if [[ $numprocs -gt 0 ]] ; then + bail "Carelink USB already in use or not available."; return $? + fi -# if we're offline, set the clock to the pump/CGM time -~/openaps-js/bin/clockset.sh + #getpumpstatus + echo "Querying pump" && querypump 2>/dev/null -# dump out a "what we're about to try to do" report -suggest && pebble + upload -tail clock.json -tail currenttemp.json + # get glucose again in case the pump queries took awhile + getglucose + + # if we're offline, set the clock to the pump/CGM time + ~/openaps-js/bin/clockset.sh + + # dump out a "what we're about to try to do" report + suggest && pebble + + tail clock.json + tail currenttemp.json + + # make sure we're not using an old suggestion + rm requestedtemp.json* 2>/dev/null + echo "Removing requestedtemp.json and recreating it" + # if we can't run suggest, it might be because our pumpsettings are missing or screwed up" + suggest || ( getpumpsettings && suggest ) || ( bail "Can't calculate IOB or basal"; return $? ) + pebble + tail profile.json + tail iob.json + tail requestedtemp.json + + + # don't act on stale glucose data + findglucose && grep -q glucose glucose.json || ( bail "No recent glucose data"; return $? ) + # execute/enact the requested temp + cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log + if grep -q rate requestedtemp.json; then + echo "Enacting temp" + retries=3 + retry=0 + until openaps enact; do + retry=`expr $retry + 1` + echo "enact failed; retry $retry" + if [ $retry -ge $retries ]; then bail "Failed to enact temp"; return $?; fi + done + tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && return 0 + fi +} -# make sure we're not using an old suggestion -rm requestedtemp.json* -# if we can't run suggest, it might be because our pumpsettings are missing or screwed up" -suggest || ( getpumpsettings && suggest ) || die "Can't calculate IOB or basal" -pebble -tail profile.json -tail iob.json -tail requestedtemp.json +requery() { + numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) + if [[ $numprocs -gt 0 ]] ; then + bail "Carelink USB already in use or not available."; return $? + fi -# don't act on stale glucose data -findglucose && grep -q glucose glucose.json || die "No recent glucose data" -# execute/enact the requested temp -cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log -grep -q rate requestedtemp.json && ( openaps enact || openaps enact ) && tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log + echo "Re-querying pump" + retries=5 + retry=0 + until querypump; do + retry=`expr $retry + 1` + echo "Re-query failed; retry $retry" + if [ $retry -ge $retries ]; then bail "Failed to re-query pump"; return $?; fi + done + + # unlock in case upload is really slow + rm /tmp/openaps.lock 2>/dev/null + pebble + upload -echo "Re-querying pump" -query pump + # if another instance didn't start while we were uploading, refresh pump settings + ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit + touch /tmp/openaps.lock + numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) + if [[ $numprocs -gt 0 ]] ; then + bail "Carelink USB already in use or not available."; return $? + fi + retries=2 + retry=0 + until getpumpsettings; do + retry=`expr $retry + 1` + echo "getpumpsettings failed; retry $retry" + if [ $retry -ge $retries ]; then bail "getpumpsettings failed"; return $?; fi + done +} -# unlock in case upload is really slow -rm /tmp/openaps.lock -pebble -upload +# main event loop -# if another instance didn't start while we were uploading, refresh pump settings -ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit -touch /tmp/openaps.lock -getpumpsettings +while(true); do + + # execute on startup, and then whenever actionrequired() + until execute; do + echo "Failed; retrying" + sleep 5 + done + requery + # set a new reservoir baseline and watch for changes (boluses) + rsync -tu reservoir.json.new reservoir.json + until actionrequired; do + getglucose && cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log + openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + echo -n "-" >> /var/log/openaps/easy.log + sleep 5 + done +done From 27a3c5c0d9ad33605cc5298cde39404fdf04d0dd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 02:45:40 -0700 Subject: [PATCH 002/131] regenerate requestedtemp.online.json before printing out its reason --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index c4dfd50..61609b4 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -221,7 +221,7 @@ while(true); do # set a new reservoir baseline and watch for changes (boluses) rsync -tu reservoir.json.new reservoir.json until actionrequired; do - getglucose && cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log + getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log echo -n "-" >> /var/log/openaps/easy.log From 4f17b8faab0dcf5b7cba8a3eb91d7e620b8dda1c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 02:48:33 -0700 Subject: [PATCH 003/131] don't tell easy.log every time we're already running --- bin/loop.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 61609b4..050802a 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -27,7 +27,8 @@ find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null # only one process can talk to the pump at a time if ls /tmp/openaps.lock >/dev/null 2>/dev/null; then ls -la /tmp/openaps.lock - die "/tmp/openaps.lock exists" + echo "/tmp/openaps.lock exists" + exit 1 fi echo "No lockfile: continuing" From 7d1928c024f4a2580e0762c8d22cc245742d9fff Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 02:52:32 -0700 Subject: [PATCH 004/131] refresh the openaps.lock file each time we loop --- bin/loop.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/loop.sh b/bin/loop.sh index 050802a..4c9c019 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -213,6 +213,7 @@ requery() { while(true); do + touch /tmp/openaps.lock # execute on startup, and then whenever actionrequired() until execute; do echo "Failed; retrying" From 0bfcf313021a6a6072c5cbfba620af9e583a19df Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 03:20:05 -0700 Subject: [PATCH 005/131] if there are any old loops still running without proper lockfiles, kill them off --- bin/loop.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/loop.sh b/bin/loop.sh index 4c9c019..eae98b1 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -33,6 +33,8 @@ fi echo "No lockfile: continuing" touch /tmp/openaps.lock +# if there are any old loops still running without proper lockfiles, kill them off +killall loop.sh # make sure decocare can talk to the Carelink USB stick ~/decocare/insert.sh 2>/dev/null >/dev/null From 56256a0652cf80387f48b51741b152c81cc63966 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 03:26:22 -0700 Subject: [PATCH 006/131] need to be a bit more specific to avoid killing ourselves --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index eae98b1..ce91f12 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -34,7 +34,7 @@ fi echo "No lockfile: continuing" touch /tmp/openaps.lock # if there are any old loops still running without proper lockfiles, kill them off -killall loop.sh +kill $(pgrep -f openaps-js/bin/loop.sh | grep -v ^$$\$) # make sure decocare can talk to the Carelink USB stick ~/decocare/insert.sh 2>/dev/null >/dev/null From a5a373587e9b4025038bdb1dc0aea0836ac03a29 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 03:39:18 -0700 Subject: [PATCH 007/131] ping google to see if we're online instead of relying on openaps-mongo.sh exit codes --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index ce91f12..27a439f 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -83,7 +83,7 @@ querypump() { return 0 } # try to upload pumphistory data -upload() { findpumphistory && ~/bin/openaps-mongo.sh && touch /tmp/openaps.online; } +upload() { findpumphistory && ~/bin/openaps-mongo.sh; ping -c 1 google.com > /dev/null && touch /tmp/openaps.online; } # if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) suggest() { openaps suggest || echo -n "!" >> /var/log/openaps/easy.log From 5a5210e8a662b4c44e81311565aaecb862940a87 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 04:03:37 -0700 Subject: [PATCH 008/131] comment out last die statement that might kill the loop once it's going --- bin/loop.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 27a439f..a1f4116 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -191,12 +191,12 @@ requery() { done # unlock in case upload is really slow - rm /tmp/openaps.lock 2>/dev/null + #rm /tmp/openaps.lock 2>/dev/null pebble upload # if another instance didn't start while we were uploading, refresh pump settings - ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit + #ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit touch /tmp/openaps.lock numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) if [[ $numprocs -gt 0 ]] ; then From 88ecf99fd31951527d1e44cb2344f8834e0bef46 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 04:22:38 -0700 Subject: [PATCH 009/131] pull new reservoir data for baseline --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index a1f4116..8428d70 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -223,7 +223,7 @@ while(true); do done requery # set a new reservoir baseline and watch for changes (boluses) - rsync -tu reservoir.json.new reservoir.json + openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json until actionrequired; do getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log From 967b02d336b9986ca684b29e5f573ec2ccbf7bcc Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 04:28:48 -0700 Subject: [PATCH 010/131] enact is fast: let's retry it more times if it fails --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 8428d70..2f4c422 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -164,7 +164,7 @@ execute() { cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log if grep -q rate requestedtemp.json; then echo "Enacting temp" - retries=3 + retries=5 retry=0 until openaps enact; do retry=`expr $retry + 1` From ba6c39a06515b145e8b9b18c80546fea9bf31f64 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 14:05:44 -0700 Subject: [PATCH 011/131] if ntp isn't working, try /etc/init.d/ntp restart before setting fake-hwclock --- bin/clockset.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/clockset.sh b/bin/clockset.sh index 84f6a56..1da17db 100755 --- a/bin/clockset.sh +++ b/bin/clockset.sh @@ -20,7 +20,7 @@ PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin die() { echo "$@" ; exit 1; } -ntp-wait -n 1 -v && die "NTP already synchronized." +ntp-wait -n 1 -v && die "NTP already synchronized." || ( sudo /etc/init.d/ntp restart && ntp-wait -n 1 -v && die "NTP re-synchronized." ) cd ~/openaps-dev ( cat clock.json; echo ) | sed 's/"//g' | sed "s/$/`date +%z`/" | while read line; do date -u -d $line +"%F %R:%S"; done > fake-hwclock.data From 10a07d4c57f72870e74b9ce9122a3cc2a88aecdb Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 12:35:21 -0700 Subject: [PATCH 012/131] or clock set incorrectly --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index a0986b8..98c578e 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -265,7 +265,7 @@ if (!module.parent) { console.error(reason); } } else { - reason = "BG data is too old"; + reason = "BG data is too old, or clock set incorrectly"; console.error(reason); } From 269b8e9cf0e5d8e66f97b3b54a1725c8b49231e2 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 12:45:05 -0700 Subject: [PATCH 013/131] sleep 10 between enact retries --- bin/loop.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 2f4c422..0cf29d0 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -169,7 +169,8 @@ execute() { until openaps enact; do retry=`expr $retry + 1` echo "enact failed; retry $retry" - if [ $retry -ge $retries ]; then bail "Failed to enact temp"; return $?; fi + if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retry of $retries retries"; return $?; fi + sleep 10; done tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && return 0 fi From 73dabe8bd442c2aea3adc67a694f9eb9dd1522ca Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 12:56:40 -0700 Subject: [PATCH 014/131] if we can't generate a suggestion, we need to requery everything --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 0cf29d0..0af4a38 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -115,7 +115,7 @@ actionrequired() { else rsync -tu reservoir.json.new reservoir.json # if a temp is needed based on current BG and temp - openaps invoke requestedtemp.online.json + openaps invoke requestedtemp.online.json || return 0 grep rate requestedtemp.online.json return $? fi From 3937d1603d7f85ed50506d78ad5eff76d2d0c1de Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 13:05:24 -0700 Subject: [PATCH 015/131] 5 of 5 retries is redundant --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 0af4a38..7ade689 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -169,7 +169,7 @@ execute() { until openaps enact; do retry=`expr $retry + 1` echo "enact failed; retry $retry" - if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retry of $retries retries"; return $?; fi + if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retries retries"; return $?; fi sleep 10; done tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && return 0 From 10231c59a9bffc0f39bb539ab697f2b59a502a8c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 23:20:43 -0700 Subject: [PATCH 016/131] bgpredict.js was never used for anything --- bin/bgpredict.js | 62 ------------------------------------------------ 1 file changed, 62 deletions(-) delete mode 100644 bin/bgpredict.js diff --git a/bin/bgpredict.js b/bin/bgpredict.js deleted file mode 100644 index 588bb32..0000000 --- a/bin/bgpredict.js +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env node - -/* - Predict Blood Glucose (BG) - - Copyright (c) 2015 OpenAPS Contributors - - 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. -*/ - -function isfLookup() { - var now = new Date(); - //isf_data.sensitivities.sort(function (a, b) { return a.offset > b.offset }); - var isfSchedule = isf_data.sensitivities[isf_data.sensitivities.length - 1] - - for (var i = 0; i < isf_data.sensitivities.length - 1; i++) { - if ((now >= getTime(isf_data.sensitivities[i].offset)) && (now < getTime(isf_data.sensitivities[i + 1].offset))) { - isfSchedule = isf_data.sensitivities[i]; - break; - } - } - isf = isfSchedule.sensitivity; -} - - -if (!module.parent) { - - var glucose_input = process.argv.slice(2, 3).pop() - var iob_input = process.argv.slice(3, 4).pop() - var isf_input = process.argv.slice(4, 5).pop() - - if (!glucose_input || !iob_input || !isf_input) { - console.log('usage: ', process.argv.slice(0, 2), ' '); - process.exit(1); - } - - var cwd = process.cwd() - var glucose_data = require(cwd + '/' + glucose_input); - var bgnow = glucose_data[0].glucose; - var delta = bgnow - glucose_data[1].glucose; - var tick; - if (delta < 0) { tick = delta; } else { tick = "+" + delta; } - var iob_data = require(cwd + '/' + iob_input); - iob = iob_data.iob.toFixed(2); - var isf_data = require(cwd + '/' + isf_input); - var isf; - isfLookup(); - var eventualBG = Math.round( bgnow - ( iob * isf ) ); - - var prediction = { "bg" : bgnow, "iob" : iob, "eventualBG" : eventualBG } - - console.log(JSON.stringify(prediction)); -} From 5e7b843899617031532ec69b69effa6dc032cfbd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 23:29:43 -0700 Subject: [PATCH 017/131] retry querypump until findpumphistory succeeds, and sleep more during tight loop to avoid stepping on other pi's --- bin/loop.sh | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 7ade689..cb151d6 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -130,10 +130,15 @@ execute() { bail "Carelink USB already in use or not available."; return $? fi - #getpumpstatus - echo "Querying pump" && querypump 2>/dev/null - - upload + retries=5 + retry=0 + until findpumphistory; do + echo "Querying pump" && querypump 2>/dev/null + retry=`expr $retry + 1` + echo "querypump failed; retry $retry" + if [ $retry -ge $retries ]; then bail "Failed to query pump historyafter $retries retries"; return $?; fi + sleep 10; + done # get glucose again in case the pump queries took awhile getglucose @@ -230,6 +235,6 @@ while(true); do openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log echo -n "-" >> /var/log/openaps/easy.log - sleep 5 + sleep 30 done done From e9d229c4cb0e61a39f6e4026890a4ad5f54a7c54 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 23:57:36 -0700 Subject: [PATCH 018/131] no need to retry inside a retry loop --- bin/loop.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index cb151d6..46100c7 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -75,7 +75,7 @@ getpumpstatus() { } # query pump, and update pump data files if successful querypump() { - ( openaps pumpquery || openaps pumpquery ) 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) + openaps pumpquery 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) findclocknew && grep T clock.json.new && ( rsync -tu clock.json.new clock.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log grep -q timestamp pumphistory.json.new && ( rsync -tu pumphistory.json.new pumphistory.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log @@ -136,7 +136,7 @@ execute() { echo "Querying pump" && querypump 2>/dev/null retry=`expr $retry + 1` echo "querypump failed; retry $retry" - if [ $retry -ge $retries ]; then bail "Failed to query pump historyafter $retries retries"; return $?; fi + if [ $retry -ge $retries ]; then bail "Failed to query pump history after $retries retries"; return $?; fi sleep 10; done From 358688ad076827068eef7b0e4221f2404b8b0ac9 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 7 Sep 2015 23:59:47 -0700 Subject: [PATCH 019/131] sleep 30s in between pump queries to give other Pi's a chance --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 46100c7..06bc9e4 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -137,7 +137,7 @@ execute() { retry=`expr $retry + 1` echo "querypump failed; retry $retry" if [ $retry -ge $retries ]; then bail "Failed to query pump history after $retries retries"; return $?; fi - sleep 10; + sleep 30; done # get glucose again in case the pump queries took awhile From 17ad85b3c58e143dec60adaa5457325f7f206b14 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 00:13:35 -0700 Subject: [PATCH 020/131] let's try running each pumpquery report individually so they don't have to all succeed on the same run --- bin/loop.sh | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 06bc9e4..40a08df 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -75,9 +75,12 @@ getpumpstatus() { } # query pump, and update pump data files if successful querypump() { - openaps pumpquery 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) + #openaps pumpquery 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) + openaps report invoke clock.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) findclocknew && grep T clock.json.new && ( rsync -tu clock.json.new clock.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log + openaps report invoke currenttemp.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log + openaps report invoke pumphistory.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) grep -q timestamp pumphistory.json.new && ( rsync -tu pumphistory.json.new pumphistory.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log upload return 0 @@ -132,7 +135,7 @@ execute() { retries=5 retry=0 - until findpumphistory; do + until findpumphistory && findclocknew; do echo "Querying pump" && querypump 2>/dev/null retry=`expr $retry + 1` echo "querypump failed; retry $retry" From 8feca00a155e75d5610ed23f1640cf5a53c0ed56 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 00:25:37 -0700 Subject: [PATCH 021/131] findclock instead of findclocknew --- bin/loop.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 40a08df..b207a0b 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -96,6 +96,7 @@ suggest() { getpumpsettings() { ~/openaps-js/bin/pumpsettings.sh; } # functions for making sure we have up-to-date data before proceeding +findclock() { find clock.json -mmin -10 | egrep -q '.*'; } findclocknew() { find clock.json.new -mmin -10 | egrep -q '.*'; } findglucose() { find glucose.json -mmin -10 | egrep -q '.*'; } findpumphistory() { find pumphistory.json -mmin -10 | egrep -q '.*'; } @@ -135,7 +136,8 @@ execute() { retries=5 retry=0 - until findpumphistory && findclocknew; do + echo "Querying pump" && querypump 2>/dev/null + until findpumphistory && findclock; do echo "Querying pump" && querypump 2>/dev/null retry=`expr $retry + 1` echo "querypump failed; retry $retry" From bd675e51a763f590003f042363dbb3d8d09eec73 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 00:28:25 -0700 Subject: [PATCH 022/131] background the upload process and immediately continue --- bin/loop.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index b207a0b..a52975d 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -86,7 +86,10 @@ querypump() { return 0 } # try to upload pumphistory data -upload() { findpumphistory && ~/bin/openaps-mongo.sh; ping -c 1 google.com > /dev/null && touch /tmp/openaps.online; } +upload() { + findpumphistory && ~/bin/openaps-mongo.sh & + ping -c 1 google.com > /dev/null && touch /tmp/openaps.online +} # if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) suggest() { openaps suggest || echo -n "!" >> /var/log/openaps/easy.log From bf4dbaadee454e19a74cf15ef1d3ce3bff061483 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 00:40:31 -0700 Subject: [PATCH 023/131] refresh glucose and currenttemp before deciding if action is required --- bin/loop.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/loop.sh b/bin/loop.sh index a52975d..9787bcd 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -236,8 +236,10 @@ while(true); do sleep 5 done requery + getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log # set a new reservoir baseline and watch for changes (boluses) openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json + openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log until actionrequired; do getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log From 467797fa1f5ea73dbcef9251c3c3b5cb3a94a8b1 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 00:46:39 -0700 Subject: [PATCH 024/131] try or retry; there is no fail --- bin/loop.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 9787bcd..0d1087f 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -141,9 +141,8 @@ execute() { retry=0 echo "Querying pump" && querypump 2>/dev/null until findpumphistory && findclock; do - echo "Querying pump" && querypump 2>/dev/null + echo "Querying pump (try $retry)" && querypump 2>/dev/null retry=`expr $retry + 1` - echo "querypump failed; retry $retry" if [ $retry -ge $retries ]; then bail "Failed to query pump history after $retries retries"; return $?; fi sleep 30; done From ea664612c07c5a9fab21b5efe78cc25105a146d7 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 01:10:56 -0700 Subject: [PATCH 025/131] keep openaps.lock when tight-looping --- bin/loop.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/loop.sh b/bin/loop.sh index 0d1087f..564e9e8 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -240,6 +240,7 @@ while(true); do openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log until actionrequired; do + touch /tmp/openaps.lock getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log From 792f42c280692c6fef276264ae1d2779a7df83a2 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 02:02:20 -0700 Subject: [PATCH 026/131] disable mongo uploads --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 564e9e8..9d81917 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -87,7 +87,7 @@ querypump() { } # try to upload pumphistory data upload() { - findpumphistory && ~/bin/openaps-mongo.sh & + #findpumphistory && ~/bin/openaps-mongo.sh & ping -c 1 google.com > /dev/null && touch /tmp/openaps.online } # if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) From b510c3f3e5ab58e86160cf5ce94211434ab91767 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 02:12:26 -0700 Subject: [PATCH 027/131] clock.json is still required to get up-to-date IOB, so refresh it --- bin/loop.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/loop.sh b/bin/loop.sh index 9d81917..01a0c70 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -244,6 +244,8 @@ while(true); do getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + openaps invoke clock.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + findclocknew && grep T clock.json.new && rsync -tu clock.json.new clock.json || echo -n "!" >> /var/log/openaps/easy.log echo -n "-" >> /var/log/openaps/easy.log sleep 30 done From 77895fa157043ea30c244e1220be16f135cb1a20 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 02:13:48 -0700 Subject: [PATCH 028/131] s/openaps invoke/openaps report invoke/ for compatibility --- bin/loop.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 01a0c70..6d01931 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -122,7 +122,7 @@ actionrequired() { else rsync -tu reservoir.json.new reservoir.json # if a temp is needed based on current BG and temp - openaps invoke requestedtemp.online.json || return 0 + openaps report invoke requestedtemp.online.json || return 0 grep rate requestedtemp.online.json return $? fi @@ -235,16 +235,16 @@ while(true); do sleep 5 done requery - getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log + getglucose && openaps report invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log # set a new reservoir baseline and watch for changes (boluses) - openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json - openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + openaps report invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json + openaps report invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log until actionrequired; do touch /tmp/openaps.lock - getglucose && openaps invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log - openaps invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log - openaps invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log - openaps invoke clock.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + getglucose && openaps report invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log + openaps report invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + openaps report invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + openaps report invoke clock.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log findclocknew && grep T clock.json.new && rsync -tu clock.json.new clock.json || echo -n "!" >> /var/log/openaps/easy.log echo -n "-" >> /var/log/openaps/easy.log sleep 30 From feaf1b46ac85ff29ce4136c418b8d63374758c98 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 21:58:37 -0700 Subject: [PATCH 029/131] spacing --- bin/determine-basal.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index cd36a10..70aeb50 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -180,10 +180,10 @@ if (!module.parent) { if (snoozeBG > profile_data.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 if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + "> basal " + profile_data.current_basal; + reason = tick + " and temp " + temps_data.rate + " > basal " + profile_data.current_basal; setTempBasal(0, 0); // cancel temp } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + "< basal " + profile_data.current_basal; + reason = tick + " and temp " + temps_data.rate + " < basal " + profile_data.current_basal; setTempBasal(0, 0); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; @@ -200,7 +200,7 @@ if (!module.parent) { rate = Math.round( rate * 1000 ) / 1000; // if required temp < existing temp basal if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) { - reason = "temp " + temps_data.rate + "<~ req " + rate + "U/hr"; + reason = "temp " + temps_data.rate + " <~ req " + rate + "U/hr"; console.error(reason); } else { reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; @@ -236,7 +236,7 @@ if (!module.parent) { setTempBasal(rate, 30); } else if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate < temps_data.rate + 0.1)) { // if required temp < existing temp basal - reason = "temp " + temps_data.rate + ">~ req " + rate + "U/hr"; + reason = "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; console.error(reason); } else { // required temp > existing temp basal reason = "temp " + temps_data.rate + "<" + rate + "U/hr"; From 35592f3a1253f24a149dc3b26151741781d240cf Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 8 Sep 2015 21:58:58 -0700 Subject: [PATCH 030/131] write iob to easy.log --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 6d01931..a918e9c 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -184,7 +184,7 @@ execute() { if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retries retries"; return $?; fi sleep 10; done - tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && return 0 + tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && cat iob.json | json_pp | grep '"iob' >> /var/log/openaps/easy.log && return 0 fi } From 801257b7c756fc8c8af82d00da739829d815cb96 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 9 Sep 2015 22:49:42 -0700 Subject: [PATCH 031/131] bump package version, just because --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9ee57d..0c5e076 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openaps-js", - "version": "0.0.5", + "version": "0.0.7", "description": "openaps js plugins", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" From 2438da041ecd248d42b85bd9bb60954a8236fa64 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 11:43:57 -0700 Subject: [PATCH 032/131] ns-upload.sh --- bin/loop.sh | 3 ++- bin/ns-upload.sh | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100755 bin/ns-upload.sh diff --git a/bin/loop.sh b/bin/loop.sh index a918e9c..88d17da 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -88,7 +88,8 @@ querypump() { # try to upload pumphistory data upload() { #findpumphistory && ~/bin/openaps-mongo.sh & - ping -c 1 google.com > /dev/null && touch /tmp/openaps.online + ~/openaps-js/bin/ns-upload.sh + #ping -c 1 google.com > /dev/null && touch /tmp/openaps.online } # if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) suggest() { diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh new file mode 100755 index 0000000..20582e1 --- /dev/null +++ b/bin/ns-upload.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +HISTORY=${1-pumphistory.json} +OUTPUT=${2-pumphistory.ns.json} +#TZ=${3} + +cat $HISTORY | \ + json -e "this.medtronic = this._type;" | \ + #json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ + json -e "this.dateString = this.timestamp + '$(date +%z)'" | \ + json -e "this.type = 'medtronic'" | \ + json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ + > $OUTPUT + + +# requires API_SECRET and site to be set in calling environment (i.e. in crontab) +curl -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json && touch /tmp/openaps.online || echo "Unable to upload to $site." From 391b7418205dcd60a5ddf14259addd5002c43761 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 12:00:26 -0700 Subject: [PATCH 033/131] upload quietly --- bin/ns-upload.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index 20582e1..6546142 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -14,4 +14,4 @@ cat $HISTORY | \ # requires API_SECRET and site to be set in calling environment (i.e. in crontab) -curl -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json && touch /tmp/openaps.online || echo "Unable to upload to $site." +curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." From 65cad8cef28b39746d86efd317db2a44a71c132a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 13:02:23 -0700 Subject: [PATCH 034/131] author --- bin/ns-upload.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index 6546142..e4410e1 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -1,5 +1,7 @@ #!/bin/bash +# Author: Ben West, Maintainer: Scott Leibrand + HISTORY=${1-pumphistory.json} OUTPUT=${2-pumphistory.ns.json} #TZ=${3} From bed9cb0250390fa50d63d1d40f2e482d3d046d5d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 13:08:45 -0700 Subject: [PATCH 035/131] support timezone override --- bin/ns-upload.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index e4410e1..582f81c 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -4,12 +4,11 @@ HISTORY=${1-pumphistory.json} OUTPUT=${2-pumphistory.ns.json} -#TZ=${3} +TZ=${3-$(date +%z)} cat $HISTORY | \ json -e "this.medtronic = this._type;" | \ - #json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ - json -e "this.dateString = this.timestamp + '$(date +%z)'" | \ + json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ json -e "this.type = 'medtronic'" | \ json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ > $OUTPUT From 4fae5107f9cd9c7dd220dc2724cb5284190f15dd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 14:29:05 -0700 Subject: [PATCH 036/131] fix basal_iob > max_iob logic, and call out when no temp, setting --- bin/determine-basal.js | 63 ++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 50692ed..c7097c4 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -217,36 +217,45 @@ if (!module.parent) { } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target: // if iob is over max, just cancel any temps - var basal_iob = iob_data.iob - iob_data.bolusiob; + var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; if (basal_iob > max_iob) { - reason = "IOB " + basal_iob + ">" + max_iob; + reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; setTempBasal(0, 0); - } - // calculate 30m high-temp required to get projected BG down to target - // additional insulin required to get down to max bg: - var insulinReq = (eventualBG - target_bg) / profile_data.sens; - // if that would put us over max_iob, then reduce accordingly - insulinReq = Math.min(insulinReq, max_iob-basal_iob); + } else { + // calculate 30m high-temp required to get projected BG down to target + // additional insulin required to get down to max bg: + var insulinReq = (eventualBG - target_bg) / profile_data.sens; + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-basal_iob) { + reason = "max_iob " + max_iob + ", "; + insulinReq = max_iob-basal_iob; + } - // rate required to deliver insulinReq more insulin over 30m: - var rate = profile_data.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; - maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); - if (rate > maxSafeBasal) { - rate = maxSafeBasal; - //console.error(maxSafeBasal); - } - var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; - if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; - setTempBasal(rate, 30); - } - else if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate < temps_data.rate + 0.1)) { // if required temp < existing temp basal - reason = "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; - console.error(reason); - } else { // required temp > existing temp basal - reason = "temp " + temps_data.rate + "<" + rate + "U/hr"; - setTempBasal(rate, 30); + // rate required to deliver insulinReq more insulin over 30m: + var rate = profile_data.current_basal + (2 * insulinReq); + rate = Math.round( rate * 1000 ) / 1000; + + maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); + if (rate > maxSafeBasal) { + rate = maxSafeBasal; + //console.error(maxSafeBasal); + } + var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; + if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate + reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; + setTempBasal(rate, 30); + } + else if (typeof temps_data.rate == 'undefined' || temps_data.rate == 0) { // no temp is set + reason += "no temp, setting " + rate + "U/hr"; + setTempBasal(rate, 30); + } + else if (temps_data.duration > 0 && rate < temps_data.rate + 0.1) { // if required temp <~ existing temp basal + reason += "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; + console.error(reason); + } else { // required temp > existing temp basal + reason += "temp " + temps_data.rate + "<" + rate + "U/hr"; + setTempBasal(rate, 30); + } } } else { From f70e168e5eeb0789b2796daedc3b9333b5075583 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 15:26:12 -0700 Subject: [PATCH 037/131] openaps is writing incorrect dates: override --- bin/ns-upload.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index 582f81c..e195783 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -10,7 +10,8 @@ cat $HISTORY | \ json -e "this.medtronic = this._type;" | \ json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ json -e "this.type = 'medtronic'" | \ - json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ + #json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ + json -e "this.date = new Date(Date.parse(this.dateString)).getTime( )" \ > $OUTPUT From 1d2e4f9893f20c9c7936478b42238a1579bcb830 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 15:57:11 -0700 Subject: [PATCH 038/131] Revert "openaps is writing incorrect dates: override" Fixed incorrect dates by upgrading decocare on affected Pi This reverts commit f70e168e5eeb0789b2796daedc3b9333b5075583. --- bin/ns-upload.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index e195783..582f81c 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -10,8 +10,7 @@ cat $HISTORY | \ json -e "this.medtronic = this._type;" | \ json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ json -e "this.type = 'medtronic'" | \ - #json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ - json -e "this.date = new Date(Date.parse(this.dateString)).getTime( )" \ + json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ > $OUTPUT From 72223ec15f04d5779a2900a916f33bf334553785 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 16:17:01 -0700 Subject: [PATCH 039/131] return requestedTemp --- bin/determine-basal.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index c7097c4..2bcf468 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -54,6 +54,9 @@ function setTempBasal(rate, duration) { requestedTemp.duration = duration; requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; + requestedTemp.reason = reason; + console.log(JSON.stringify(requestedTemp)); + return requestedTemp; }; @@ -151,16 +154,16 @@ if (!module.parent) { console.error(reason); if (glucose_status.delta > 0) { // if BG is rising if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running - setTempBasal(0, 0); // cancel high temp + return setTempBasal(0, 0); // cancel high temp } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB - setTempBasal(0, 0); // cancel low temp + return setTempBasal(0, 0); // cancel low temp } else { reason = bg + "<" + threshold + "; no high-temp to cancel"; console.error(reason); } } else { // BG is not yet rising - setTempBasal(0, 30); + return setTempBasal(0, 30); } } else { @@ -174,7 +177,7 @@ if (!module.parent) { console.error(reason); } else { reason = tick + " and eventualBG " + eventualBG; - setTempBasal(0, 0); // cancel temp + return setTempBasal(0, 0); // cancel temp } } else { reason = tick + "; no temp to cancel"; @@ -187,10 +190,10 @@ if (!module.parent) { // if BG is falling and high-temped, or rising and low-temped, cancel if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) { reason = tick + " and temp " + temps_data.rate + " > basal " + profile_data.current_basal; - setTempBasal(0, 0); // cancel temp + return setTempBasal(0, 0); // cancel temp } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) { reason = tick + " and temp " + temps_data.rate + " < basal " + profile_data.current_basal; - setTempBasal(0, 0); // cancel temp + return setTempBasal(0, 0); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(reason); @@ -210,8 +213,7 @@ if (!module.parent) { console.error(reason); } else { reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; - //console.error(reason); - setTempBasal(rate, 30); + return setTempBasal(rate, 30); } } @@ -220,7 +222,7 @@ if (!module.parent) { var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; if (basal_iob > max_iob) { reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; - setTempBasal(0, 0); + return setTempBasal(0, 0); } else { // calculate 30m high-temp required to get projected BG down to target // additional insulin required to get down to max bg: @@ -243,25 +245,25 @@ if (!module.parent) { var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; - setTempBasal(rate, 30); + return setTempBasal(rate, 30); } else if (typeof temps_data.rate == 'undefined' || temps_data.rate == 0) { // no temp is set reason += "no temp, setting " + rate + "U/hr"; - setTempBasal(rate, 30); + return setTempBasal(rate, 30); } else if (temps_data.duration > 0 && rate < temps_data.rate + 0.1) { // if required temp <~ existing temp basal reason += "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; console.error(reason); } else { // required temp > existing temp basal reason += "temp " + temps_data.rate + "<" + rate + "U/hr"; - setTempBasal(rate, 30); + return setTempBasal(rate, 30); } } } else { reason = eventualBG + " is in range. No temp required."; if (temps_data.duration > 0) { // if there is currently any temp basal running - setTempBasal(0, 0); // cancel temp + return setTempBasal(0, 0); // cancel temp } else { console.error(reason); } @@ -272,7 +274,7 @@ if (!module.parent) { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) { reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp"; - setTempBasal(profile_data.current_basal, 30); + return setTempBasal(profile_data.current_basal, 30); } } } else { @@ -285,6 +287,6 @@ if (!module.parent) { } -requestedTemp.reason = reason; -console.log(JSON.stringify(requestedTemp)); + requestedTemp.reason = reason; + console.log(JSON.stringify(requestedTemp)); } From 1f7af776e6474bb7186f7f56bad6dacacd334961 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 16:32:08 -0700 Subject: [PATCH 040/131] separate initial read of _data from everything else (function determine_basal) --- bin/determine-basal.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 2bcf468..13003fd 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -77,7 +77,12 @@ if (!module.parent) { var temps_data = require(cwd + '/' + temps_input); var iob_data = require(cwd + '/' + iob_input); var profile_data = require(cwd + '/' + profile_input); + var glucose_status = getLastGlucose(glucose_data); + requestedTemp = determine_basal(glucose_status, temps_data, iob_data, profile_data); + console.log(JSON.stringify(requestedTemp)); +} +function determine_basal(glucose_status, temps_data, iob_data, profile_data) { if (typeof profile_data === 'undefined' || typeof profile_data.current_basal === 'undefined') { console.error('Error: could not get current basal rate'); process.exit(1); @@ -98,7 +103,6 @@ if (!module.parent) { } } - var glucose_status = getLastGlucose(glucose_data); var bg = glucose_status.glucose; var tick; if (glucose_status.delta >= 0) { tick = "+" + glucose_status.delta; } @@ -288,5 +292,5 @@ if (!module.parent) { requestedTemp.reason = reason; - console.log(JSON.stringify(requestedTemp)); + return requestedTemp; } From 93aa61a6fd4c8956a07ff8783a965adc334e555e Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 17:04:02 -0700 Subject: [PATCH 041/131] move BG data is too old check outside of function determine_basal for easier testability --- bin/determine-basal.js | 270 +++++++++++++++++++++-------------------- 1 file changed, 136 insertions(+), 134 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 13003fd..8f2264c 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -68,7 +68,7 @@ if (!module.parent) { var offline_input = process.argv.slice(6, 7).pop() if (!iob_input || !temps_input || !glucose_input || !profile_input) { - console.error('usage: ', process.argv.slice(0, 2), ' [Offline]'); + console.error('usage: ', process.argv.slice(0, 2), ' [Offline]'); process.exit(1); } @@ -78,7 +78,27 @@ if (!module.parent) { var iob_data = require(cwd + '/' + iob_input); var profile_data = require(cwd + '/' + profile_input); var glucose_status = getLastGlucose(glucose_data); - requestedTemp = determine_basal(glucose_status, temps_data, iob_data, profile_data); + + //if old reading from Dexcom do nothing + + var systemTime = new Date(); + var bgTime; + if (glucose_data[0].display_time) { + bgTime = new Date(glucose_data[0].display_time.replace('T', ' ')); + } else if (glucose_data[0].dateString) { + bgTime = new Date(glucose_data[0].dateString); + } else { console.error("Could not determine last BG time"); } + var minAgo = (systemTime - bgTime) / 60 / 1000 + + if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future + + requestedTemp = determine_basal(glucose_status, temps_data, iob_data, profile_data); + + } else { + var reason = "BG data is too old, or clock set incorrectly"; + console.error(reason); + return 1; + } console.log(JSON.stringify(requestedTemp)); } @@ -135,158 +155,140 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { }; - - //if old reading from Dexcom do nothing - - var systemTime = new Date(); - var bgTime; - if (glucose_data[0].display_time) { - bgTime = new Date(glucose_data[0].display_time.replace('T', ' ')); - } else if (glucose_data[0].dateString) { - bgTime = new Date(glucose_data[0].dateString); - } else { console.error("Could not determine last BG time"); } - var minAgo = (systemTime - bgTime) / 60 / 1000 - var threshold = profile_data.min_bg - 30; - var reason=""; - - if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future + if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose + var threshold = profile_data.min_bg - 30; + var reason=""; - if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose + if (bg < threshold) { // low glucose suspend mode: BG is < ~80 + reason = "BG " + bg + "<" + threshold; + console.error(reason); + if (glucose_status.delta > 0) { // if BG is rising + if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running + return setTempBasal(0, 0); // cancel high temp + } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB + return setTempBasal(0, 0); // cancel low temp + } else { + reason = bg + "<" + threshold + "; no high-temp to cancel"; + console.error(reason); + } + } + else { // BG is not yet rising + return setTempBasal(0, 30); + } + + } else { - if (bg < threshold) { // low glucose suspend mode: BG is < ~80 - reason = "BG " + bg + "<" + threshold; - console.error(reason); - if (glucose_status.delta > 0) { // if BG is rising - if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running - return setTempBasal(0, 0); // cancel high temp - } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB - return setTempBasal(0, 0); // cancel low temp - } else { - reason = bg + "<" + threshold + "; no high-temp to cancel"; + // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min + if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) { + if (temps_data.duration > 0) { // if there is currently any temp basal running + // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer + if (temps_data.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) { + reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile_data.max_bg; console.error(reason); + } else { + reason = tick + " and eventualBG " + eventualBG; + return setTempBasal(0, 0); // cancel temp } + } else { + reason = tick + "; no temp to cancel"; + console.error(reason); } - else { // BG is not yet rising - return setTempBasal(0, 30); - } - - } else { - - // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min - if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) { - if (temps_data.duration > 0) { // if there is currently any temp basal running - // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer - if (temps_data.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) { - reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile_data.max_bg; - console.error(reason); - } else { - reason = tick + " and eventualBG " + eventualBG; - return setTempBasal(0, 0); // cancel temp - } + + } else if (eventualBG < profile_data.min_bg) { // if eventual BG is below target: + // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) + if (snoozeBG > profile_data.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 + if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) { + reason = tick + " and temp " + temps_data.rate + " > basal " + profile_data.current_basal; + return setTempBasal(0, 0); // cancel temp + } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) { + reason = tick + " and temp " + temps_data.rate + " < basal " + profile_data.current_basal; + return setTempBasal(0, 0); // cancel temp } else { - reason = tick + "; no temp to cancel"; + reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(reason); } - - } else if (eventualBG < profile_data.min_bg) { // if eventual BG is below target: - // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) - if (snoozeBG > profile_data.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 - if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + " > basal " + profile_data.current_basal; - return setTempBasal(0, 0); // cancel temp - } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + " < basal " + profile_data.current_basal; - return setTempBasal(0, 0); // cancel temp - } else { - reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; - console.error(reason); - } + } else { + // calculate 30m low-temp required to get projected BG up to target + // negative insulin required to get up to min: + //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile_data.sens); + // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses + var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile_data.sens); + // rate required to deliver insulinReq less insulin over 30m: + var rate = profile_data.current_basal + (2 * insulinReq); + rate = Math.round( rate * 1000 ) / 1000; + // if required temp < existing temp basal + if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) { + reason = "temp " + temps_data.rate + " <~ req " + rate + "U/hr"; + console.error(reason); } else { - // calculate 30m low-temp required to get projected BG up to target - // negative insulin required to get up to min: - //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile_data.sens); - // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses - var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile_data.sens); - // rate required to deliver insulinReq less insulin over 30m: - var rate = profile_data.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; - // if required temp < existing temp basal - if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) { - reason = "temp " + temps_data.rate + " <~ req " + rate + "U/hr"; - console.error(reason); - } else { - reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; - return setTempBasal(rate, 30); - } + reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; + return setTempBasal(rate, 30); } + } - } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target: - // if iob is over max, just cancel any temps - var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; - if (basal_iob > max_iob) { - reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; - return setTempBasal(0, 0); - } else { - // calculate 30m high-temp required to get projected BG down to target - // additional insulin required to get down to max bg: - var insulinReq = (eventualBG - target_bg) / profile_data.sens; - // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-basal_iob) { - reason = "max_iob " + max_iob + ", "; - insulinReq = max_iob-basal_iob; - } + } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target: + // if iob is over max, just cancel any temps + var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; + if (basal_iob > max_iob) { + reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; + return setTempBasal(0, 0); + } else { + // calculate 30m high-temp required to get projected BG down to target + // additional insulin required to get down to max bg: + var insulinReq = (eventualBG - target_bg) / profile_data.sens; + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-basal_iob) { + reason = "max_iob " + max_iob + ", "; + insulinReq = max_iob-basal_iob; + } - // rate required to deliver insulinReq more insulin over 30m: - var rate = profile_data.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; + // rate required to deliver insulinReq more insulin over 30m: + var rate = profile_data.current_basal + (2 * insulinReq); + rate = Math.round( rate * 1000 ) / 1000; - maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); - if (rate > maxSafeBasal) { - rate = maxSafeBasal; - //console.error(maxSafeBasal); - } - var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; - if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; - return setTempBasal(rate, 30); - } - else if (typeof temps_data.rate == 'undefined' || temps_data.rate == 0) { // no temp is set - reason += "no temp, setting " + rate + "U/hr"; - return setTempBasal(rate, 30); - } - else if (temps_data.duration > 0 && rate < temps_data.rate + 0.1) { // if required temp <~ existing temp basal - reason += "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; - console.error(reason); - } else { // required temp > existing temp basal - reason += "temp " + temps_data.rate + "<" + rate + "U/hr"; - return setTempBasal(rate, 30); - } + maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); + if (rate > maxSafeBasal) { + rate = maxSafeBasal; + //console.error(maxSafeBasal); } - - } else { - reason = eventualBG + " is in range. No temp required."; - if (temps_data.duration > 0) { // if there is currently any temp basal running - return setTempBasal(0, 0); // cancel temp - } else { + var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; + if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate + reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; + return setTempBasal(rate, 30); + } + else if (typeof temps_data.rate == 'undefined' || temps_data.rate == 0) { // no temp is set + reason += "no temp, setting " + rate + "U/hr"; + return setTempBasal(rate, 30); + } + else if (temps_data.duration > 0 && rate < temps_data.rate + 0.1) { // if required temp <~ existing temp basal + reason += "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; console.error(reason); + } else { // required temp > existing temp basal + reason += "temp " + temps_data.rate + "<" + rate + "U/hr"; + return setTempBasal(rate, 30); } } - } - - if (offline_input == 'Offline') { - // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) { - reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp"; - return setTempBasal(profile_data.current_basal, 30); + + } else { + reason = eventualBG + " is in range. No temp required."; + if (temps_data.duration > 0) { // if there is currently any temp basal running + return setTempBasal(0, 0); // cancel temp + } else { + console.error(reason); } } - } else { - reason = "CGM is calibrating or in ??? state"; - console.error(reason); } - } else { - reason = "BG data is too old, or clock set incorrectly"; + + if (offline_input == 'Offline') { + // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working + if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) { + reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp"; + return setTempBasal(profile_data.current_basal, 30); + } + } + } else { + reason = "CGM is calibrating or in ??? state"; console.error(reason); } From 0c6759606b3d739e4dfcffd712cb45d330da47ce Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 17:05:53 -0700 Subject: [PATCH 042/131] rename temps_data to currenttemp and temps_input to currenttemp_input --- bin/determine-basal.js | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 8f2264c..04a71f7 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -62,19 +62,19 @@ function setTempBasal(rate, duration) { if (!module.parent) { var iob_input = process.argv.slice(2, 3).pop() - var temps_input = process.argv.slice(3, 4).pop() + var currenttemp_input = process.argv.slice(3, 4).pop() var glucose_input = process.argv.slice(4, 5).pop() var profile_input = process.argv.slice(5, 6).pop() var offline_input = process.argv.slice(6, 7).pop() - if (!iob_input || !temps_input || !glucose_input || !profile_input) { + if (!iob_input || !currenttemp_input || !glucose_input || !profile_input) { console.error('usage: ', process.argv.slice(0, 2), ' [Offline]'); process.exit(1); } var cwd = process.cwd() var glucose_data = require(cwd + '/' + glucose_input); - var temps_data = require(cwd + '/' + temps_input); + var currenttemp = require(cwd + '/' + currenttemp_input); var iob_data = require(cwd + '/' + iob_input); var profile_data = require(cwd + '/' + profile_input); var glucose_status = getLastGlucose(glucose_data); @@ -92,7 +92,7 @@ if (!module.parent) { if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future - requestedTemp = determine_basal(glucose_status, temps_data, iob_data, profile_data); + requestedTemp = determine_basal(glucose_status, currenttemp, iob_data, profile_data); } else { var reason = "BG data is too old, or clock set incorrectly"; @@ -102,7 +102,7 @@ if (!module.parent) { console.log(JSON.stringify(requestedTemp)); } -function determine_basal(glucose_status, temps_data, iob_data, profile_data) { +function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { if (typeof profile_data === 'undefined' || typeof profile_data.current_basal === 'undefined') { console.error('Error: could not get current basal rate'); process.exit(1); @@ -163,9 +163,9 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { reason = "BG " + bg + "<" + threshold; console.error(reason); if (glucose_status.delta > 0) { // if BG is rising - if (temps_data.rate > profile_data.current_basal) { // if a high-temp is running + if (currenttemp.rate > profile_data.current_basal) { // if a high-temp is running return setTempBasal(0, 0); // cancel high temp - } else if (temps_data.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB + } else if (currenttemp.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB return setTempBasal(0, 0); // cancel low temp } else { reason = bg + "<" + threshold + "; no high-temp to cancel"; @@ -180,9 +180,9 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) { - if (temps_data.duration > 0) { // if there is currently any temp basal running + if (currenttemp.duration > 0) { // if there is currently any temp basal running // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer - if (temps_data.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) { + if (currenttemp.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) { reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile_data.max_bg; console.error(reason); } else { @@ -198,11 +198,11 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) if (snoozeBG > profile_data.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 - if (glucose_status.delta < 0 && temps_data.rate > profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + " > basal " + profile_data.current_basal; + if (glucose_status.delta < 0 && currenttemp.rate > profile_data.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " > basal " + profile_data.current_basal; return setTempBasal(0, 0); // cancel temp - } else if (glucose_status.delta > 0 && temps_data.rate < profile_data.current_basal) { - reason = tick + " and temp " + temps_data.rate + " < basal " + profile_data.current_basal; + } else if (glucose_status.delta > 0 && currenttemp.rate < profile_data.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " < basal " + profile_data.current_basal; return setTempBasal(0, 0); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; @@ -218,8 +218,8 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { var rate = profile_data.current_basal + (2 * insulinReq); rate = Math.round( rate * 1000 ) / 1000; // if required temp < existing temp basal - if (typeof temps_data.rate !== 'undefined' && (temps_data.duration > 0 && rate > temps_data.rate - 0.1)) { - reason = "temp " + temps_data.rate + " <~ req " + rate + "U/hr"; + if (typeof currenttemp.rate !== 'undefined' && (currenttemp.duration > 0 && rate > currenttemp.rate - 0.1)) { + reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; console.error(reason); } else { reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; @@ -252,27 +252,27 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { rate = maxSafeBasal; //console.error(maxSafeBasal); } - var insulinScheduled = temps_data.duration * (temps_data.rate - profile_data.current_basal) / 60; + var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile_data.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - reason = temps_data.duration + "@" + temps_data.rate + " > req " + insulinReq + "U"; + reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; return setTempBasal(rate, 30); } - else if (typeof temps_data.rate == 'undefined' || temps_data.rate == 0) { // no temp is set + else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set reason += "no temp, setting " + rate + "U/hr"; return setTempBasal(rate, 30); } - else if (temps_data.duration > 0 && rate < temps_data.rate + 0.1) { // if required temp <~ existing temp basal - reason += "temp " + temps_data.rate + " >~ req " + rate + "U/hr"; + else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal + reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; console.error(reason); } else { // required temp > existing temp basal - reason += "temp " + temps_data.rate + "<" + rate + "U/hr"; + reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; return setTempBasal(rate, 30); } } } else { reason = eventualBG + " is in range. No temp required."; - if (temps_data.duration > 0) { // if there is currently any temp basal running + if (currenttemp.duration > 0) { // if there is currently any temp basal running return setTempBasal(0, 0); // cancel temp } else { console.error(reason); @@ -282,7 +282,7 @@ function determine_basal(glucose_status, temps_data, iob_data, profile_data) { if (offline_input == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!temps_data.duration || (temps_data.rate == profile_data.current_basal)) && !requestedTemp.duration) { + if ((!currenttemp.duration || (currenttemp.rate == profile_data.current_basal)) && !requestedTemp.duration) { reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp"; return setTempBasal(profile_data.current_basal, 30); } From 5b23b68b4d05fb7b2e5a172350a7315bd513bd9b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 17:09:17 -0700 Subject: [PATCH 043/131] rename profile_data to just profile --- bin/determine-basal.js | 78 +++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 04a71f7..c596a06 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -40,7 +40,7 @@ function getLastGlucose(data) { function setTempBasal(rate, duration) { - maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead else if (rate > maxSafeBasal) { rate = maxSafeBasal; } @@ -48,7 +48,7 @@ function setTempBasal(rate, duration) { // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp // so we can see on the pump that openaps is working if (duration == 0 && offline_input == 'Offline') { - rate = profile_data.current_basal; + rate = profile.current_basal; duration = 30; } @@ -76,7 +76,7 @@ if (!module.parent) { var glucose_data = require(cwd + '/' + glucose_input); var currenttemp = require(cwd + '/' + currenttemp_input); var iob_data = require(cwd + '/' + iob_input); - var profile_data = require(cwd + '/' + profile_input); + var profile = require(cwd + '/' + profile_input); var glucose_status = getLastGlucose(glucose_data); //if old reading from Dexcom do nothing @@ -92,7 +92,7 @@ if (!module.parent) { if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future - requestedTemp = determine_basal(glucose_status, currenttemp, iob_data, profile_data); + requestedTemp = determine_basal(glucose_status, currenttemp, iob_data, profile); } else { var reason = "BG data is too old, or clock set incorrectly"; @@ -102,21 +102,21 @@ if (!module.parent) { console.log(JSON.stringify(requestedTemp)); } -function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { - if (typeof profile_data === 'undefined' || typeof profile_data.current_basal === 'undefined') { +function determine_basal(glucose_status, currenttemp, iob_data, profile) { + if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { console.error('Error: could not get current basal rate'); process.exit(1); } - var max_iob = profile_data.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver + var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver // if target_bg is set, great. otherwise, if min and max are set, then set target to their average var target_bg; - if (typeof profile_data.target_bg !== 'undefined') { - target_bg = profile_data.target_bg; + if (typeof profile.target_bg !== 'undefined') { + target_bg = profile.target_bg; } else { - if (typeof profile_data.max_bg !== 'undefined' && typeof profile_data.max_bg !== 'undefined') { - target_bg = (profile_data.min_bg + profile_data.max_bg) / 2; + if (typeof profile.max_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') { + target_bg = (profile.min_bg + profile.max_bg) / 2; } else { console.error('Error: could not determine target_bg'); process.exit(1); @@ -129,17 +129,17 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { else { tick = glucose_status.delta; } console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2)); //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone - var bgi = -iob_data.activity * profile_data.sens * 5; + var bgi = -iob_data.activity * profile.sens * 5; console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1)); // project deviation over next 15 minutes var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) ); console.error("15m deviation: " + deviation.toFixed(0)); // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity - var naive_eventualBG = Math.round( bg - (iob_data.iob * profile_data.sens) ); + var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) ); // and adjust it for the deviation above var eventualBG = naive_eventualBG + deviation; // calculate what portion of that is due to bolusiob - var bolusContrib = iob_data.bolusiob * profile_data.sens; + var bolusContrib = iob_data.bolusiob * profile.sens; // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib ); // adjust that for deviation like we did eventualBG @@ -156,16 +156,16 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose - var threshold = profile_data.min_bg - 30; + var threshold = profile.min_bg - 30; var reason=""; if (bg < threshold) { // low glucose suspend mode: BG is < ~80 reason = "BG " + bg + "<" + threshold; console.error(reason); if (glucose_status.delta > 0) { // if BG is rising - if (currenttemp.rate > profile_data.current_basal) { // if a high-temp is running + if (currenttemp.rate > profile.current_basal) { // if a high-temp is running return setTempBasal(0, 0); // cancel high temp - } else if (currenttemp.duration && eventualBG > profile_data.max_bg) { // if low-temped and predicted to go high from negative IOB + } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB return setTempBasal(0, 0); // cancel low temp } else { reason = bg + "<" + threshold + "; no high-temp to cancel"; @@ -179,11 +179,11 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { } else { // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min - if ((glucose_status.delta > 0 && eventualBG < profile_data.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile_data.min_bg)) { + if ((glucose_status.delta > 0 && eventualBG < profile.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile.min_bg)) { if (currenttemp.duration > 0) { // if there is currently any temp basal running - // if it's a low-temp and eventualBG < profile_data.max_bg, let it run a bit longer - if (currenttemp.rate <= profile_data.current_basal && eventualBG < profile_data.max_bg) { - reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile_data.max_bg; + // if it's a low-temp and eventualBG < profile.max_bg, let it run a bit longer + if (currenttemp.rate <= profile.current_basal && eventualBG < profile.max_bg) { + reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; console.error(reason); } else { reason = tick + " and eventualBG " + eventualBG; @@ -194,15 +194,15 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { console.error(reason); } - } else if (eventualBG < profile_data.min_bg) { // if eventual BG is below target: + } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) - if (snoozeBG > profile_data.min_bg) { // if adding back in the bolus contribution BG would be above min + 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 - if (glucose_status.delta < 0 && currenttemp.rate > profile_data.current_basal) { - reason = tick + " and temp " + currenttemp.rate + " > basal " + profile_data.current_basal; + if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " > basal " + profile.current_basal; return setTempBasal(0, 0); // cancel temp - } else if (glucose_status.delta > 0 && currenttemp.rate < profile_data.current_basal) { - reason = tick + " and temp " + currenttemp.rate + " < basal " + profile_data.current_basal; + } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; return setTempBasal(0, 0); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; @@ -211,23 +211,23 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { } else { // calculate 30m low-temp required to get projected BG up to target // negative insulin required to get up to min: - //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile_data.sens); + //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile.sens); // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses - var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile_data.sens); + var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile.sens); // rate required to deliver insulinReq less insulin over 30m: - var rate = profile_data.current_basal + (2 * insulinReq); + var rate = profile.current_basal + (2 * insulinReq); 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)) { reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; console.error(reason); } else { - reason = "Eventual BG " + eventualBG + "<" + profile_data.min_bg; + reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; return setTempBasal(rate, 30); } } - } else if (eventualBG > profile_data.max_bg) { // if eventual BG is above target: + } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: // if iob is over max, just cancel any temps var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; if (basal_iob > max_iob) { @@ -236,7 +236,7 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { } else { // calculate 30m high-temp required to get projected BG down to target // additional insulin required to get down to max bg: - var insulinReq = (eventualBG - target_bg) / profile_data.sens; + var insulinReq = (eventualBG - target_bg) / profile.sens; // if that would put us over max_iob, then reduce accordingly if (insulinReq > max_iob-basal_iob) { reason = "max_iob " + max_iob + ", "; @@ -244,15 +244,15 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { } // rate required to deliver insulinReq more insulin over 30m: - var rate = profile_data.current_basal + (2 * insulinReq); + var rate = profile.current_basal + (2 * insulinReq); rate = Math.round( rate * 1000 ) / 1000; - maxSafeBasal = Math.min(profile_data.max_basal, 3 * profile_data.max_daily_basal, 4 * profile_data.current_basal); + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); if (rate > maxSafeBasal) { rate = maxSafeBasal; //console.error(maxSafeBasal); } - var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile_data.current_basal) / 60; + var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; return setTempBasal(rate, 30); @@ -282,9 +282,9 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile_data) { if (offline_input == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!currenttemp.duration || (currenttemp.rate == profile_data.current_basal)) && !requestedTemp.duration) { - reason = reason + "; setting current basal of " + profile_data.current_basal + " as temp"; - return setTempBasal(profile_data.current_basal, 30); + if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !requestedTemp.duration) { + reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; + return setTempBasal(profile.current_basal, 30); } } } else { From 6f1426056291096423030d430fe1ad95b7a04409 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 17:36:35 -0700 Subject: [PATCH 044/131] debugging console.error statements --- bin/determine-basal.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index c596a06..b183778 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -92,6 +92,10 @@ if (!module.parent) { if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future + console.error(JSON.stringify(glucose_status)); + console.error(JSON.stringify(currenttemp)); + console.error(JSON.stringify(iob_data)); + console.error(JSON.stringify(profile)); requestedTemp = determine_basal(glucose_status, currenttemp, iob_data, profile); } else { From 97551f8e11f4c322a4b4cc6d1b11c984fb8b1a3b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 17:37:48 -0700 Subject: [PATCH 045/131] move functions into a more logical order --- bin/determine-basal.js | 91 +++++++++++++++++++++--------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index b183778..1f100a8 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -15,51 +15,6 @@ THE SOFTWARE. */ -function getLastGlucose(data) { - - var now = data[0]; - var last = data[1]; - var avg; - //TODO: calculate average using system_time instead of assuming 1 data point every 5m - if (typeof data[3] !== 'undefined' && data[3].glucose > 30) { - avg = ( now.glucose - data[3].glucose) / 3; - } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) { - avg = ( now.glucose - data[2].glucose) / 2; - } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) { - avg = now.glucose - data[1].glucose; - } else { avg = 0; } - var o = { - delta: now.glucose - last.glucose - , glucose: now.glucose - , avgdelta: avg - }; - - return o; - -} - -function setTempBasal(rate, duration) { - - maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); - - if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead - else if (rate > maxSafeBasal) { rate = maxSafeBasal; } - - // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp - // so we can see on the pump that openaps is working - if (duration == 0 && offline_input == 'Offline') { - rate = profile.current_basal; - duration = 30; - } - - requestedTemp.duration = duration; - requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; - requestedTemp.reason = reason; - console.log(JSON.stringify(requestedTemp)); - return requestedTemp; -}; - - if (!module.parent) { var iob_input = process.argv.slice(2, 3).pop() var currenttemp_input = process.argv.slice(3, 4).pop() @@ -106,6 +61,30 @@ if (!module.parent) { console.log(JSON.stringify(requestedTemp)); } +function getLastGlucose(data) { + + var now = data[0]; + var last = data[1]; + var avg; + //TODO: calculate average using system_time instead of assuming 1 data point every 5m + if (typeof data[3] !== 'undefined' && data[3].glucose > 30) { + avg = ( now.glucose - data[3].glucose) / 3; + } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) { + avg = ( now.glucose - data[2].glucose) / 2; + } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) { + avg = now.glucose - data[1].glucose; + } else { avg = 0; } + var o = { + delta: now.glucose - last.glucose + , glucose: now.glucose + , avgdelta: avg + }; + + return o; + +} + + function determine_basal(glucose_status, currenttemp, iob_data, profile) { if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { console.error('Error: could not get current basal rate'); @@ -300,3 +279,25 @@ function determine_basal(glucose_status, currenttemp, iob_data, profile) { requestedTemp.reason = reason; return requestedTemp; } + +function setTempBasal(rate, duration) { + + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); + + if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead + else if (rate > maxSafeBasal) { rate = maxSafeBasal; } + + // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp + // so we can see on the pump that openaps is working + if (duration == 0 && offline_input == 'Offline') { + rate = profile.current_basal; + duration = 30; + } + + requestedTemp.duration = duration; + requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; + requestedTemp.reason = reason; + console.log(JSON.stringify(requestedTemp)); + return requestedTemp; +}; + From 7df7692bb30009cc73c47d872fea5256b5b2dddd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 18:37:00 -0700 Subject: [PATCH 046/131] refactor to export functions for testing and modularization --- bin/determine-basal.js | 431 +++++++++++++++++++++-------------------- 1 file changed, 222 insertions(+), 209 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 1f100a8..038d84b 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -16,6 +16,8 @@ */ if (!module.parent) { + var determinebasal = init(); + var iob_input = process.argv.slice(2, 3).pop() var currenttemp_input = process.argv.slice(3, 4).pop() var glucose_input = process.argv.slice(4, 5).pop() @@ -32,7 +34,7 @@ if (!module.parent) { var currenttemp = require(cwd + '/' + currenttemp_input); var iob_data = require(cwd + '/' + iob_input); var profile = require(cwd + '/' + profile_input); - var glucose_status = getLastGlucose(glucose_data); + var glucose_status = determinebasal.getLastGlucose(glucose_data); //if old reading from Dexcom do nothing @@ -51,7 +53,7 @@ if (!module.parent) { console.error(JSON.stringify(currenttemp)); console.error(JSON.stringify(iob_data)); console.error(JSON.stringify(profile)); - requestedTemp = determine_basal(glucose_status, currenttemp, iob_data, profile); + requestedTemp = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); } else { var reason = "BG data is too old, or clock set incorrectly"; @@ -61,243 +63,254 @@ if (!module.parent) { console.log(JSON.stringify(requestedTemp)); } -function getLastGlucose(data) { - - var now = data[0]; - var last = data[1]; - var avg; - //TODO: calculate average using system_time instead of assuming 1 data point every 5m - if (typeof data[3] !== 'undefined' && data[3].glucose > 30) { - avg = ( now.glucose - data[3].glucose) / 3; - } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) { - avg = ( now.glucose - data[2].glucose) / 2; - } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) { - avg = now.glucose - data[1].glucose; - } else { avg = 0; } - var o = { - delta: now.glucose - last.glucose - , glucose: now.glucose - , avgdelta: avg - }; - - return o; - -} +function init() { + var determinebasal = { + name: 'determine-basal' + , label: "OpenAPS Determine Basal" + , pluginType: 'pill-major' + }; -function determine_basal(glucose_status, currenttemp, iob_data, profile) { - if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { - console.error('Error: could not get current basal rate'); - process.exit(1); + determinebasal.getLastGlucose = function getLastGlucose(data) { + + var now = data[0]; + var last = data[1]; + var avg; + //TODO: calculate average using system_time instead of assuming 1 data point every 5m + if (typeof data[3] !== 'undefined' && data[3].glucose > 30) { + avg = ( now.glucose - data[3].glucose) / 3; + } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) { + avg = ( now.glucose - data[2].glucose) / 2; + } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) { + avg = now.glucose - data[1].glucose; + } else { avg = 0; } + var o = { + delta: now.glucose - last.glucose + , glucose: now.glucose + , avgdelta: avg + }; + + return o; + } - var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver - // if target_bg is set, great. otherwise, if min and max are set, then set target to their average - var target_bg; - if (typeof profile.target_bg !== 'undefined') { - target_bg = profile.target_bg; - } else { - if (typeof profile.max_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') { - target_bg = (profile.min_bg + profile.max_bg) / 2; - } else { - console.error('Error: could not determine target_bg'); + determinebasal.determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile) { + if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { + console.error('Error: could not get current basal rate'); process.exit(1); } - } - - var bg = glucose_status.glucose; - var tick; - if (glucose_status.delta >= 0) { tick = "+" + glucose_status.delta; } - else { tick = glucose_status.delta; } - console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2)); - //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone - var bgi = -iob_data.activity * profile.sens * 5; - console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1)); - // project deviation over next 15 minutes - var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) ); - console.error("15m deviation: " + deviation.toFixed(0)); - // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity - var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) ); - // and adjust it for the deviation above - var eventualBG = naive_eventualBG + deviation; - // calculate what portion of that is due to bolusiob - var bolusContrib = iob_data.bolusiob * profile.sens; - // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime - var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib ); - // adjust that for deviation like we did eventualBG - var snoozeBG = naive_snoozeBG + deviation; - console.error("BG: " + bg + tick + " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + ")"); - if (typeof eventualBG === 'undefined') { console.error('Error: could not calculate eventualBG'); } - var requestedTemp = { - 'temp': 'absolute' - , 'bg': bg - , 'tick': tick - , 'eventualBG': eventualBG - , 'snoozeBG': snoozeBG - }; - - - if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose - var threshold = profile.min_bg - 30; - var reason=""; - - if (bg < threshold) { // low glucose suspend mode: BG is < ~80 - reason = "BG " + bg + "<" + threshold; - console.error(reason); - if (glucose_status.delta > 0) { // if BG is rising - if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - return setTempBasal(0, 0); // cancel high temp - } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - return setTempBasal(0, 0); // cancel low temp - } else { - reason = bg + "<" + threshold + "; no high-temp to cancel"; - console.error(reason); - } - } - else { // BG is not yet rising - return setTempBasal(0, 30); + + var max_iob = profile.max_iob; // maximum amount of non-bolus IOB OpenAPS will ever deliver + + // if target_bg is set, great. otherwise, if min and max are set, then set target to their average + var target_bg; + if (typeof profile.target_bg !== 'undefined') { + target_bg = profile.target_bg; + } else { + if (typeof profile.max_bg !== 'undefined' && typeof profile.max_bg !== 'undefined') { + target_bg = (profile.min_bg + profile.max_bg) / 2; + } else { + console.error('Error: could not determine target_bg'); + process.exit(1); } + } - } else { + var bg = glucose_status.glucose; + var tick; + if (glucose_status.delta >= 0) { tick = "+" + glucose_status.delta; } + else { tick = glucose_status.delta; } + console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2)); + //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone + var bgi = -iob_data.activity * profile.sens * 5; + console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1)); + // project deviation over next 15 minutes + var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) ); + console.error("15m deviation: " + deviation.toFixed(0)); + // calculate the naive (bolus calculator math) eventual BG based on net IOB and sensitivity + var naive_eventualBG = Math.round( bg - (iob_data.iob * profile.sens) ); + // and adjust it for the deviation above + var eventualBG = naive_eventualBG + deviation; + // calculate what portion of that is due to bolusiob + var bolusContrib = iob_data.bolusiob * profile.sens; + // and add it back in to get snoozeBG, plus another 50% to avoid low-temping at mealtime + var naive_snoozeBG = Math.round( naive_eventualBG + 1.5 * bolusContrib ); + // adjust that for deviation like we did eventualBG + var snoozeBG = naive_snoozeBG + deviation; + console.error("BG: " + bg + tick + " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + ")"); + if (typeof eventualBG === 'undefined') { console.error('Error: could not calculate eventualBG'); } + var requestedTemp = { + 'temp': 'absolute' + , 'bg': bg + , 'tick': tick + , 'eventualBG': eventualBG + , 'snoozeBG': snoozeBG + }; + + + if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose + var threshold = profile.min_bg - 30; + var reason=""; - // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min - if ((glucose_status.delta > 0 && eventualBG < profile.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile.min_bg)) { - if (currenttemp.duration > 0) { // if there is currently any temp basal running - // if it's a low-temp and eventualBG < profile.max_bg, let it run a bit longer - if (currenttemp.rate <= profile.current_basal && eventualBG < profile.max_bg) { - reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; - console.error(reason); + if (bg < threshold) { // low glucose suspend mode: BG is < ~80 + reason = "BG " + bg + "<" + threshold; + console.error(reason); + if (glucose_status.delta > 0) { // if BG is rising + if (currenttemp.rate > profile.current_basal) { // if a high-temp is running + return determinebasal.setTempBasal(0, 0); // cancel high temp + } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB + return determinebasal.setTempBasal(0, 0); // cancel low temp } else { - reason = tick + " and eventualBG " + eventualBG; - return setTempBasal(0, 0); // cancel temp + reason = bg + "<" + threshold + "; no high-temp to cancel"; + console.error(reason); } - } else { - reason = tick + "; no temp to cancel"; - console.error(reason); } - - } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: - // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) - 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 - if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { - reason = tick + " and temp " + currenttemp.rate + " > basal " + profile.current_basal; - return setTempBasal(0, 0); // cancel temp - } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { - reason = tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; - return setTempBasal(0, 0); // cancel temp + else { // BG is not yet rising + return determinebasal.setTempBasal(0, 30); + } + + } else { + + // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min + if ((glucose_status.delta > 0 && eventualBG < profile.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile.min_bg)) { + if (currenttemp.duration > 0) { // if there is currently any temp basal running + // if it's a low-temp and eventualBG < profile.max_bg, let it run a bit longer + if (currenttemp.rate <= profile.current_basal && eventualBG < profile.max_bg) { + reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; + console.error(reason); + } else { + reason = tick + " and eventualBG " + eventualBG; + return determinebasal.setTempBasal(0, 0); // cancel temp + } } else { - reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; + reason = tick + "; no temp to cancel"; console.error(reason); } - } else { - // calculate 30m low-temp required to get projected BG up to target - // negative insulin required to get up to min: - //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile.sens); - // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses - var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile.sens); - // rate required to deliver insulinReq less insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - 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)) { - reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; - console.error(reason); + + } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: + // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) + 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 + if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " > basal " + profile.current_basal; + return determinebasal.setTempBasal(0, 0); // cancel temp + } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { + reason = tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; + return determinebasal.setTempBasal(0, 0); // cancel temp + } else { + reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; + console.error(reason); + } } else { - reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; - return setTempBasal(rate, 30); + // calculate 30m low-temp required to get projected BG up to target + // negative insulin required to get up to min: + //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile.sens); + // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses + var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile.sens); + // rate required to deliver insulinReq less insulin over 30m: + var rate = profile.current_basal + (2 * insulinReq); + 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)) { + reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; + console.error(reason); + } else { + reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; + return determinebasal.setTempBasal(rate, 30); + } } - } - } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: - // if iob is over max, just cancel any temps - var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; - if (basal_iob > max_iob) { - reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; - return setTempBasal(0, 0); - } else { - // calculate 30m high-temp required to get projected BG down to target - // additional insulin required to get down to max bg: - var insulinReq = (eventualBG - target_bg) / profile.sens; - // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-basal_iob) { - reason = "max_iob " + max_iob + ", "; - insulinReq = max_iob-basal_iob; - } + } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: + // if iob is over max, just cancel any temps + var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; + if (basal_iob > max_iob) { + reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; + return determinebasal.setTempBasal(0, 0); + } else { + // calculate 30m high-temp required to get projected BG down to target + // additional insulin required to get down to max bg: + var insulinReq = (eventualBG - target_bg) / profile.sens; + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-basal_iob) { + reason = "max_iob " + max_iob + ", "; + insulinReq = max_iob-basal_iob; + } - // rate required to deliver insulinReq more insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; + // rate required to deliver insulinReq more insulin over 30m: + var rate = profile.current_basal + (2 * insulinReq); + rate = Math.round( rate * 1000 ) / 1000; - maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); - if (rate > maxSafeBasal) { - rate = maxSafeBasal; - //console.error(maxSafeBasal); - } - var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; - if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; - return setTempBasal(rate, 30); - } - else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set - reason += "no temp, setting " + rate + "U/hr"; - return setTempBasal(rate, 30); + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); + if (rate > maxSafeBasal) { + rate = maxSafeBasal; + //console.error(maxSafeBasal); + } + var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; + if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate + reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; + return determinebasal.setTempBasal(rate, 30); + } + else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set + reason += "no temp, setting " + rate + "U/hr"; + return determinebasal.setTempBasal(rate, 30); + } + else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal + reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; + console.error(reason); + } else { // required temp > existing temp basal + reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; + return determinebasal.setTempBasal(rate, 30); + } } - else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal - reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; + + } else { + reason = eventualBG + " is in range. No temp required."; + if (currenttemp.duration > 0) { // if there is currently any temp basal running + return determinebasal.setTempBasal(0, 0); // cancel temp + } else { console.error(reason); - } else { // required temp > existing temp basal - reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; - return setTempBasal(rate, 30); } } - - } else { - reason = eventualBG + " is in range. No temp required."; - if (currenttemp.duration > 0) { // if there is currently any temp basal running - return setTempBasal(0, 0); // cancel temp - } else { - console.error(reason); - } } - } - - if (offline_input == 'Offline') { - // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !requestedTemp.duration) { - reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; - return setTempBasal(profile.current_basal, 30); + + if (offline_input == 'Offline') { + // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working + if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !requestedTemp.duration) { + reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; + return determinebasal.setTempBasal(profile.current_basal, 30); + } } + } else { + reason = "CGM is calibrating or in ??? state"; + console.error(reason); } - } else { - reason = "CGM is calibrating or in ??? state"; - console.error(reason); - } - - requestedTemp.reason = reason; - return requestedTemp; -} -function setTempBasal(rate, duration) { - - maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); - - if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead - else if (rate > maxSafeBasal) { rate = maxSafeBasal; } - - // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp - // so we can see on the pump that openaps is working - if (duration == 0 && offline_input == 'Offline') { - rate = profile.current_basal; - duration = 30; + requestedTemp.reason = reason; + return requestedTemp; } - requestedTemp.duration = duration; - requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; - requestedTemp.reason = reason; - console.log(JSON.stringify(requestedTemp)); - return requestedTemp; -}; + determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, requestedTemp, offline_input) { + + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); + + if (rate < 0) { rate = 0; } // if >30m @ 0 required, zero temp will be extended to 30m instead + else if (rate > maxSafeBasal) { rate = maxSafeBasal; } + + // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp + // so we can see on the pump that openaps is working + if (duration == 0 && offline_input == 'Offline') { + rate = profile.current_basal; + duration = 30; + } + + requestedTemp.duration = duration; + requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; + requestedTemp.reason = reason; + console.log(JSON.stringify(requestedTemp)); + return requestedTemp; + }; + return determinebasal; +} +module.exports = init; From 5d821a4347754dd8d611cb9ecdd84e568a5d7bcd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 18:37:34 -0700 Subject: [PATCH 047/131] initial tests of function setTempBasal --- tests/determine-basal.test.js | 80 +++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 tests/determine-basal.test.js diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js new file mode 100644 index 0000000..332af40 --- /dev/null +++ b/tests/determine-basal.test.js @@ -0,0 +1,80 @@ +'use strict'; + +require('should'); + +describe('setTempBasal', function ( ) { + var determinebasal = require('../bin/determine-basal')(); + + //function setTempBasal(rate, duration, profile, requestedTemp) + + it('should cancel temp', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(0, 0, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(0); + cancel.duration.should.equal(0); + }); + + it('should set zero temp', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(0, 30, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(0); + cancel.duration.should.equal(30); + }); + + it('should set high temp', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(2, 30, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(2); + cancel.duration.should.equal(30); + }); + + it('should limit high temp to max_basal', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(4, 30, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(3); + cancel.duration.should.equal(30); + }); + + it('should limit high temp to 3 * max_daily_basal', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":10.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(6, 30, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(3.9); + cancel.duration.should.equal(30); + }); + + it('should limit high temp to 4 * current_basal', function () { + var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(6, 30, profile, requestedTemp); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(2.8); + cancel.duration.should.equal(30); + }); + + it('should set current_basal as temp on cancel if offline', function () { + var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 }; + var requestedTemp = {}; + //console.error(JSON.stringify(profile)); + var cancel = determinebasal.setTempBasal(0, 0, profile, requestedTemp, "Offline"); + //console.error(JSON.stringify(cancel)); + cancel.rate.should.equal(0.7); + cancel.duration.should.equal(30); + }); + +}); From 8c8a58ca727ac9b173610e601babea46f75aa097 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 19:48:42 -0700 Subject: [PATCH 048/131] still having issues with timezones; remove timezone override again --- bin/ns-upload.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index 582f81c..95b9a9e 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -4,15 +4,16 @@ HISTORY=${1-pumphistory.json} OUTPUT=${2-pumphistory.ns.json} -TZ=${3-$(date +%z)} +#TZ=${3-$(date +%z)} cat $HISTORY | \ json -e "this.medtronic = this._type;" | \ - json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ + #json -e "this.dateString = this.timestamp + '$(TZ=TZ date +%z)'" | \ + json -e "this.dateString = this.timestamp + '$(date +%z)'" | \ json -e "this.type = 'medtronic'" | \ json -e "this.date = this.date ? this.date : new Date(Date.parse(this.dateString)).getTime( )" \ > $OUTPUT # requires API_SECRET and site to be set in calling environment (i.e. in crontab) -curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." +curl -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." From 791d4d272cce8a476abfeb491210f9fa6233e25f Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 21:48:58 -0700 Subject: [PATCH 049/131] don't use global varaibles inside setTempBasal, and s/offline_input/offline/g --- bin/determine-basal.js | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 038d84b..1128565 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -22,7 +22,7 @@ if (!module.parent) { var currenttemp_input = process.argv.slice(3, 4).pop() var glucose_input = process.argv.slice(4, 5).pop() var profile_input = process.argv.slice(5, 6).pop() - var offline_input = process.argv.slice(6, 7).pop() + var offline = process.argv.slice(6, 7).pop() if (!iob_input || !currenttemp_input || !glucose_input || !profile_input) { console.error('usage: ', process.argv.slice(0, 2), ' [Offline]'); @@ -157,16 +157,16 @@ function init() { console.error(reason); if (glucose_status.delta > 0) { // if BG is rising if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - return determinebasal.setTempBasal(0, 0); // cancel high temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel high temp } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - return determinebasal.setTempBasal(0, 0); // cancel low temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel low temp } else { reason = bg + "<" + threshold + "; no high-temp to cancel"; console.error(reason); } } else { // BG is not yet rising - return determinebasal.setTempBasal(0, 30); + return determinebasal.setTempBasal(0, 30, profile, requestedTemp, offline); } } else { @@ -180,7 +180,7 @@ function init() { console.error(reason); } else { reason = tick + " and eventualBG " + eventualBG; - return determinebasal.setTempBasal(0, 0); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp } } else { reason = tick + "; no temp to cancel"; @@ -193,10 +193,10 @@ function init() { // if BG is falling and high-temped, or rising and low-temped, cancel if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { reason = tick + " and temp " + currenttemp.rate + " > basal " + profile.current_basal; - return determinebasal.setTempBasal(0, 0); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { reason = tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; - return determinebasal.setTempBasal(0, 0); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(reason); @@ -216,7 +216,7 @@ function init() { console.error(reason); } else { reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; - return determinebasal.setTempBasal(rate, 30); + return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); } } @@ -248,36 +248,36 @@ function init() { var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; - return determinebasal.setTempBasal(rate, 30); + return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); } else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set reason += "no temp, setting " + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30); + return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); } else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; console.error(reason); } else { // required temp > existing temp basal reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30); + return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); } } } else { reason = eventualBG + " is in range. No temp required."; if (currenttemp.duration > 0) { // if there is currently any temp basal running - return determinebasal.setTempBasal(0, 0); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp } else { console.error(reason); } } } - if (offline_input == 'Offline') { + if (offline == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !requestedTemp.duration) { reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; - return determinebasal.setTempBasal(profile.current_basal, 30); + return determinebasal.setTempBasal(profile.current_basal, 30, profile, requestedTemp, offline); } } } else { @@ -290,7 +290,7 @@ function init() { return requestedTemp; } - determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, requestedTemp, offline_input) { + determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, requestedTemp, offline) { maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); @@ -299,7 +299,7 @@ function init() { // rather than canceling temps, if Offline mode is set, always set the current basal as a 30m temp // so we can see on the pump that openaps is working - if (duration == 0 && offline_input == 'Offline') { + if (duration == 0 && offline == 'Offline') { rate = profile.current_basal; duration = 30; } From 212656313313255c99421312d079d28abd14d795 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 21:56:49 -0700 Subject: [PATCH 050/131] shorten requestedTemp to just rT --- bin/determine-basal.js | 50 +++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 1128565..4ad8686 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -53,14 +53,14 @@ if (!module.parent) { console.error(JSON.stringify(currenttemp)); console.error(JSON.stringify(iob_data)); console.error(JSON.stringify(profile)); - requestedTemp = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + rT = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); } else { var reason = "BG data is too old, or clock set incorrectly"; console.error(reason); return 1; } - console.log(JSON.stringify(requestedTemp)); + console.log(JSON.stringify(rT)); //requestedTemp } function init() { @@ -95,7 +95,7 @@ function init() { } - determinebasal.determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile) { + determinebasal.determine_basal = function determine_basal(glucose_status, currenttemp, iob_data, profile, offline) { if (typeof profile === 'undefined' || typeof profile.current_basal === 'undefined') { console.error('Error: could not get current basal rate'); process.exit(1); @@ -139,7 +139,7 @@ function init() { var snoozeBG = naive_snoozeBG + deviation; console.error("BG: " + bg + tick + " -> " + eventualBG + "-" + snoozeBG + " (Unadjusted: " + naive_eventualBG + "-" + naive_snoozeBG + ")"); if (typeof eventualBG === 'undefined') { console.error('Error: could not calculate eventualBG'); } - var requestedTemp = { + var rT = { //short for requestedTemp 'temp': 'absolute' , 'bg': bg , 'tick': tick @@ -157,16 +157,16 @@ function init() { console.error(reason); if (glucose_status.delta > 0) { // if BG is rising if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel high temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel low temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp } else { reason = bg + "<" + threshold + "; no high-temp to cancel"; console.error(reason); } } else { // BG is not yet rising - return determinebasal.setTempBasal(0, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(0, 30, profile, rT, offline); } } else { @@ -180,7 +180,7 @@ function init() { console.error(reason); } else { reason = tick + " and eventualBG " + eventualBG; - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } } else { reason = tick + "; no temp to cancel"; @@ -193,10 +193,10 @@ function init() { // if BG is falling and high-temped, or rising and low-temped, cancel if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { reason = tick + " and temp " + currenttemp.rate + " > basal " + profile.current_basal; - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else if (glucose_status.delta > 0 && currenttemp.rate < profile.current_basal) { reason = tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else { reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(reason); @@ -216,7 +216,7 @@ function init() { console.error(reason); } else { reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; - return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } } @@ -248,25 +248,25 @@ function init() { var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; - return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set reason += "no temp, setting " + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; console.error(reason); } else { // required temp > existing temp basal reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } } } else { reason = eventualBG + " is in range. No temp required."; if (currenttemp.duration > 0) { // if there is currently any temp basal running - return determinebasal.setTempBasal(0, 0, profile, requestedTemp, offline); // cancel temp + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else { console.error(reason); } @@ -275,9 +275,9 @@ function init() { if (offline == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working - if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !requestedTemp.duration) { + if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) { reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; - return determinebasal.setTempBasal(profile.current_basal, 30, profile, requestedTemp, offline); + return determinebasal.setTempBasal(profile.current_basal, 30, profile, rT, offline); } } } else { @@ -286,11 +286,11 @@ function init() { } - requestedTemp.reason = reason; - return requestedTemp; + rT.reason = reason; + return rT; } - determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, requestedTemp, offline) { + determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, rT, offline) { maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); @@ -304,11 +304,11 @@ function init() { duration = 30; } - requestedTemp.duration = duration; - requestedTemp.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; - requestedTemp.reason = reason; - console.log(JSON.stringify(requestedTemp)); - return requestedTemp; + rT.duration = duration; + rT.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; + rT.reason = reason; + console.log(JSON.stringify(rT)); + return rT; }; return determinebasal; From a4e9f15fd037a725be172ac459405f68bf398aef Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 21:59:24 -0700 Subject: [PATCH 051/131] set rT.reason directly instead of treating reason as a global variable --- bin/determine-basal.js | 60 ++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 4ad8686..6678c83 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -150,19 +150,18 @@ function init() { if (bg > 10) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose var threshold = profile.min_bg - 30; - var reason=""; if (bg < threshold) { // low glucose suspend mode: BG is < ~80 - reason = "BG " + bg + "<" + threshold; - console.error(reason); + rT.reason = "BG " + bg + "<" + threshold; + console.error(rT.reason); if (glucose_status.delta > 0) { // if BG is rising if (currenttemp.rate > profile.current_basal) { // if a high-temp is running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp } else { - reason = bg + "<" + threshold + "; no high-temp to cancel"; - console.error(reason); + rT.reason = bg + "<" + threshold + "; no high-temp to cancel"; + console.error(rT.reason); } } else { // BG is not yet rising @@ -176,15 +175,15 @@ function init() { if (currenttemp.duration > 0) { // if there is currently any temp basal running // if it's a low-temp and eventualBG < profile.max_bg, let it run a bit longer if (currenttemp.rate <= profile.current_basal && eventualBG < profile.max_bg) { - reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; - console.error(reason); + rT.reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; + console.error(rT.reason); } else { - reason = tick + " and eventualBG " + eventualBG; + rT.reason = tick + " and eventualBG " + eventualBG; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } } else { - reason = tick + "; no temp to cancel"; - console.error(reason); + rT.reason = tick + "; no temp to cancel"; + console.error(rT.reason); } } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: @@ -192,14 +191,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 if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { - reason = tick + " and temp " + currenttemp.rate + " > basal " + 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) { - reason = tick + " and temp " + currenttemp.rate + " < basal " + 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 { - reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; - console.error(reason); + rT.reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; + console.error(rT.reason); } } else { // calculate 30m low-temp required to get projected BG up to target @@ -212,10 +211,10 @@ 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)) { - reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; - console.error(reason); + rT.reason = "temp " + currenttemp.rate + " <~ req " + rate + "U/hr"; + console.error(rT.reason); } else { - reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; + rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } } @@ -224,7 +223,7 @@ function init() { // if iob is over max, just cancel any temps var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; if (basal_iob > max_iob) { - reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; + rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; return determinebasal.setTempBasal(0, 0); } else { // calculate 30m high-temp required to get projected BG down to target @@ -232,7 +231,7 @@ function init() { var insulinReq = (eventualBG - target_bg) / profile.sens; // if that would put us over max_iob, then reduce accordingly if (insulinReq > max_iob-basal_iob) { - reason = "max_iob " + max_iob + ", "; + rT.reason = "max_iob " + max_iob + ", "; insulinReq = max_iob-basal_iob; } @@ -247,28 +246,28 @@ function init() { } var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; + rT.reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set - reason += "no temp, setting " + rate + "U/hr"; + rT.reason += "no temp, setting " + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal - reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; - console.error(reason); + rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; + console.error(rT.reason); } else { // required temp > existing temp basal - reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; + rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } } } else { - reason = eventualBG + " is in range. No temp required."; + rT.reason = eventualBG + " is in range. No temp required."; if (currenttemp.duration > 0) { // if there is currently any temp basal running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else { - console.error(reason); + console.error(rT.reason); } } } @@ -276,17 +275,15 @@ function init() { if (offline == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) { - reason = reason + "; setting current basal of " + profile.current_basal + " as temp"; + rT.reason = rT.reason + "; setting current basal of " + profile.current_basal + " as temp"; return determinebasal.setTempBasal(profile.current_basal, 30, profile, rT, offline); } } } else { - reason = "CGM is calibrating or in ??? state"; - console.error(reason); + rT.reason = "CGM is calibrating or in ??? state"; + console.error(rT.reason); } - - rT.reason = reason; return rT; } @@ -306,7 +303,6 @@ function init() { rT.duration = duration; rT.rate = Math.round((Math.round(rate / 0.05) * 0.05)*100)/100; - rT.reason = reason; console.log(JSON.stringify(rT)); return rT; }; From 2131bf1ff7b2ccd876652531477b2f36a8040d07 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 22:22:50 -0700 Subject: [PATCH 052/131] start with empty rT.reason so += doesn't prepend 'undefined' --- bin/determine-basal.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 6678c83..b8c2de8 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -222,6 +222,7 @@ function init() { } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: // if iob is over max, just cancel any temps var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; + rT.reason = ""; if (basal_iob > max_iob) { rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; return determinebasal.setTempBasal(0, 0); @@ -242,7 +243,6 @@ function init() { maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); if (rate > maxSafeBasal) { rate = maxSafeBasal; - //console.error(maxSafeBasal); } var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate @@ -263,7 +263,7 @@ function init() { } } else { - rT.reason = eventualBG + " is in range. No temp required."; + rT.reason = eventualBG + " is in range. No temp required"; if (currenttemp.duration > 0) { // if there is currently any temp basal running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else { From afc40510388ab4c36700e95b2d547cf9c3c38f02 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 22:23:22 -0700 Subject: [PATCH 053/131] test cases for low glucose suspend mode --- tests/determine-basal.test.js | 181 +++++++++++++++++++++------------- 1 file changed, 111 insertions(+), 70 deletions(-) diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index 332af40..e118cb3 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -3,78 +3,119 @@ require('should'); describe('setTempBasal', function ( ) { - var determinebasal = require('../bin/determine-basal')(); + var determinebasal = require('../bin/determine-basal')(); //function setTempBasal(rate, duration, profile, requestedTemp) - it('should cancel temp', function () { - var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(0, 0, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(0); - cancel.duration.should.equal(0); - }); - - it('should set zero temp', function () { - var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(0, 30, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(0); - cancel.duration.should.equal(30); - }); - - it('should set high temp', function () { - var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(2, 30, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(2); - cancel.duration.should.equal(30); - }); - - it('should limit high temp to max_basal', function () { - var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":3.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(4, 30, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(3); - cancel.duration.should.equal(30); - }); - - it('should limit high temp to 3 * max_daily_basal', function () { - var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":10.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(6, 30, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(3.9); - cancel.duration.should.equal(30); - }); - - it('should limit high temp to 4 * current_basal', function () { - var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(6, 30, profile, requestedTemp); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(2.8); - cancel.duration.should.equal(30); - }); - - it('should set current_basal as temp on cancel if offline', function () { - var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 }; - var requestedTemp = {}; - //console.error(JSON.stringify(profile)); - var cancel = determinebasal.setTempBasal(0, 0, profile, requestedTemp, "Offline"); - //console.error(JSON.stringify(cancel)); - cancel.rate.should.equal(0.7); - cancel.duration.should.equal(30); - }); + var profile = { "current_basal":0.8,"max_daily_basal":1.3,"max_basal":3.0 }; + var rt = {}; + it('should cancel temp', function () { + var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt); + requestedTemp.rate.should.equal(0); + requestedTemp.duration.should.equal(0); + }); + + it('should set zero temp', function () { + var requestedTemp = determinebasal.setTempBasal(0, 30, profile, rt); + requestedTemp.rate.should.equal(0); + requestedTemp.duration.should.equal(30); + }); + + it('should set high temp', function () { + var requestedTemp = determinebasal.setTempBasal(2, 30, profile, rt); + requestedTemp.rate.should.equal(2); + requestedTemp.duration.should.equal(30); + }); + + it('should limit high temp to max_basal', function () { + var requestedTemp = determinebasal.setTempBasal(4, 30, profile, rt); + requestedTemp.rate.should.equal(3); + requestedTemp.duration.should.equal(30); + }); + + it('should set current_basal as temp on requestedTemp if offline', function () { + var requestedTemp = determinebasal.setTempBasal(0, 0, profile, rt, "Offline"); + requestedTemp.rate.should.equal(0.8); + requestedTemp.duration.should.equal(30); + }); + + it('should limit high temp to 3 * max_daily_basal', function () { + var profile = { "current_basal":1.0,"max_daily_basal":1.3,"max_basal":10.0 }; + var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt); + requestedTemp.rate.should.equal(3.9); + requestedTemp.duration.should.equal(30); + }); + + it('should limit high temp to 4 * current_basal', function () { + var profile = { "current_basal":0.7,"max_daily_basal":1.3,"max_basal":10.0 }; + var requestedTemp = determinebasal.setTempBasal(6, 30, profile, rt); + requestedTemp.rate.should.equal(2.8); + requestedTemp.duration.should.equal(30); + }); + +}); + +describe('determine-basal', function ( ) { + var determinebasal = require('../bin/determine-basal')(); + + //function determine_basal(glucose_status, currenttemp, iob_data, profile) + + var glucose_status = {"delta":0,"glucose":115,"avgdelta":0}; + var currenttemp = {"duration":0,"rate":0,"temp":"absolute"}; + var iob_data = {"iob":0,"activity":0,"bolusiob":0}; + var profile = {"max_iob":1.5,"dia":3,"type":"current","current_basal":0.9,"max_daily_basal":1.3,"max_basal":3.5,"max_bg":120,"min_bg":110,"sens":40}; + + it('should do nothing when in range w/o IOB', function () { + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + console.error(JSON.stringify(output)); + (typeof output.rate).should.equal('undefined'); + (typeof output.duration).should.equal('undefined'); + }); + + it('should set current temp when in range w/o IOB with Offline set', function () { + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile, 'Offline'); + output.rate.should.equal(0.9); + output.duration.should.equal(30); + }); + + // low glucose suspend test cases + it('should temp to 0 when low w/o IOB', function () { + var glucose_status = {"delta":-5,"glucose":75,"avgdelta":-5}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.equal(0); + output.duration.should.equal(30); + }); + + it('should do nothing when low and rising w/o IOB', function () { + var glucose_status = {"delta":5,"glucose":75,"avgdelta":5}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + (typeof output.rate).should.equal('undefined'); + (typeof output.duration).should.equal('undefined'); + }); + + it('should do nothing when low and rising w/ negative IOB', function () { + var glucose_status = {"delta":5,"glucose":75,"avgdelta":5}; + var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + (typeof output.rate).should.equal('undefined'); + (typeof output.duration).should.equal('undefined'); + }); + + it('should cancel high-temp when low and rising', function () { + var currenttemp = {"duration":20,"rate":2,"temp":"absolute"}; + var glucose_status = {"delta":5,"glucose":75,"avgdelta":5}; + var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.equal(0); + output.duration.should.equal(0); + }); + + it('should high-temp when > 80-ish and rising w/ lots of negative IOB', function () { + var glucose_status = {"delta":5,"glucose":85,"avgdelta":5}; + var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.above(1); + output.duration.should.equal(30); + }); }); From 700376d855ad14febeb4e1c202407ace33f05a04 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 22:46:33 -0700 Subject: [PATCH 054/131] add output.reason.should.match to test cases --- tests/determine-basal.test.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index e118cb3..bc53206 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -70,12 +70,14 @@ describe('determine-basal', function ( ) { console.error(JSON.stringify(output)); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); + output.reason.should.match(/in range/); }); it('should set current temp when in range w/o IOB with Offline set', function () { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile, 'Offline'); output.rate.should.equal(0.9); output.duration.should.equal(30); + output.reason.should.match(/in range.*setting current basal/); }); // low glucose suspend test cases @@ -84,6 +86,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(30); + output.reason.should.match(/BG 75<80/); }); it('should do nothing when low and rising w/o IOB', function () { @@ -91,6 +94,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); + output.reason.should.match(/75<80; no high-temp/); }); it('should do nothing when low and rising w/ negative IOB', function () { @@ -99,6 +103,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); + output.reason.should.match(/75<80; no high-temp/); }); it('should cancel high-temp when low and rising', function () { @@ -108,6 +113,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(/BG 75<80/); }); it('should high-temp when > 80-ish and rising w/ lots of negative IOB', function () { @@ -116,6 +122,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); output.rate.should.be.above(1); output.duration.should.equal(30); + output.reason.should.match(/no temp, setting/); }); }); From 71578adf128ab9a7993dceb42f406af269d18267 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 22:57:16 -0700 Subject: [PATCH 055/131] Makefile to allow you to run tests by typing 'make' --- Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fc6528e --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +TESTS=tests/*.js + +all: test + +test: + mocha ${TESTS} From b7fbcc67fb160c7b8b17ef303ac96cd09905140b Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 23:10:07 -0700 Subject: [PATCH 056/131] update a comment --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index b8c2de8..9a7da11 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -164,7 +164,7 @@ function init() { console.error(rT.reason); } } - else { // BG is not yet rising + else { // BG is still falling / not yet rising return determinebasal.setTempBasal(0, 30, profile, rT, offline); } From 70de133b9ada9ef8208e94c1814940c17ad6b0ca Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 13 Sep 2015 23:55:52 -0700 Subject: [PATCH 057/131] make curl quiet again: that was just for debugging --- bin/ns-upload.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index 95b9a9e..b8f6e6d 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -16,4 +16,4 @@ cat $HISTORY | \ # requires API_SECRET and site to be set in calling environment (i.e. in crontab) -curl -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." +curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." From d545be5e45aa6b131b39391bc0b3b8aa396346a8 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 00:19:18 -0700 Subject: [PATCH 058/131] remove now-duplcate console.log(JSON.stringify(rT)) --- bin/determine-basal.js | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 353bfaf..278f264 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -60,7 +60,6 @@ if (!module.parent) { console.error(reason); return 1; } - console.log(JSON.stringify(rT)); //requestedTemp } function init() { From e0291a83fedf3337a2c0e45aca04b1a1d494ab6f Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 15:09:43 -0700 Subject: [PATCH 059/131] calculate IOB as of 'now' instead of as of clock.json time --- bin/pebble.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bin/pebble.sh b/bin/pebble.sh index f2c7e89..75a2c47 100755 --- a/bin/pebble.sh +++ b/bin/pebble.sh @@ -17,12 +17,14 @@ # THE SOFTWARE. cd ~/openaps-dev -stat -c %y clock.json | cut -c 1-19 -cat clock.json | sed 's/"//g' | sed 's/T/ /' -echo +#stat -c %y clock.json | cut -c 1-19 +#cat clock.json | sed 's/"//g' | sed 's/T/ /' +#echo share2-bridge file glucose.json.new | grep glucose diff -q glucose.json glucose.json.new && grep -q glucose glucose.json.new && rsync -tu glucose.json.new glucose.json -node ~/openaps-js/bin/iob.js pumphistory.json profile.json clock.json > iob.json.new && grep iob iob.json.new && rsync -tu iob.json.new iob.json +#TODO: consider replacing this now.json hack with an option in iob.js to use current time instead of pump time +(echo -n '"'; date -Iseconds | sed "s/[+-][0-9][0-9]00/\"/") > now.json +node ~/openaps-js/bin/iob.js pumphistory.json profile.json now.json > iob.json.new && grep iob iob.json.new && rsync -tu iob.json.new iob.json node ~/openaps-js/bin/determine-basal.js iob.json currenttemp.json glucose.json profile.json > requestedtemp.json.new && grep reason requestedtemp.json.new && rsync -tu requestedtemp.json.new requestedtemp.json node ~/openaps-js/bin/pebble.js glucose.json iob.json current_basal_profile.json currenttemp.json requestedtemp.json enactedtemp.json > /tmp/pebble-openaps.json #cat /tmp/pebble-openaps.json From 4a65badad36be2fe9bd9c5154fcfe640a91169dd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 15:33:20 -0700 Subject: [PATCH 060/131] console.log rT even when not doing setTemp --- bin/determine-basal.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 278f264..9e9a709 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -255,6 +255,8 @@ function init() { else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; } else { // required temp > existing temp basal rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); @@ -281,6 +283,7 @@ function init() { } else { rT.reason = "CGM is calibrating or in ??? state"; console.error(rT.reason); + console.log(JSON.stringify(rT)); } return rT; From 2f91e73838b1e613cf64045695a233efa8f59dad Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 17:31:38 -0700 Subject: [PATCH 061/131] #28: Compare delta against BGI instead of against 0: first pass, and tests of modified code --- bin/determine-basal.js | 49 +++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 9e9a709..85afedc 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -153,7 +153,7 @@ function init() { if (bg < threshold) { // low glucose suspend mode: BG is < ~80 rT.reason = "BG " + bg + "<" + threshold; console.error(rT.reason); - if (glucose_status.delta > 0) { // if BG is rising + if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { // if BG is rising faster than BGI if (currenttemp.rate > profile.current_basal) { // if a high-temp is running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB @@ -163,40 +163,49 @@ function init() { console.error(rT.reason); } } - else { // BG is still falling / not yet rising + else { // BG is still falling / rising slower than predicted return determinebasal.setTempBasal(0, 30, profile, rT, offline); } } else { - // if BG is rising but eventual BG is below min, or BG is falling but eventual BG is above min - if ((glucose_status.delta > 0 && eventualBG < profile.min_bg) || (glucose_status.delta < 0 && eventualBG >= profile.min_bg)) { + // if eventual BG is below min but BG is rising faster than BGI + if (eventualBG < profile.min_bg && (glucose_status.delta > bgi || glucose_status.avgdelta > bgi)) { + rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg + " but Delta " + tick + " > BGI " + bgi; if (currenttemp.duration > 0) { // if there is currently any temp basal running - // if it's a low-temp and eventualBG < profile.max_bg, let it run a bit longer - if (currenttemp.rate <= profile.current_basal && eventualBG < profile.max_bg) { - rT.reason = "BG" + tick + " but eventualBG " + eventualBG + "<" + profile.max_bg; - console.error(rT.reason); - } else { - rT.reason = tick + " and eventualBG " + eventualBG; - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp - } + rT.reason = rT.reason += "; cancel"; + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } else { - rT.reason = tick + "; no temp to cancel"; + rT.reason = rT.reason += "; no temp to cancel"; console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + // if eventual BG is above min but BG is falling faster than BGI + } else if (eventualBG >= profile.min_bg && (glucose_status.delta < bgi || glucose_status.avgdelta < bgi)) { + rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi; + 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 + } else { + rT.reason = rT.reason += "; no temp to cancel"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; } - } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: + rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg + ", "; // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) 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 if (glucose_status.delta < 0 && currenttemp.rate > profile.current_basal) { - rT.reason = tick + " and temp " + currenttemp.rate + " > basal " + 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) { - rT.reason = tick + " and temp " + currenttemp.rate + " < basal " + 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 { - rT.reason = "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; + rT.reason += "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; console.error(rT.reason); } } else { @@ -210,10 +219,10 @@ 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); } else { - rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; + rT.reason += "no temp, setting " + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } } @@ -221,7 +230,7 @@ function init() { } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: // if iob is over max, just cancel any temps var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; - rT.reason = ""; + rT.reason = "Eventual BG " + eventualBG + ">" + profile.max_bg + ", "; if (basal_iob > max_iob) { rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; return determinebasal.setTempBasal(0, 0); From 4756cf4f447e3d7e6d676cc596b0c146db5fe9df Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 21:52:10 -0700 Subject: [PATCH 062/131] switch from else clauses to returning early --- bin/determine-basal.js | 280 ++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 144 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 85afedc..4278cf8 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -47,19 +47,17 @@ if (!module.parent) { } else { console.error("Could not determine last BG time"); } var minAgo = (systemTime - bgTime) / 60 / 1000 - if (minAgo < 10 && minAgo > -5) { // Dexcom data is recent, but not far in the future - - console.error(JSON.stringify(glucose_status)); - console.error(JSON.stringify(currenttemp)); - console.error(JSON.stringify(iob_data)); - console.error(JSON.stringify(profile)); - rT = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); - - } else { + if (minAgo > 10 && minAgo < -5) { // Dexcom data is too old, or way in the future var reason = "BG data is too old, or clock set incorrectly"; console.error(reason); return 1; } + console.error(JSON.stringify(glucose_status)); + console.error(JSON.stringify(currenttemp)); + console.error(JSON.stringify(iob_data)); + console.error(JSON.stringify(profile)); + rT = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + } function init() { @@ -147,141 +145,94 @@ function init() { }; - if (bg > 30) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose - var threshold = profile.min_bg - 30; - - if (bg < threshold) { // low glucose suspend mode: BG is < ~80 - rT.reason = "BG " + bg + "<" + threshold; - console.error(rT.reason); - if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { // if BG is rising faster than BGI - if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp - } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp - } else { - rT.reason = bg + "<" + threshold + "; no high-temp to cancel"; - console.error(rT.reason); - } + if (bg < 30) { //Dexcom is in ??? mode or calibrating, do nothing. Asked @benwest for raw data in iter_glucose + rT.reason = "CGM is calibrating or in ??? state"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + var threshold = profile.min_bg - 30; + + if (bg < threshold) { // low glucose suspend mode: BG is < ~80 + rT.reason = "BG " + bg + "<" + threshold; + console.error(rT.reason); + if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { // if BG is rising faster than BGI + if (currenttemp.rate > profile.current_basal) { // if a high-temp is running + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp + } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp } - else { // BG is still falling / rising slower than predicted - return determinebasal.setTempBasal(0, 30, profile, rT, offline); + rT.reason = bg + "<" + threshold + "; no high-temp to cancel"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + // BG is still falling / rising slower than predicted + return determinebasal.setTempBasal(0, 30, profile, rT, offline); + } + if (eventualBG < profile.min_bg) { // if eventual BG is below target: + rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; + // if 5m or 15m avg BG is rising faster than BGI + if (glucose_status.delta > bgi || glucose_status.avgdelta > bgi) { + rT.reason += ", but Delta " + tick + " > BGI " + bgi; + 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 } - - } else { - - // if eventual BG is below min but BG is rising faster than BGI - if (eventualBG < profile.min_bg && (glucose_status.delta > bgi || glucose_status.avgdelta > bgi)) { - rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg + " but Delta " + tick + " > BGI " + bgi; - 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 - } else { - rT.reason = rT.reason += "; no temp to cancel"; - console.error(rT.reason); - console.log(JSON.stringify(rT)); - return rT; - } - // if eventual BG is above min but BG is falling faster than BGI - } else if (eventualBG >= profile.min_bg && (glucose_status.delta < bgi || glucose_status.avgdelta < bgi)) { - rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi; - 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 - } else { - rT.reason = rT.reason += "; no temp to cancel"; - console.error(rT.reason); - console.log(JSON.stringify(rT)); - return rT; - } - } else if (eventualBG < profile.min_bg) { // if eventual BG is below target: - rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg + ", "; - // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) - 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 - if (glucose_status.delta < 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) { - rT.reason += tick + " and temp " + currenttemp.rate + " < basal " + profile.current_basal; - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else { - rT.reason += "bolus snooze: eventual BG range " + eventualBG + "-" + snoozeBG; - console.error(rT.reason); - } - } else { - // calculate 30m low-temp required to get projected BG up to target - // negative insulin required to get up to min: - //var insulinReq = Math.max(0, (target_bg - eventualBG) / profile.sens); - // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses - var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile.sens); - // rate required to deliver insulinReq less insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - 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"; - console.error(rT.reason); - } else { - rT.reason += "no temp, setting " + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30, profile, rT, offline); - } - } - - } else if (eventualBG > profile.max_bg) { // if eventual BG is above target: - // if iob is over max, just cancel any temps - var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; - rT.reason = "Eventual BG " + eventualBG + ">" + profile.max_bg + ", "; - if (basal_iob > max_iob) { - rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; - return determinebasal.setTempBasal(0, 0); - } else { - // calculate 30m high-temp required to get projected BG down to target - // additional insulin required to get down to max bg: - var insulinReq = (eventualBG - target_bg) / profile.sens; - // if that would put us over max_iob, then reduce accordingly - if (insulinReq > max_iob-basal_iob) { - rT.reason = "max_iob " + max_iob + ", "; - insulinReq = max_iob-basal_iob; - } - - // rate required to deliver insulinReq more insulin over 30m: - var rate = profile.current_basal + (2 * insulinReq); - rate = Math.round( rate * 1000 ) / 1000; - - maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); - if (rate > maxSafeBasal) { - rate = maxSafeBasal; - } - var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; - if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate - rT.reason = currenttemp.duration + "@" + currenttemp.rate + " > req " + insulinReq + "U"; - return determinebasal.setTempBasal(rate, 30, profile, rT, offline); - } - else if (typeof currenttemp.rate == 'undefined' || currenttemp.rate == 0) { // no temp is set - rT.reason += "no temp, setting " + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30, profile, rT, offline); - } - else if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal - rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; - console.error(rT.reason); - console.log(JSON.stringify(rT)); - return rT; - } else { // required temp > existing temp basal - rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; - return determinebasal.setTempBasal(rate, 30, profile, rT, offline); - } - } - - } else { - rT.reason = eventualBG + " is in range. No temp required"; - if (currenttemp.duration > 0) { // if there is currently any temp basal running - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp - } else { - console.error(rT.reason); - } + rT.reason = rT.reason += "; no temp to cancel"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) + 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 + if (glucose_status.delta < 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) { + 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; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + // calculate 30m low-temp required to get projected BG up to target + // use snoozeBG instead of eventualBG to more gradually ramp in any counteraction of the user's boluses + var insulinReq = Math.min(0, (snoozeBG - target_bg) / profile.sens); + // rate required to deliver insulinReq less insulin over 30m: + var rate = profile.current_basal + (2 * insulinReq); + 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"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; } - + rT.reason += "no temp, setting " + rate + "U/hr"; + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); + } + // if eventual BG is above min but BG is falling faster than BGI + if (glucose_status.delta < bgi || glucose_status.avgdelta < bgi) { + rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi; + 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 + } + rT.reason = rT.reason += "; no temp to cancel"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } + if (eventualBG < profile.max_bg) { + rT.reason = eventualBG + " is in range. No temp required"; + if (currenttemp.duration > 0) { // if there is currently any temp basal running + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp + } + console.error(rT.reason); if (offline == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) { @@ -289,13 +240,54 @@ function init() { return determinebasal.setTempBasal(profile.current_basal, 30, profile, rT, offline); } } - } else { - rT.reason = "CGM is calibrating or in ??? state"; - console.error(rT.reason); console.log(JSON.stringify(rT)); + return rT; } - return rT; + // eventual BG is above target: + // if iob is over max, just cancel any temps + var basal_iob = Math.round(( iob_data.iob - iob_data.bolusiob )*1000)/1000; + rT.reason = "Eventual BG " + eventualBG + ">" + profile.max_bg + ", "; + if (basal_iob > max_iob) { + rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; + return determinebasal.setTempBasal(0, 0); + } + // otherwise, calculate 30m high-temp required to get projected BG down to target + // insulinReq is the additional insulin required to get down to max bg: + var insulinReq = (eventualBG - target_bg) / profile.sens; + // if that would put us over max_iob, then reduce accordingly + if (insulinReq > max_iob-basal_iob) { + rT.reason = "max_iob " + max_iob + ", "; + insulinReq = max_iob-basal_iob; + } + + // rate required to deliver insulinReq more insulin over 30m: + var rate = profile.current_basal + (2 * insulinReq); + rate = Math.round( rate * 1000 ) / 1000; + + maxSafeBasal = Math.min(profile.max_basal, 3 * profile.max_daily_basal, 4 * profile.current_basal); + if (rate > maxSafeBasal) { + rate = maxSafeBasal; + } + var insulinScheduled = currenttemp.duration * (currenttemp.rate - profile.current_basal) / 60; + if (insulinScheduled > insulinReq + 0.3) { // if current temp would deliver >0.3U more than the required insulin, lower the rate + 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 + rT.reason += "no temp, setting " + rate + "U/hr"; + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); + } + if (currenttemp.duration > 0 && rate < currenttemp.rate + 0.1) { // if required temp <~ existing temp basal + rT.reason += "temp " + currenttemp.rate + " >~ req " + rate + "U/hr"; + console.error(rT.reason); + console.log(JSON.stringify(rT)); + return rT; + } // required temp > existing temp basal + rT.reason += "temp " + currenttemp.rate + "<" + rate + "U/hr"; + return determinebasal.setTempBasal(rate, 30, profile, rT, offline); + + } determinebasal.setTempBasal = function setTempBasal(rate, duration, profile, rT, offline) { From 6631801bbe269afa956b406742d3ce8d309cbb82 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 21:52:29 -0700 Subject: [PATCH 063/131] more tests --- tests/determine-basal.test.js | 80 ++++++++++++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index bc53206..dd03f7c 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -60,6 +60,7 @@ describe('determine-basal', function ( ) { //function determine_basal(glucose_status, currenttemp, iob_data, profile) + // standard initial conditions for all determine-basal test cases unless overridden var glucose_status = {"delta":0,"glucose":115,"avgdelta":0}; var currenttemp = {"duration":0,"rate":0,"temp":"absolute"}; var iob_data = {"iob":0,"activity":0,"bolusiob":0}; @@ -106,7 +107,24 @@ describe('determine-basal', function ( ) { output.reason.should.match(/75<80; no high-temp/); }); - it('should cancel high-temp when low and rising', function () { + it('should temp to 0 on uptick if avgdelta is still negative', function () { + var glucose_status = {"delta":1,"glucose":75,"avgdelta":-2}; + 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 75<80/); + }); + + it('should temp to 0 when rising slower than BGI', function () { + var glucose_status = {"delta":2,"glucose":75,"avgdelta":1}; + var iob_data = {"iob":-1,"activity":-0.01,"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 75<80/); + }); + + it('should cancel high-temp when low and rising faster than BGI', function () { var currenttemp = {"duration":20,"rate":2,"temp":"absolute"}; var glucose_status = {"delta":5,"glucose":75,"avgdelta":5}; var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0}; @@ -125,4 +143,64 @@ describe('determine-basal', function ( ) { output.reason.should.match(/no temp, setting/); }); + // no-IOB no-basal test cases + it('should low-temp when eventualBG < min_bg', function () { + var glucose_status = {"delta":-3,"glucose":110,"avgdelta":-1}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.below(0.8); + output.duration.should.equal(30); + output.reason.should.match(/Eventual BG .*<110/); + }); + + it('should high-temp when eventualBG > max_bg', function () { + var glucose_status = {"delta":+3,"glucose":120,"avgdelta":+1}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.above(1); + output.duration.should.equal(30); + output.reason.should.match(/Eventual BG .*>120/); + }); + + // high BG + + it('should cancel high-temp when high and falling faster than BGI', function () { + var currenttemp = {"duration":20,"rate":2,"temp":"absolute"}; + var glucose_status = {"delta":-5,"glucose":175,"avgdelta":-5}; + var iob_data = {"iob":1,"activity":0.01,"bolusiob":0}; + 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/); + }); + + it('should high-temp when high and falling slower than BGI', function () { + var glucose_status = {"delta":-1,"glucose":175,"avgdelta":-1}; + var iob_data = {"iob":1,"activity":0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.above(1); + output.duration.should.equal(30); + output.reason.should.match(/no temp, setting/); + }); + + // low BG + + it('should cancel low-temp when lowish and rising faster than BGI', function () { + var currenttemp = {"duration":20,"rate":0.5,"temp":"absolute"}; + var glucose_status = {"delta":3,"glucose":85,"avgdelta":3}; + var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; + 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/); + }); + + it('should low-temp when low and rising slower than BGI', function () { + var glucose_status = {"delta":1,"glucose":85,"avgdelta":1}; + var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.below(0.8); + output.duration.should.equal(30); + output.reason.should.match(/no temp, setting/); + }); + + }); From 71591b4480399e1fc8ddffa6803b5c2af9817fb2 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 22:18:38 -0700 Subject: [PATCH 064/131] cosmetic stuff --- bin/determine-basal.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 4278cf8..33ced85 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -155,7 +155,6 @@ function init() { if (bg < threshold) { // low glucose suspend mode: BG is < ~80 rT.reason = "BG " + bg + "<" + threshold; - console.error(rT.reason); if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { // if BG is rising faster than BGI if (currenttemp.rate > profile.current_basal) { // if a high-temp is running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp @@ -168,6 +167,7 @@ function init() { return rT; } // BG is still falling / rising slower than predicted + console.error(rT.reason); return determinebasal.setTempBasal(0, 30, profile, rT, offline); } if (eventualBG < profile.min_bg) { // if eventual BG is below target: @@ -187,6 +187,7 @@ function init() { // if this is just due to boluses, we can snooze until the bolus IOB decays (at double speed) 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) { rT.reason += tick + ", and temp " + currenttemp.rate + " > basal " + profile.current_basal; return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp @@ -212,7 +213,7 @@ function init() { console.log(JSON.stringify(rT)); return rT; } - rT.reason += "no temp, setting " + rate + "U/hr"; + rT.reason += ", no temp, setting " + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } // if eventual BG is above min but BG is falling faster than BGI @@ -232,7 +233,6 @@ function init() { if (currenttemp.duration > 0) { // if there is currently any temp basal running return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel temp } - console.error(rT.reason); if (offline == 'Offline') { // if no temp is running or required, set the current basal as a temp, so you can see on the pump that the loop is working if ((!currenttemp.duration || (currenttemp.rate == profile.current_basal)) && !rT.duration) { @@ -240,6 +240,7 @@ function init() { return determinebasal.setTempBasal(profile.current_basal, 30, profile, rT, offline); } } + console.error(rT.reason); console.log(JSON.stringify(rT)); return rT; } @@ -309,6 +310,7 @@ function init() { console.log(JSON.stringify(rT)); return rT; }; + return determinebasal; } From ff4bbb5267b6247bfdc46ba11ae1ac045653afbb Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 22:19:17 -0700 Subject: [PATCH 065/131] reorganize tests slightly --- tests/determine-basal.test.js | 48 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index dd03f7c..ea60601 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -68,7 +68,6 @@ describe('determine-basal', function ( ) { it('should do nothing when in range w/o IOB', function () { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); - console.error(JSON.stringify(output)); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); output.reason.should.match(/in range/); @@ -143,7 +142,8 @@ describe('determine-basal', function ( ) { output.reason.should.match(/no temp, setting/); }); - // no-IOB no-basal test cases + // low eventualBG + it('should low-temp when eventualBG < min_bg', function () { var glucose_status = {"delta":-3,"glucose":110,"avgdelta":-1}; var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); @@ -152,6 +152,27 @@ describe('determine-basal', function ( ) { output.reason.should.match(/Eventual BG .*<110/); }); + it('should cancel low-temp when lowish and rising faster than BGI', function () { + var currenttemp = {"duration":20,"rate":0.5,"temp":"absolute"}; + var glucose_status = {"delta":3,"glucose":85,"avgdelta":3}; + var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; + 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/); + }); + + it('should low-temp when low and rising slower than BGI', function () { + var glucose_status = {"delta":1,"glucose":85,"avgdelta":1}; + var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; + var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); + output.rate.should.be.below(0.8); + output.duration.should.equal(30); + output.reason.should.match(/no temp, setting/); + }); + + // high eventualBG + it('should high-temp when eventualBG > max_bg', function () { var glucose_status = {"delta":+3,"glucose":120,"avgdelta":+1}; var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); @@ -160,8 +181,6 @@ describe('determine-basal', function ( ) { output.reason.should.match(/Eventual BG .*>120/); }); - // high BG - it('should cancel high-temp when high and falling faster than BGI', function () { var currenttemp = {"duration":20,"rate":2,"temp":"absolute"}; var glucose_status = {"delta":-5,"glucose":175,"avgdelta":-5}; @@ -181,26 +200,5 @@ describe('determine-basal', function ( ) { output.reason.should.match(/no temp, setting/); }); - // low BG - - it('should cancel low-temp when lowish and rising faster than BGI', function () { - var currenttemp = {"duration":20,"rate":0.5,"temp":"absolute"}; - var glucose_status = {"delta":3,"glucose":85,"avgdelta":3}; - var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; - 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/); - }); - - it('should low-temp when low and rising slower than BGI', function () { - var glucose_status = {"delta":1,"glucose":85,"avgdelta":1}; - var iob_data = {"iob":-0.5,"activity":-0.01,"bolusiob":0}; - var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); - output.rate.should.be.below(0.8); - output.duration.should.equal(30); - output.reason.should.match(/no temp, setting/); - }); - }); From 53ed16f98c2ab233e98e1b297fb31e2920591268 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Mon, 14 Sep 2015 23:16:12 -0700 Subject: [PATCH 066/131] round bgi --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 9e9a709..470e338 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -121,7 +121,7 @@ function init() { else { tick = glucose_status.delta; } console.error("IOB: " + iob_data.iob.toFixed(2) + ", Bolus IOB: " + iob_data.bolusiob.toFixed(2)); //calculate BG impact: the amount BG "should" be rising or falling based on insulin activity alone - var bgi = -iob_data.activity * profile.sens * 5; + var bgi = Math.round(( -iob_data.activity * profile.sens * 5 )*100)/100; console.error("Avg. Delta: " + glucose_status.avgdelta.toFixed(1) + ", BGI: " + bgi.toFixed(1)); // project deviation over next 15 minutes var deviation = Math.round( 15 / 5 * ( glucose_status.avgdelta - bgi ) ); From 43b4770355833393106ad05e197a7079242f8a32 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 15 Sep 2015 22:36:49 -0700 Subject: [PATCH 067/131] add fix-dead-carelink check to the loop --- bin/loop.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 88d17da..008abe3 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -114,7 +114,8 @@ bail() { } actionrequired() { - #if diff -u reservoir.json reservoir.json.new; then + # make sure we can still talk to the carelink stick + python -m decocare.stick $(python -m decocare.scan) >/dev/null || sudo ~/openaps-js/bin/fix-dead-carelink.sh | tee -a /var/log/openaps/easy.log # if reservoir insulin remaining changes by more than 0.2U between runs, that probably indicates a bolus if awk '{getline t<"reservoir.json.new"; if (($0-t) > 0.2 || ($0-t < -0.2)) print "Reservoir changed from " $0 " to " t}' reservoir.json | grep changed; then echo "Reservoir status changed" From 239b6d3a9240f925e529a4a0d972ebb1cd023f49 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 15 Sep 2015 23:16:17 -0700 Subject: [PATCH 068/131] only suppress low-temp if BOTH delta and avgdelta are > bgi --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index cb3609e..6be3477 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -173,7 +173,7 @@ function init() { if (eventualBG < profile.min_bg) { // if eventual BG is below target: rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; // if 5m or 15m avg BG is rising faster than BGI - if (glucose_status.delta > bgi || glucose_status.avgdelta > bgi) { + if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { rT.reason += ", but Delta " + tick + " > BGI " + bgi; if (currenttemp.duration > 0) { // if there is currently any temp basal running rT.reason = rT.reason += "; cancel"; From 95599737e7957aff7fc85636b8df506d66e27ac0 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 16 Sep 2015 22:22:52 -0700 Subject: [PATCH 069/131] fix iob.js for non-3h DIAs, and do bolus IOB properly --- bin/iob.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bin/iob.js b/bin/iob.js index 91c51e2..fbb4649 100644 --- a/bin/iob.js +++ b/bin/iob.js @@ -20,7 +20,8 @@ function iobCalc(treatment, time, dia) { var diaratio = dia / 3; - var peak = 75 * diaratio; + var peak = 75 ; + var end = 180 ; //var sens = profile_data.sens; if (typeof time === 'undefined') { var time = new Date(); @@ -28,21 +29,20 @@ function iobCalc(treatment, time, dia) { if (treatment.insulin) { var bolusTime=new Date(treatment.date); - var minAgo=(time-bolusTime)/1000/60; + var minAgo=(time-bolusTime)/1000/60 * diaratio; if (minAgo < 0) { var iobContrib=0; var activityContrib=0; } - if (minAgo < peak) { - var x = (minAgo/5 + 1) * diaratio; + else 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 < 180) { - var x = (minAgo-peak)/5 * diaratio; + 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)); @@ -77,7 +77,7 @@ function iobTotal(treatments, time) { 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/3) + var bIOB = iobCalc(treatment, time, dia*3) //console.log(treatment); //console.log(bIOB); if (bIOB && bIOB.iobContrib) bolusiob += bIOB.iobContrib; From fe84acf35d16992d14c1c2f50fcdcb9e3944fee7 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 18 Sep 2015 10:41:23 -0700 Subject: [PATCH 070/131] should temp to 0 when low and falling, regardless of BGI or bolus snooze --- bin/determine-basal.js | 27 ++++++++++++++++----------- tests/determine-basal.test.js | 21 +++++++++++++++------ 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 6be3477..dd24921 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -155,20 +155,25 @@ function init() { if (bg < threshold) { // low glucose suspend mode: BG is < ~80 rT.reason = "BG " + bg + "<" + threshold; - if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { // if BG is rising faster than BGI - if (currenttemp.rate > profile.current_basal) { // if a high-temp is running - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp - } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB - return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp - } - rT.reason = bg + "<" + threshold + "; no high-temp to cancel"; + 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); - console.log(JSON.stringify(rT)); - return rT; + return determinebasal.setTempBasal(0, 30, profile, rT, offline); + } + if (glucose_status.delta > glucose_status.avgdelta) { + rT.reason += ", delta " + glucose_status.delta + ">0"; + } else { + rT.reason += ", avg delta " + glucose_status.avgdelta + ">0"; + } + if (currenttemp.rate > profile.current_basal) { // if a high-temp is running + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel high temp + } else if (currenttemp.duration && eventualBG > profile.max_bg) { // if low-temped and predicted to go high from negative IOB + return determinebasal.setTempBasal(0, 0, profile, rT, offline); // cancel low temp } - // BG is still falling / rising slower than predicted + rT.reason += "; no high-temp to cancel"; console.error(rT.reason); - return determinebasal.setTempBasal(0, 30, profile, rT, offline); + console.log(JSON.stringify(rT)); + return rT; } if (eventualBG < profile.min_bg) { // if eventual BG is below target: rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index ea60601..e296b34 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -94,7 +94,7 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); - output.reason.should.match(/75<80; no high-temp/); + output.reason.should.match(/75<80.*no high-temp/); }); it('should do nothing when low and rising w/ negative IOB', function () { @@ -103,19 +103,19 @@ describe('determine-basal', function ( ) { var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); (typeof output.rate).should.equal('undefined'); (typeof output.duration).should.equal('undefined'); - output.reason.should.match(/75<80; no high-temp/); + output.reason.should.match(/75<80.*no high-temp/); }); - it('should temp to 0 on uptick if avgdelta is still negative', function () { + it('should do nothing on uptick even if avgdelta is still negative', function () { var glucose_status = {"delta":1,"glucose":75,"avgdelta":-2}; var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); - output.rate.should.equal(0); - output.duration.should.equal(30); + (typeof output.rate).should.equal('undefined'); + (typeof output.duration).should.equal('undefined'); output.reason.should.match(/BG 75<80/); }); it('should temp to 0 when rising slower than BGI', function () { - var glucose_status = {"delta":2,"glucose":75,"avgdelta":1}; + var glucose_status = {"delta":1,"glucose":75,"avgdelta":1}; var iob_data = {"iob":-1,"activity":-0.01,"bolusiob":0}; var output = determinebasal.determine_basal(glucose_status, currenttemp, iob_data, profile); output.rate.should.equal(0); @@ -123,6 +123,15 @@ describe('determine-basal', function ( ) { output.reason.should.match(/BG 75<80/); }); + it('should temp to 0 when low and falling, regardless of BGI', function () { + var glucose_status = {"delta":-1,"glucose":75,"avgdelta":-1}; + 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 75<80/); + }); + it('should cancel high-temp when low and rising faster than BGI', function () { var currenttemp = {"duration":20,"rate":2,"temp":"absolute"}; var glucose_status = {"delta":5,"glucose":75,"avgdelta":5}; From ba130481b8dffbb565e0ab566d5763af6890b319 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 18 Sep 2015 19:05:03 -0700 Subject: [PATCH 071/131] make it clearer what we're doing to calculate avg, and make it easier to actually use timestamps to determine minutes instead of assuming 1 data point every 5m --- bin/determine-basal.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index dd24921..5bc7d5c 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -72,15 +72,22 @@ function init() { var now = data[0]; var last = data[1]; + var minutes; + var change; var avg; //TODO: calculate average using system_time instead of assuming 1 data point every 5m if (typeof data[3] !== 'undefined' && data[3].glucose > 30) { - avg = ( now.glucose - data[3].glucose) / 3; + minutes = 3*5; + change = now.glucose - data[3].glucose; } else if (typeof data[2] !== 'undefined' && data[2].glucose > 30) { - avg = ( now.glucose - data[2].glucose) / 2; + minutes = 2*5; + change = now.glucose - data[2].glucose; } else if (typeof data[1] !== 'undefined' && data[1].glucose > 30) { - avg = now.glucose - data[1].glucose; - } else { avg = 0; } + minutes = 1*5; + change = now.glucose - data[1].glucose; + } else { change = 0; } + // multiply by 5 to get the same units as delta, i.e. mg/dL/5m + avg = change/min * 5; var o = { delta: now.glucose - last.glucose , glucose: now.glucose From d90a11fa9ba4d4d08fb05cb2bbd3fa81bf434f30 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sat, 19 Sep 2015 22:55:27 -0700 Subject: [PATCH 072/131] update pebble while tight-looping --- bin/loop.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/loop.sh b/bin/loop.sh index 008abe3..1cd9c6c 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -248,6 +248,7 @@ while(true); do openaps report invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps report invoke clock.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log findclocknew && grep T clock.json.new && rsync -tu clock.json.new clock.json || echo -n "!" >> /var/log/openaps/easy.log + pebble echo -n "-" >> /var/log/openaps/easy.log sleep 30 done From 6dbe93abfe39f72374757c8313aab35e9a65b5cd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sat, 19 Sep 2015 23:00:08 -0700 Subject: [PATCH 073/131] comparing to BGI is a bit too extreme: backing it off to BGI/2 (half the distance between 0 and BGI), while also increasing bolus snooze from 1/3 to 1/2 of DIA --- bin/determine-basal.js | 12 ++++++------ bin/iob.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 5bc7d5c..be138f6 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -184,9 +184,9 @@ function init() { } if (eventualBG < profile.min_bg) { // if eventual BG is below target: rT.reason = "Eventual BG " + eventualBG + "<" + profile.min_bg; - // if 5m or 15m avg BG is rising faster than BGI - if (glucose_status.delta > bgi && glucose_status.avgdelta > bgi) { - rT.reason += ", but Delta " + tick + " > BGI " + bgi; + // 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 (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 @@ -228,9 +228,9 @@ function init() { rT.reason += ", no temp, setting " + rate + "U/hr"; return determinebasal.setTempBasal(rate, 30, profile, rT, offline); } - // if eventual BG is above min but BG is falling faster than BGI - if (glucose_status.delta < bgi || glucose_status.avgdelta < bgi) { - rT.reason = "Eventual BG " + eventualBG + ">" + profile.min_bg + " but Delta " + tick + " < BGI " + bgi; + // 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 (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 diff --git a/bin/iob.js b/bin/iob.js index fbb4649..0be8601 100644 --- a/bin/iob.js +++ b/bin/iob.js @@ -77,7 +77,7 @@ function iobTotal(treatments, time) { 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*3) + var bIOB = iobCalc(treatment, time, dia*2) //console.log(treatment); //console.log(bIOB); if (bIOB && bIOB.iobContrib) bolusiob += bIOB.iobContrib; From 1367af72bedbf1e75a0d210c59e327c6ed5b7315 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 00:02:32 -0700 Subject: [PATCH 074/131] fix variable name --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index be138f6..4a38130 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -87,7 +87,7 @@ function init() { change = now.glucose - data[1].glucose; } else { change = 0; } // multiply by 5 to get the same units as delta, i.e. mg/dL/5m - avg = change/min * 5; + avg = change/minutes * 5; var o = { delta: now.glucose - last.glucose , glucose: now.glucose From ee99fd2493870872cbf20a4f0f0467cb5264e458 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 00:14:33 -0700 Subject: [PATCH 075/131] rm all requestedtemp* to make sure we're not using an old suggestion --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index 1cd9c6c..35a1027 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -162,7 +162,7 @@ execute() { tail currenttemp.json # make sure we're not using an old suggestion - rm requestedtemp.json* 2>/dev/null + rm requestedtemp* 2>/dev/null echo "Removing requestedtemp.json and recreating it" # if we can't run suggest, it might be because our pumpsettings are missing or screwed up" suggest || ( getpumpsettings && suggest ) || ( bail "Can't calculate IOB or basal"; return $? ) From f1b5df35eca817366d90fe373dcd5dc04a6e1149 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 00:22:35 -0700 Subject: [PATCH 076/131] add another rm requestedtemp* just in case an old process is in an endless loop --- bin/loop.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bin/loop.sh b/bin/loop.sh index 35a1027..d39fc37 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -21,6 +21,9 @@ die() { exit 1 } +# remove all requestedtemp* files on startup, just in case an old process is in an endless loop +rm requestedtemp* 2>/dev/null + # remove any old stale lockfiles find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null From dc33b4288335f6c3cff5b5c63926ccdbfff5a898 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 01:01:39 -0700 Subject: [PATCH 077/131] delete any json files older than 10m to make triply sure we avoid using stale data --- bin/loop.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/bin/loop.sh b/bin/loop.sh index d39fc37..955d81f 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -21,8 +21,14 @@ die() { exit 1 } +# TODO: allow openaps instances in directories other than ~/openaps-dev +# for now, make sure we're running in ~/openaps-dev/, or die. +cd ~/openaps-dev/ || die "can't cd ~/openaps-dev/" + # remove all requestedtemp* files on startup, just in case an old process is in an endless loop rm requestedtemp* 2>/dev/null +# delete any json files older than 10m to make triply sure we avoid using stale data +find *.json -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null # remove any old stale lockfiles find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null From af6556af359869fdc84ecffe367270ab91fc27f4 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 01:10:29 -0700 Subject: [PATCH 078/131] add .json to pumphistory in the usage --- bin/iob.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/iob.js b/bin/iob.js index 0be8601..7e92bc3 100644 --- a/bin/iob.js +++ b/bin/iob.js @@ -171,7 +171,7 @@ if (!module.parent) { 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), ' '); + console.log('usage: ', process.argv.slice(0, 2), ' '); process.exit(1); } var cwd = process.cwd() From f7120fe3c2bff85430c7851edc12d3c90e5eaab3 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 16:36:53 -0700 Subject: [PATCH 079/131] removing everything removes max_iob.json and infrequently-changed settings. just remove anything ephemeral. --- bin/loop.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 955d81f..cdc89f9 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -27,8 +27,12 @@ cd ~/openaps-dev/ || die "can't cd ~/openaps-dev/" # remove all requestedtemp* files on startup, just in case an old process is in an endless loop rm requestedtemp* 2>/dev/null -# delete any json files older than 10m to make triply sure we avoid using stale data -find *.json -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null +# delete any recent-history json files older than 30m to make triply sure we avoid using stale data +find pumphistory*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find clock*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find *temp*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find glucose*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find iob*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null # remove any old stale lockfiles find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null From 8b495c8880961eaf841662c003180b221b6d7585 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 17:05:01 -0700 Subject: [PATCH 080/131] forgot to add profile, rT, offline to one instance of setTempBasal() --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index 4a38130..fbcce80 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -263,7 +263,7 @@ function init() { rT.reason = "Eventual BG " + eventualBG + ">" + profile.max_bg + ", "; if (basal_iob > max_iob) { rT.reason = "basal_iob " + basal_iob + " > max_iob " + max_iob; - return determinebasal.setTempBasal(0, 0); + return determinebasal.setTempBasal(0, 0, profile, rT, offline); } // otherwise, calculate 30m high-temp required to get projected BG down to target // insulinReq is the additional insulin required to get down to max bg: From fe07b7cb9e0b0f670452aefedb9d8fe139a6d8ec Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 17:31:57 -0700 Subject: [PATCH 081/131] remove windows byte-order mark and add #!/usr/bin/env node --- bin/sendtempbasal-Azure.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/sendtempbasal-Azure.js b/bin/sendtempbasal-Azure.js index 5f23730..28cef43 100644 --- a/bin/sendtempbasal-Azure.js +++ b/bin/sendtempbasal-Azure.js @@ -1,4 +1,6 @@ -/* +#!/usr/bin/env node + +/* Send Temporary Basal to Azure Copyright (c) 2015 OpenAPS Contributors From e19ea6745066cff515ee1f3f14f7d8ed0745a38f Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 17:43:13 -0700 Subject: [PATCH 082/131] use cwd + '/' instead of './' --- bin/sendtempbasal-Azure.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/sendtempbasal-Azure.js b/bin/sendtempbasal-Azure.js index 28cef43..14bcdfd 100644 --- a/bin/sendtempbasal-Azure.js +++ b/bin/sendtempbasal-Azure.js @@ -29,9 +29,10 @@ if (!module.parent) { } } -var glucose_data = require('./' + glucose_input); -var enacted_temps = require('./' + enacted_temps_input); -var iob_data = require('./' + iob_input); +var cwd = process.cwd(); +var glucose_data = require(cwd + '/' + glucose_input); +var enacted_temps = require(cwd + '/' + enacted_temps_input); +var iob_data = require(cwd + '/' + iob_input); From 796e0628d027ad0b7a40a4e275642738a9189c40 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 17:54:54 -0700 Subject: [PATCH 083/131] take webapi host as an argument instead of hardcoding --- bin/sendtempbasal-Azure.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bin/sendtempbasal-Azure.js b/bin/sendtempbasal-Azure.js index 14bcdfd..32b6038 100644 --- a/bin/sendtempbasal-Azure.js +++ b/bin/sendtempbasal-Azure.js @@ -23,8 +23,9 @@ if (!module.parent) { var iob_input = process.argv.slice(2, 3).pop() var enacted_temps_input = process.argv.slice(3, 4).pop() var glucose_input = process.argv.slice(4, 5).pop() - if (!iob_input || !enacted_temps_input || !glucose_input) { - console.log('usage: ', process.argv.slice(0, 2), ' '); + var webapi = process.argv.slice(5, 6).pop() + if (!iob_input || !enacted_temps_input || !glucose_input || !webapi) { + console.log('usage: ', process.argv.slice(0, 2), ' <[your_webapi].azurewebsites.net>'); process.exit(1); } } @@ -49,7 +50,7 @@ var data = JSON.stringify({ ); var options = { - host: '[your_webapi].azurewebsites.net', + host: webapi, port: '443', path: '/api/openapstempbasals', method: 'POST', From e313fee9f96cc47f074f0c6e26cb0aa3a5e21dad Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 18:37:20 -0700 Subject: [PATCH 084/131] change site environment variable to NIGHTSCOUT_HOST --- bin/ns-upload.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/ns-upload.sh b/bin/ns-upload.sh index b8f6e6d..7805de3 100755 --- a/bin/ns-upload.sh +++ b/bin/ns-upload.sh @@ -15,5 +15,5 @@ cat $HISTORY | \ > $OUTPUT -# requires API_SECRET and site to be set in calling environment (i.e. in crontab) -curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $site/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $site." ) || echo "Unable to upload to $site." +# requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) +curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $NIGHTSCOUT_HOST/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $NIGHTSCOUT_HOST" ) || echo "Unable to upload to $NIGHTSCOUT_HOST" From de99c2945ccbb55c2921ce277b4e375438b7d2ac Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 18:38:12 -0700 Subject: [PATCH 085/131] functionalize enact and getcurrenttemp, add send-tempbasal-Azure if AZURE_SQL_API_HOST exists, and fine-tune failsafes --- bin/loop.sh | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index cdc89f9..757e57a 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -25,12 +25,11 @@ die() { # for now, make sure we're running in ~/openaps-dev/, or die. cd ~/openaps-dev/ || die "can't cd ~/openaps-dev/" -# remove all requestedtemp* files on startup, just in case an old process is in an endless loop -rm requestedtemp* 2>/dev/null -# delete any recent-history json files older than 30m to make triply sure we avoid using stale data +# delete any recent-history json files older than 30m to make doubly sure we avoid using stale data find pumphistory*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find clock*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null -find *temp*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find request*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find current*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find glucose*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find iob*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null @@ -87,12 +86,15 @@ getpumpstatus() { grep -q status status.json.new && ( rsync -tu status.json.new status.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log } # query pump, and update pump data files if successful +getcurrenttemp() { + openaps report invoke currenttemp.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) + grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log +} querypump() { #openaps pumpquery 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) openaps report invoke clock.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) findclocknew && grep T clock.json.new && ( rsync -tu clock.json.new clock.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log - openaps report invoke currenttemp.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) - grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log + getcurrenttemp || return 1 openaps report invoke pumphistory.json.new 2>/dev/null || ( echo -n "!" >> /var/log/openaps/easy.log && return 1 ) grep -q timestamp pumphistory.json.new && ( rsync -tu pumphistory.json.new pumphistory.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log upload @@ -109,6 +111,24 @@ suggest() { openaps suggest || echo -n "!" >> /var/log/openaps/easy.log grep -q "too old" requestedtemp.online.json || ( find /tmp/openaps.online -mmin -10 | egrep -q '.*' && rsync -tu requestedtemp.online.json requestedtemp.json || rsync -tu requestedtemp.offline.json requestedtemp.json ) } +enact() { + retries=5 + retry=0 + until openaps enact; do + retry=`expr $retry + 1` + echo "enact failed; retry $retry" + if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retries retries"; return $?; fi + sleep 10; + done + if tail enactedtemp.json; then + ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log + cat iob.json | json_pp | grep '"iob' >> /var/log/openaps/easy.log + if $AZURE_SQL_API_HOST; then + send-tempbasal-Azure iob.json enactedtemp.json glucose.json $AZURE_SQL_API_HOST + fi + return 0 + fi +} # get updated pump settings (basal schedules, targets, ISF, etc.) getpumpsettings() { ~/openaps-js/bin/pumpsettings.sh; } @@ -191,15 +211,7 @@ execute() { cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log if grep -q rate requestedtemp.json; then echo "Enacting temp" - retries=5 - retry=0 - until openaps enact; do - retry=`expr $retry + 1` - echo "enact failed; retry $retry" - if [ $retry -ge $retries ]; then bail "Failed to enact temp after $retries retries"; return $?; fi - sleep 10; - done - tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && cat iob.json | json_pp | grep '"iob' >> /var/log/openaps/easy.log && return 0 + enact fi } @@ -253,11 +265,11 @@ while(true); do getglucose && openaps report invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log # set a new reservoir baseline and watch for changes (boluses) openaps report invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log && rsync -tu reservoir.json.new reservoir.json - openaps report invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + getcurrenttemp until actionrequired; do touch /tmp/openaps.lock getglucose && openaps report invoke requestedtemp.online.json && cat requestedtemp.online.json | json_pp | grep reason >> /var/log/openaps/easy.log - openaps report invoke currenttemp.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log + getcurrenttemp openaps report invoke reservoir.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log openaps report invoke clock.json.new 2>/dev/null || echo -n "!" >> /var/log/openaps/easy.log findclocknew && grep T clock.json.new && rsync -tu clock.json.new clock.json || echo -n "!" >> /var/log/openaps/easy.log From a06aa40d421bcd23a1b570a558c7e0a0044de51c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 18:51:45 -0700 Subject: [PATCH 086/131] only try ns-upload if NIGHTSCOUT_HOST exists --- bin/loop.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index 757e57a..a47ef24 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -102,9 +102,9 @@ querypump() { } # try to upload pumphistory data upload() { - #findpumphistory && ~/bin/openaps-mongo.sh & - ~/openaps-js/bin/ns-upload.sh - #ping -c 1 google.com > /dev/null && touch /tmp/openaps.online + if $NIGHTSCOUT_HOST; then + ~/openaps-js/bin/ns-upload.sh + fi } # if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) suggest() { From f6e1ccb1e5954869dd337f5c33c2703a2545325d Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Sun, 20 Sep 2015 18:56:52 -0700 Subject: [PATCH 087/131] syntax --- bin/loop.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/loop.sh b/bin/loop.sh index a47ef24..bcfec3b 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -102,7 +102,7 @@ querypump() { } # try to upload pumphistory data upload() { - if $NIGHTSCOUT_HOST; then + if [ ! -z "$NIGHTSCOUT_HOST" ]; then ~/openaps-js/bin/ns-upload.sh fi } @@ -123,7 +123,7 @@ enact() { if tail enactedtemp.json; then ( echo && cat enactedtemp.json | egrep -i "bg|dur|rate|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log cat iob.json | json_pp | grep '"iob' >> /var/log/openaps/easy.log - if $AZURE_SQL_API_HOST; then + if [ ! -z "$AZURE_SQL_API_HOST" ]; then send-tempbasal-Azure iob.json enactedtemp.json glucose.json $AZURE_SQL_API_HOST fi return 0 From 142c99eced5fbb7f7b746dc58e019f2cd127d2dd Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Tue, 22 Sep 2015 20:00:43 -0700 Subject: [PATCH 088/131] don't delete current_basal_profile.json --- bin/loop.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/loop.sh b/bin/loop.sh index bcfec3b..b745f88 100755 --- a/bin/loop.sh +++ b/bin/loop.sh @@ -29,7 +29,7 @@ cd ~/openaps-dev/ || die "can't cd ~/openaps-dev/" find pumphistory*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find clock*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find request*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null -find current*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null +find current*temp*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find glucose*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null find iob*.json* -mmin +30 -exec rm {} \; 2>/dev/null > /dev/null From 0bc352dabc379a992f1cbeeb4b69523d9e4ee3e5 Mon Sep 17 00:00:00 2001 From: cjo20 Date: Sun, 27 Sep 2015 00:29:56 +0100 Subject: [PATCH 089/131] Adding ns-upload-glucose.sh --- bin/ns-upload-glucose.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100755 bin/ns-upload-glucose.sh diff --git a/bin/ns-upload-glucose.sh b/bin/ns-upload-glucose.sh new file mode 100755 index 0000000..f10cef2 --- /dev/null +++ b/bin/ns-upload-glucose.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Author: Ben West, Maintainer: Scott Leibrand + +HISTORY=${1-glucosehistory.json} +OUTPUT=${2-glucosehistory.ns.json} +#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 = 'medtronic'" \ + > $OUTPUT + +# requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) +curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $NIGHTSCOUT_HOST/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $NIGHTSCOUT_HOST" ) || echo "Unable to upload to $NIGHTSCOUT_HOST" From 482e303b3c3bc097ef04eac05b39de532f1a1d38 Mon Sep 17 00:00:00 2001 From: cjo20 Date: Sun, 27 Sep 2015 00:58:12 +0100 Subject: [PATCH 090/131] In ns-upload-glucose, fix 'type' for sgv entries, set device to show it comes from cgm --- bin/ns-upload-glucose.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/ns-upload-glucose.sh b/bin/ns-upload-glucose.sh index f10cef2..0ffdfef 100755 --- a/bin/ns-upload-glucose.sh +++ b/bin/ns-upload-glucose.sh @@ -10,7 +10,8 @@ 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 = 'medtronic'" \ + json -e "this.type = (this.name == 'GlucoseSensorData') ? 'sgv' : 'pumpdata'" | \ + json -e "this.device = 'openaps://medtronic/pump/cgm'" \ > $OUTPUT # requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) From b03821ecd0e17ccea2f412033b70227a7c0222cf Mon Sep 17 00:00:00 2001 From: cjo20 Date: Sun, 27 Sep 2015 01:04:41 +0100 Subject: [PATCH 091/131] ns-upload-glucose.sh, note this was written for decocare v0.0.17 --- bin/ns-upload-glucose.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/ns-upload-glucose.sh b/bin/ns-upload-glucose.sh index 0ffdfef..65a0c38 100755 --- a/bin/ns-upload-glucose.sh +++ b/bin/ns-upload-glucose.sh @@ -2,6 +2,7 @@ # Author: Ben West, Maintainer: Scott Leibrand +# Written for decocare v0.0.17. Will need updating the the decocare json format changes. HISTORY=${1-glucosehistory.json} OUTPUT=${2-glucosehistory.ns.json} #TZ=${3-$(date +%z)} From e757efe7d77b19b6964067ba675fa9c6144f8fc3 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 17:10:57 -0700 Subject: [PATCH 092/131] make script names match installed script names --- bin/{iob.js => calculate-iob.js} | 0 bin/{getprofile.js => get-profile.js} | 0 bin/{sendtempbasal-Azure.js => send-tempbasal-Azure.js} | 0 package.json | 6 +++--- 4 files changed, 3 insertions(+), 3 deletions(-) rename bin/{iob.js => calculate-iob.js} (100%) rename bin/{getprofile.js => get-profile.js} (100%) rename bin/{sendtempbasal-Azure.js => send-tempbasal-Azure.js} (100%) diff --git a/bin/iob.js b/bin/calculate-iob.js similarity index 100% rename from bin/iob.js rename to bin/calculate-iob.js diff --git a/bin/getprofile.js b/bin/get-profile.js similarity index 100% rename from bin/getprofile.js rename to bin/get-profile.js diff --git a/bin/sendtempbasal-Azure.js b/bin/send-tempbasal-Azure.js similarity index 100% rename from bin/sendtempbasal-Azure.js rename to bin/send-tempbasal-Azure.js diff --git a/package.json b/package.json index 2df3e67..1387f3a 100644 --- a/package.json +++ b/package.json @@ -18,10 +18,10 @@ "url": "https://github.com/openaps/openaps-js/issues" }, "bin" : { - "calculate-iob" : "./bin/iob.js", + "calculate-iob" : "./bin/calculate-iob.js", "determine-basal" : "./bin/determine-basal.js", - "send-tempbasal-Azure" : "./bin/sendtempbasal-Azure.js", - "get-profile" : "./bin/getprofile.js" + "send-tempbasal-Azure" : "./bin/send-tempbasal-Azure.js", + "get-profile" : "./bin/get-profile.js" }, "homepage": "https://github.com/openaps/openaps-js" } From 0826bee3a6a49be1a00f3d5fcd3058cc00ed23b1 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 17:17:25 -0700 Subject: [PATCH 093/131] add more tools to the package/distribution --- bin/{pebble.js => diyps-pebble.js} | 0 bin/{fix-dead-carelink.sh => reset-wifi-dongle.sh} | 0 package.json | 4 +++- 3 files changed, 3 insertions(+), 1 deletion(-) rename bin/{pebble.js => diyps-pebble.js} (100%) rename bin/{fix-dead-carelink.sh => reset-wifi-dongle.sh} (100%) diff --git a/bin/pebble.js b/bin/diyps-pebble.js similarity index 100% rename from bin/pebble.js rename to bin/diyps-pebble.js diff --git a/bin/fix-dead-carelink.sh b/bin/reset-wifi-dongle.sh similarity index 100% rename from bin/fix-dead-carelink.sh rename to bin/reset-wifi-dongle.sh diff --git a/package.json b/package.json index 1387f3a..99aea6a 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "calculate-iob" : "./bin/calculate-iob.js", "determine-basal" : "./bin/determine-basal.js", "send-tempbasal-Azure" : "./bin/send-tempbasal-Azure.js", - "get-profile" : "./bin/get-profile.js" + "get-profile" : "./bin/get-profile.js", + "bin/reset-wifi-dongle": "bin/reset-wifi-dongle.sh", + "diyps-pebble" : "./bin/diyps-pebble.js" }, "homepage": "https://github.com/openaps/openaps-js" } From dbf845852b74512ab3d70abc21f8c170f91975eb Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 17:29:33 -0700 Subject: [PATCH 094/131] separate concerns a bit The formatting things are unique, different concern from doing network I/O or uploading. --- ...pload-glucose.sh => mm-format-ns-glucose.sh} | 5 ++--- ...s-upload.sh => mm-format-ns-pump-history.sh} | 5 ++--- bin/ns-upload-entries.sh | 17 +++++++++++++++++ package.json | 5 ++++- 4 files changed, 25 insertions(+), 7 deletions(-) rename bin/{ns-upload-glucose.sh => mm-format-ns-glucose.sh} (56%) rename bin/{ns-upload.sh => mm-format-ns-pump-history.sh} (51%) create mode 100755 bin/ns-upload-entries.sh diff --git a/bin/ns-upload-glucose.sh b/bin/mm-format-ns-glucose.sh similarity index 56% rename from bin/ns-upload-glucose.sh rename to bin/mm-format-ns-glucose.sh index 65a0c38..8f21418 100755 --- a/bin/ns-upload-glucose.sh +++ b/bin/mm-format-ns-glucose.sh @@ -1,6 +1,7 @@ #!/bin/bash -# Author: Ben West, Maintainer: Scott Leibrand +# Author: Ben West @bewest +# Maintainer: Chris Oattes @cjo20 # Written for decocare v0.0.17. Will need updating the the decocare json format changes. HISTORY=${1-glucosehistory.json} @@ -15,5 +16,3 @@ cat $HISTORY | \ json -e "this.device = 'openaps://medtronic/pump/cgm'" \ > $OUTPUT -# requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) -curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $NIGHTSCOUT_HOST/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $NIGHTSCOUT_HOST" ) || echo "Unable to upload to $NIGHTSCOUT_HOST" diff --git a/bin/ns-upload.sh b/bin/mm-format-ns-pump-history.sh similarity index 51% rename from bin/ns-upload.sh rename to bin/mm-format-ns-pump-history.sh index 7805de3..5864640 100755 --- a/bin/ns-upload.sh +++ b/bin/mm-format-ns-pump-history.sh @@ -1,6 +1,7 @@ #!/bin/bash -# Author: Ben West, Maintainer: Scott Leibrand +# Author: Ben West +# Maintainer: Scott Leibrand HISTORY=${1-pumphistory.json} OUTPUT=${2-pumphistory.ns.json} @@ -15,5 +16,3 @@ cat $HISTORY | \ > $OUTPUT -# requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) -curl -s -X POST --data-binary @$OUTPUT -H "API-SECRET: $API_SECRET" -H "content-type: application/json" $NIGHTSCOUT_HOST/api/v1/entries.json >/dev/null && ( touch /tmp/openaps.online && echo "Uploaded $OUTPUT to $NIGHTSCOUT_HOST" ) || echo "Unable to upload to $NIGHTSCOUT_HOST" diff --git a/bin/ns-upload-entries.sh b/bin/ns-upload-entries.sh new file mode 100755 index 0000000..a53e7b1 --- /dev/null +++ b/bin/ns-upload-entries.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Author: Ben West + +ENTRIES=${1-entries.json} +NIGHTSCOUT_HOST=${NIGHTSCOUT_HOST-localhost:1337} +#TZ=${3-$(date +%z)} +OUTPUT=${2} + +export ENTRIES API_SECRET NIGHTSCOUT_HOST +# requires API_SECRET and NIGHTSCOUT_HOST to be set in calling environment (i.e. in crontab) +( +curl -s -X POST --data-binary @$ENTRIES \ + -H "API-SECRET: $API_SECRET" \ + -H "content-type: application/json" \ + $NIGHTSCOUT_HOST/api/v1/entries.json +) && ( test -n "$OUTPUT" && touch $OUTPUT ; logger "Uploaded $ENTRIES to $NIGHTSCOUT_HOST" ) || logger "Unable to upload to $NIGHTSCOUT_HOST" diff --git a/package.json b/package.json index 99aea6a..4ef97c9 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,10 @@ "determine-basal" : "./bin/determine-basal.js", "send-tempbasal-Azure" : "./bin/send-tempbasal-Azure.js", "get-profile" : "./bin/get-profile.js", - "bin/reset-wifi-dongle": "bin/reset-wifi-dongle.sh", + "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", + "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", + "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", + "ns-upload-entries": "./bin/ns-upload-entries.sh", "diyps-pebble" : "./bin/diyps-pebble.js" }, "homepage": "https://github.com/openaps/openaps-js" From 65d609ff0a7cc2ee8c00d8c634544faf335ad4cc Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 17:32:01 -0700 Subject: [PATCH 095/131] use stdout by default --- bin/mm-format-ns-glucose.sh | 2 +- bin/mm-format-ns-pump-history.sh | 2 +- bin/ns-upload-entries.sh | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/mm-format-ns-glucose.sh b/bin/mm-format-ns-glucose.sh index 8f21418..5dba394 100755 --- a/bin/mm-format-ns-glucose.sh +++ b/bin/mm-format-ns-glucose.sh @@ -5,7 +5,7 @@ # Written for decocare v0.0.17. Will need updating the the decocare json format changes. HISTORY=${1-glucosehistory.json} -OUTPUT=${2-glucosehistory.ns.json} +OUTPUT=${2-/dev/fd/1} #TZ=${3-$(date +%z)} cat $HISTORY | \ diff --git a/bin/mm-format-ns-pump-history.sh b/bin/mm-format-ns-pump-history.sh index 5864640..6556249 100755 --- a/bin/mm-format-ns-pump-history.sh +++ b/bin/mm-format-ns-pump-history.sh @@ -4,7 +4,7 @@ # Maintainer: Scott Leibrand HISTORY=${1-pumphistory.json} -OUTPUT=${2-pumphistory.ns.json} +OUTPUT=${2-/dev/fd/1} #TZ=${3-$(date +%z)} cat $HISTORY | \ diff --git a/bin/ns-upload-entries.sh b/bin/ns-upload-entries.sh index a53e7b1..0bb0f56 100755 --- a/bin/ns-upload-entries.sh +++ b/bin/ns-upload-entries.sh @@ -1,6 +1,7 @@ #!/bin/bash # Author: Ben West +# Maintainer: @cjo20, @scottleibrand ENTRIES=${1-entries.json} NIGHTSCOUT_HOST=${NIGHTSCOUT_HOST-localhost:1337} @@ -15,3 +16,4 @@ curl -s -X POST --data-binary @$ENTRIES \ -H "content-type: application/json" \ $NIGHTSCOUT_HOST/api/v1/entries.json ) && ( test -n "$OUTPUT" && touch $OUTPUT ; logger "Uploaded $ENTRIES to $NIGHTSCOUT_HOST" ) || logger "Unable to upload to $NIGHTSCOUT_HOST" + From a61cf597627fd8b681b1735734f8bf33611d63ad Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 19:49:55 -0700 Subject: [PATCH 096/131] Provide top level exec shell for diyps. A little tool to help @scottleibrand save some typing. Any tool called `diyps-foo`, eg `diyps-pebble` can be registered once in openaps as `diyps` device, and then used many times using `openaps use diyps shell pebble ...` etc. --- bin/diyps.sh | 22 ++++++++++++++++++++++ package.json | 17 ++++++++++------- 2 files changed, 32 insertions(+), 7 deletions(-) create mode 100755 bin/diyps.sh diff --git a/bin/diyps.sh b/bin/diyps.sh new file mode 100755 index 0000000..2fa36e4 --- /dev/null +++ b/bin/diyps.sh @@ -0,0 +1,22 @@ +#!/bin/bash + + +self=$0 +NAME=$1 +shift +PROGRAM="diyps-${NAME}" +COMMAND=$(which $PROGRAM | head -n 1) +if [ -n "$COMMAND" ] ; then + exec $COMMAND "$*" +else + cat < + +Valid commands: + diyps pebble + diyps help - this message +EOF +fi + + diff --git a/package.json b/package.json index 4ef97c9..e0d7956 100644 --- a/package.json +++ b/package.json @@ -17,16 +17,19 @@ "bugs": { "url": "https://github.com/openaps/openaps-js/issues" }, - "bin" : { - "calculate-iob" : "./bin/calculate-iob.js", - "determine-basal" : "./bin/determine-basal.js", - "send-tempbasal-Azure" : "./bin/send-tempbasal-Azure.js", - "get-profile" : "./bin/get-profile.js", + "bin": { + "calculate-iob": "./bin/calculate-iob.js", + "determine-basal": "./bin/determine-basal.js", + "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", + "get-profile": "./bin/get-profile.js", "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", "ns-upload-entries": "./bin/ns-upload-entries.sh", - "diyps-pebble" : "./bin/diyps-pebble.js" + "diyps-pebble": "./bin/diyps-pebble.js" }, - "homepage": "https://github.com/openaps/openaps-js" + "homepage": "https://github.com/openaps/openaps-js", + "dependencies": { + "share2nightscout-bridge": "^0.1.5" + } } From d413a0b75fce9f51a61b56595e957d3330185095 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 26 Sep 2015 19:56:23 -0700 Subject: [PATCH 097/131] even more helpers --- bin/diyps.sh | 2 ++ package.json | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/bin/diyps.sh b/bin/diyps.sh index 2fa36e4..98cf47d 100755 --- a/bin/diyps.sh +++ b/bin/diyps.sh @@ -15,6 +15,8 @@ $self Valid commands: diyps pebble + diyps calculate-iob + diyps determine-basal diyps help - this message EOF fi diff --git a/package.json b/package.json index e0d7956..225aa4a 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,15 @@ "bin": { "calculate-iob": "./bin/calculate-iob.js", "determine-basal": "./bin/determine-basal.js", + "diyps-calculate-iob": "./bin/calculate-iob.js", + "diyps-determine-basal": "./bin/determine-basal.js", "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", "get-profile": "./bin/get-profile.js", "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", + "diyps": "./bin/diyps.sh", + "openaps-js": "./bin/diyps.sh", "ns-upload-entries": "./bin/ns-upload-entries.sh", "diyps-pebble": "./bin/diyps-pebble.js" }, From 48168026fdc82b79b72f3bbbea3dc6baa08acb79 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sun, 27 Sep 2015 15:25:02 -0700 Subject: [PATCH 098/131] allow diyps wrapper to handle some basic debugging --- bin/diyps.sh | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/bin/diyps.sh b/bin/diyps.sh index 98cf47d..b2a553a 100755 --- a/bin/diyps.sh +++ b/bin/diyps.sh @@ -6,9 +6,8 @@ NAME=$1 shift PROGRAM="diyps-${NAME}" COMMAND=$(which $PROGRAM | head -n 1) -if [ -n "$COMMAND" ] ; then - exec $COMMAND "$*" -else + +function help_message ( ) { cat < @@ -19,6 +18,21 @@ Valid commands: diyps determine-basal diyps help - this message EOF -fi +} + +case $NAME in +env) + echo PATH=$PATH + env + exit + ;; +help) + help_message + ;; +*) + test -n "$COMMAND" && exec $COMMAND $* + ;; +esac + From a07e2f99125773b578a7acd9aba578bf07a20e01 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sun, 27 Sep 2015 17:05:48 -0700 Subject: [PATCH 099/131] init mm-stick tool To help with common debugging tasks with the usb stick. --- bin/diyps.sh | 1 - bin/mm-stick.sh | 100 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100755 bin/mm-stick.sh diff --git a/bin/diyps.sh b/bin/diyps.sh index b2a553a..435e707 100755 --- a/bin/diyps.sh +++ b/bin/diyps.sh @@ -35,4 +35,3 @@ help) esac - diff --git a/bin/mm-stick.sh b/bin/mm-stick.sh new file mode 100755 index 0000000..c87761c --- /dev/null +++ b/bin/mm-stick.sh @@ -0,0 +1,100 @@ +#!/bin/bash + +# Author: Ben West @bewest + +# Written for decocare v0.0.17. +OUTPUT=/dev/fd/1 +if [[ "$1" == "-f" ]] ; then +shift +OUTPUT=$1 +shift +fi +OPERATION=${1-help} + +function print_help ( ) { + cat < unbind + echo -n "$i" > bind + done + done + ;; + list-usb) + if [[ $EUID != 0 ]] ; then + echo This must be run as root! + exit 1 + fi + + for xhci in /sys/bus/pci/drivers/?hci_hcd ; do + + if ! cd $xhci ; then + echo Weird error. Failed to change directory to $xhci + exit 1 + fi + + echo Resetting devices from $xhci... + + for i in ????:??:??.? ; do + pwd + echo $i + ls $i + done + done + ;; + *|help) + print_help + ;; + esac +) +shift +OPERATION=${1} +done > $OUTPUT + + From 40a53a5f3ef36a0e94e5850e7183cee5c5e0c592 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sun, 27 Sep 2015 17:08:02 -0700 Subject: [PATCH 100/131] distribute with package Should help @audifile a bit. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 225aa4a..86e8630 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", "diyps": "./bin/diyps.sh", + "mm-stick": "./bin/mm-stick.sh", "openaps-js": "./bin/diyps.sh", "ns-upload-entries": "./bin/ns-upload-entries.sh", "diyps-pebble": "./bin/diyps-pebble.js" From 497057e2c0c54e7a0ebaafd4cb4810921cb407f8 Mon Sep 17 00:00:00 2001 From: Rachel Date: Sun, 27 Sep 2015 20:13:17 -0400 Subject: [PATCH 101/131] changed so pebble card can read from apache server --- bin/pebble.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/pebble.sh b/bin/pebble.sh index 75a2c47..75e95ef 100755 --- a/bin/pebble.sh +++ b/bin/pebble.sh @@ -28,5 +28,5 @@ node ~/openaps-js/bin/iob.js pumphistory.json profile.json now.json > iob.json.n node ~/openaps-js/bin/determine-basal.js iob.json currenttemp.json glucose.json profile.json > requestedtemp.json.new && grep reason requestedtemp.json.new && rsync -tu requestedtemp.json.new requestedtemp.json node ~/openaps-js/bin/pebble.js glucose.json iob.json current_basal_profile.json currenttemp.json requestedtemp.json enactedtemp.json > /tmp/pebble-openaps.json #cat /tmp/pebble-openaps.json -grep "refresh_frequency" /tmp/pebble-openaps.json && rsync -tu /tmp/pebble-openaps.json www/openaps.json +grep "refresh_frequency" /tmp/pebble-openaps.json && rsync -tu /tmp/pebble-openaps.json /var/www/openaps.json #cat www/openaps.json From a6a81cf0d966ce7ac547a25b3792b8537ee35532 Mon Sep 17 00:00:00 2001 From: Ali Mazaheri Date: Sun, 4 Oct 2015 12:36:36 -0700 Subject: [PATCH 102/131] Code was ignoring old data Replaced && with || to properly catch old bg data --- bin/determine-basal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/determine-basal.js b/bin/determine-basal.js index fbcce80..83a3467 100644 --- a/bin/determine-basal.js +++ b/bin/determine-basal.js @@ -47,7 +47,7 @@ if (!module.parent) { } else { console.error("Could not determine last BG time"); } var minAgo = (systemTime - bgTime) / 60 / 1000 - if (minAgo > 10 && minAgo < -5) { // Dexcom data is too old, or way in the future + if (minAgo > 10 || minAgo < -5) { // Dexcom data is too old, or way in the future var reason = "BG data is too old, or clock set incorrectly"; console.error(reason); return 1; From f74e54dd5597ebedb2f5f978beb19efe678ad267 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 08:29:44 -0700 Subject: [PATCH 103/131] be strict about errors --- bin/mm-stick.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/mm-stick.sh b/bin/mm-stick.sh index c87761c..bfb1e63 100755 --- a/bin/mm-stick.sh +++ b/bin/mm-stick.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -eu # Author: Ben West @bewest @@ -10,6 +10,7 @@ OUTPUT=$1 shift fi OPERATION=${1-help} +export $OPERATION function print_help ( ) { cat < $OUTPUT - - +exit $? From 839b9d932c2d63836b5003269fb8cea578a86d55 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 09:01:25 -0700 Subject: [PATCH 104/131] fix default behavior with no args should not error --- bin/mm-stick.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mm-stick.sh b/bin/mm-stick.sh index bfb1e63..00c7bfa 100755 --- a/bin/mm-stick.sh +++ b/bin/mm-stick.sh @@ -4,7 +4,7 @@ # Written for decocare v0.0.17. OUTPUT=/dev/fd/1 -if [[ "$1" == "-f" ]] ; then +if [[ "${1-}" == "-f" ]] ; then shift OUTPUT=$1 shift From c3a821b01c1d8330dcd4b3920e6e6735ffc9fae9 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 10:08:35 -0700 Subject: [PATCH 105/131] ifttt tool, rename everything to oref0 Hat tip @danalewis, @channemann Also, include @audiefile's tool to post notifications to IFTTT. It's modified to be usable as `oref0 iftt-notify ` as a use for openaps device, `oref0`. --- ...alculate-iob.js => oref0-calculate-iob.js} | 0 ...mine-basal.js => oref0-determine-basal.js} | 0 bin/{get-profile.js => oref0-get-profile.js} | 0 bin/oref0-iftt-notify | 97 +++++++++++++++++++ bin/{diyps-pebble.js => oref0-pebble.js} | 0 bin/{diyps.sh => oref0.sh} | 13 +-- package.json | 15 ++- 7 files changed, 111 insertions(+), 14 deletions(-) rename bin/{calculate-iob.js => oref0-calculate-iob.js} (100%) mode change 100644 => 100755 rename bin/{determine-basal.js => oref0-determine-basal.js} (100%) mode change 100644 => 100755 rename bin/{get-profile.js => oref0-get-profile.js} (100%) mode change 100644 => 100755 create mode 100755 bin/oref0-iftt-notify rename bin/{diyps-pebble.js => oref0-pebble.js} (100%) mode change 100644 => 100755 rename bin/{diyps.sh => oref0.sh} (66%) diff --git a/bin/calculate-iob.js b/bin/oref0-calculate-iob.js old mode 100644 new mode 100755 similarity index 100% rename from bin/calculate-iob.js rename to bin/oref0-calculate-iob.js diff --git a/bin/determine-basal.js b/bin/oref0-determine-basal.js old mode 100644 new mode 100755 similarity index 100% rename from bin/determine-basal.js rename to bin/oref0-determine-basal.js diff --git a/bin/get-profile.js b/bin/oref0-get-profile.js old mode 100644 new mode 100755 similarity index 100% rename from bin/get-profile.js rename to bin/oref0-get-profile.js diff --git a/bin/oref0-iftt-notify b/bin/oref0-iftt-notify new file mode 100755 index 0000000..2f72140 --- /dev/null +++ b/bin/oref0-iftt-notify @@ -0,0 +1,97 @@ +#!/bin/bash + +self=$0 +# Something like this: +# https://maker.ifttt.com/trigger/{event}/with/key/MyKey +IFTTT_TRIGGER=${IFTTT_TRIGGER-${1}} +IFTT_NOTIFY_USAGE="${2-pump model}" + +function help_message ( ) { +cat < +## Setup IFTTT Account + +You need to create an account and connect to the Maker channel and the +notification channel of your choice. I use pushover as I already had the app +and it allows me more control over the notification on my phone. + +## Create an IF recipe +The trigger is the maker channel. You can customize the notification message +if you wish. + +## Get the event trigger +On the Maker channel there is a "how to trigger" link. Copy and paste the url +for the example curl command, be sure to change the event name field. +The URL, something like: +# https://maker.ifttt.com/trigger/{event}/with/key/MyKey + +You can pass the IFTTT_TRIGGER, which is the trigger URL as the first +argument, or define it as an environment variable in your crontab. + +Command line: + + $self https://maker.ifttt.com/trigger/{event}/with/key/MyKey + + +Crontab: + IFTTT_TRIGGER=https://maker.ifttt.com/trigger/{event}/with/key/MyKey + +By default $self will check that the stick works, and notify the IFTTT_TRIGGER +endpoint only if the the stick fails to check out. If the stick diagnostics +indicate the carelink stick is working, $self will run: + + openaps use $IFTT_NOTIFY_USAGE + +You can specify which openaps use command to use in the second argument, or by +setting the IFTT_NOTIFY_USAGE environment variable in crontab: + +Command line, note the quotes, the second term must be passed as single word. + + $self https://maker.ifttt.com/trigger/{event}/with/key/MyKey 'pump model' + +Crontab: + + IFTT_NOTIFY_USAGE='pump model' + +EOF + +} + + + +case $1 in +env) + echo PATH=$PATH + env + exit + ;; +help) + help_message + ;; +*) + if [[ -z "$IFTTT_TRIGGER" || -z "$IFTT_NOTIFY_USAGE" ]] ; then + help_message + exit 1 + fi + ;; +esac + + +empty="" +# check carelink is working - if not send notification +# maybe switch: +# mm-stick diagnose > /dev/null || curl -X POST $IFTTT_TRIGGER + +python -m decocare.stick $(python -m decocare.scan) >/dev/null || curl -X POST $IFTTT_TRIGGER +echo "Carelink Stick OK" + +# check carelink can talk to pump - if not send notification +model=$(openaps use $IFTT_NOTIFY_USAGE) +echo "Model: " $model +if [ $model=$empty ]; +then + echo "Model is empty" + curl -X POST $IFTTT_TRIGGER +fi + diff --git a/bin/diyps-pebble.js b/bin/oref0-pebble.js old mode 100644 new mode 100755 similarity index 100% rename from bin/diyps-pebble.js rename to bin/oref0-pebble.js diff --git a/bin/diyps.sh b/bin/oref0.sh similarity index 66% rename from bin/diyps.sh rename to bin/oref0.sh index 435e707..a8e521b 100755 --- a/bin/diyps.sh +++ b/bin/oref0.sh @@ -2,9 +2,9 @@ self=$0 -NAME=$1 +NAME=${1-help} shift -PROGRAM="diyps-${NAME}" +PROGRAM="oref0-${NAME}" COMMAND=$(which $PROGRAM | head -n 1) function help_message ( ) { @@ -13,10 +13,11 @@ function help_message ( ) { $self Valid commands: - diyps pebble - diyps calculate-iob - diyps determine-basal - diyps help - this message + oref0 pebble + oref0 get-profile + oref0 calculate-iob + oref0 determine-basal + oref0 help - this message EOF } diff --git a/package.json b/package.json index 86e8630..d224738 100644 --- a/package.json +++ b/package.json @@ -18,20 +18,19 @@ "url": "https://github.com/openaps/openaps-js/issues" }, "bin": { - "calculate-iob": "./bin/calculate-iob.js", - "determine-basal": "./bin/determine-basal.js", - "diyps-calculate-iob": "./bin/calculate-iob.js", - "diyps-determine-basal": "./bin/determine-basal.js", + "oref0-calculate-iob": "./bin/oref0-calculate-iob.js", + "oref0-determine-basal": "./bin/oref0-determine-basal.js", "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", - "get-profile": "./bin/get-profile.js", + "oref0-get-profile": "./bin/oref0-get-profile.js", + "oref0-iftt-notify": "./bin/oref0-iftt-notify", "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", - "diyps": "./bin/diyps.sh", + "oref0": "./bin/oref0.sh", "mm-stick": "./bin/mm-stick.sh", - "openaps-js": "./bin/diyps.sh", + "openaps-js": "./bin/oref0.sh", "ns-upload-entries": "./bin/ns-upload-entries.sh", - "diyps-pebble": "./bin/diyps-pebble.js" + "oref0-pebble": "./bin/oref0-pebble.js" }, "homepage": "https://github.com/openaps/openaps-js", "dependencies": { From e81593debff422beed77c8b3fe2dc90f3af42bdf Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 11:24:35 -0700 Subject: [PATCH 106/131] spruce up help output a bit --- bin/oref0-iftt-notify | 4 +++- bin/oref0.sh | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/bin/oref0-iftt-notify b/bin/oref0-iftt-notify index 2f72140..774b30a 100755 --- a/bin/oref0-iftt-notify +++ b/bin/oref0-iftt-notify @@ -1,6 +1,6 @@ #!/bin/bash -self=$0 +self=$(basename $0) # Something like this: # https://maker.ifttt.com/trigger/{event}/with/key/MyKey IFTTT_TRIGGER=${IFTTT_TRIGGER-${1}} @@ -10,6 +10,7 @@ function help_message ( ) { cat < + ## Setup IFTTT Account You need to create an account and connect to the Maker channel and the @@ -54,6 +55,7 @@ Crontab: IFTT_NOTIFY_USAGE='pump model' +Author: @audiefile EOF } diff --git a/bin/oref0.sh b/bin/oref0.sh index a8e521b..e5d2c73 100755 --- a/bin/oref0.sh +++ b/bin/oref0.sh @@ -1,7 +1,7 @@ #!/bin/bash -self=$0 +self=$(basename $0) NAME=${1-help} shift PROGRAM="oref0-${NAME}" @@ -13,7 +13,9 @@ function help_message ( ) { $self Valid commands: + oref0 env - print information about environment. oref0 pebble + oref0 iftt-notify oref0 get-profile oref0 calculate-iob oref0 determine-basal From 20ad134d5058824fcad9788bf423a18ad9d6f2e5 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 11:52:27 -0700 Subject: [PATCH 107/131] add ascii art --- bin/oref0.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/oref0.sh b/bin/oref0.sh index e5d2c73..3070f30 100755 --- a/bin/oref0.sh +++ b/bin/oref0.sh @@ -12,6 +12,11 @@ function help_message ( ) { Usage: $self + ______ ______ ______ ______ 0 +/ | | \ | | | \ | | | | +| | | | | |__| | | |---- | |---- +\_|__|_/ |_| \_\ |_|____ |_| + Valid commands: oref0 env - print information about environment. oref0 pebble From 5a6621fe6eca9f124c4640ebd77c57d334985f2b Mon Sep 17 00:00:00 2001 From: Rachel Date: Tue, 6 Oct 2015 18:08:44 -0400 Subject: [PATCH 108/131] Edit test condition in oref0-itff-notify to be more roboust (eliminate false positives) --- bin/oref0-iftt-notify | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/oref0-iftt-notify b/bin/oref0-iftt-notify index 774b30a..2fbdb0b 100755 --- a/bin/oref0-iftt-notify +++ b/bin/oref0-iftt-notify @@ -80,7 +80,7 @@ help) esac -empty="" +empty='""' # check carelink is working - if not send notification # maybe switch: # mm-stick diagnose > /dev/null || curl -X POST $IFTTT_TRIGGER @@ -91,7 +91,7 @@ echo "Carelink Stick OK" # check carelink can talk to pump - if not send notification model=$(openaps use $IFTT_NOTIFY_USAGE) echo "Model: " $model -if [ $model=$empty ]; +if [ x$model = x$empty ]; then echo "Model is empty" curl -X POST $IFTTT_TRIGGER From eab2e1f53a2b505821166f26c7cbd68648cf8a0f Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 19:39:35 -0700 Subject: [PATCH 109/131] %s/FTT_/FTTT_/g --- bin/oref0-iftt-notify | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bin/oref0-iftt-notify b/bin/oref0-iftt-notify index 2fbdb0b..a9cd434 100755 --- a/bin/oref0-iftt-notify +++ b/bin/oref0-iftt-notify @@ -4,7 +4,7 @@ self=$(basename $0) # Something like this: # https://maker.ifttt.com/trigger/{event}/with/key/MyKey IFTTT_TRIGGER=${IFTTT_TRIGGER-${1}} -IFTT_NOTIFY_USAGE="${2-pump model}" +IFTTT_NOTIFY_USAGE="${2-pump model}" function help_message ( ) { cat </dev/null || curl -X POST $ echo "Carelink Stick OK" # check carelink can talk to pump - if not send notification -model=$(openaps use $IFTT_NOTIFY_USAGE) +model=$(openaps use $IFTTT_NOTIFY_USAGE) echo "Model: " $model if [ x$model = x$empty ]; then From d77db472188902120f6adffa7ffcff33761e94f7 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 19:40:51 -0700 Subject: [PATCH 110/131] use -z "$model", bash/shell tweaks --- bin/oref0-iftt-notify | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/oref0-iftt-notify b/bin/oref0-iftt-notify index a9cd434..05343b7 100755 --- a/bin/oref0-iftt-notify +++ b/bin/oref0-iftt-notify @@ -91,7 +91,7 @@ echo "Carelink Stick OK" # check carelink can talk to pump - if not send notification model=$(openaps use $IFTTT_NOTIFY_USAGE) echo "Model: " $model -if [ x$model = x$empty ]; +if [ -z "$model" ]; then echo "Model is empty" curl -X POST $IFTTT_TRIGGER From 474343f088f6fe0426e6aca18f650598a0706ba5 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 19:42:43 -0700 Subject: [PATCH 111/131] rename to ifttt-notify for consistency Look what you started @audiefile. ;) --- bin/{oref0-iftt-notify => oref0-ifttt-notify} | 0 bin/oref0.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename bin/{oref0-iftt-notify => oref0-ifttt-notify} (100%) diff --git a/bin/oref0-iftt-notify b/bin/oref0-ifttt-notify similarity index 100% rename from bin/oref0-iftt-notify rename to bin/oref0-ifttt-notify diff --git a/bin/oref0.sh b/bin/oref0.sh index 3070f30..44ffa5c 100755 --- a/bin/oref0.sh +++ b/bin/oref0.sh @@ -20,7 +20,7 @@ $self Valid commands: oref0 env - print information about environment. oref0 pebble - oref0 iftt-notify + oref0 ifttt-notify oref0 get-profile oref0 calculate-iob oref0 determine-basal From e62e94af684e2a7d701e49bd4ae124a6e8d88c34 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 6 Oct 2015 19:47:25 -0700 Subject: [PATCH 112/131] experimental tweak, using mm-stick diagnose. --- bin/oref0-ifttt-notify | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/oref0-ifttt-notify b/bin/oref0-ifttt-notify index 05343b7..17ea29b 100755 --- a/bin/oref0-ifttt-notify +++ b/bin/oref0-ifttt-notify @@ -80,12 +80,11 @@ help) esac -empty='""' # check carelink is working - if not send notification # maybe switch: -# mm-stick diagnose > /dev/null || curl -X POST $IFTTT_TRIGGER -python -m decocare.stick $(python -m decocare.scan) >/dev/null || curl -X POST $IFTTT_TRIGGER +mm-stick diagnose > /dev/null || curl -X POST $IFTTT_TRIGGER +# python -m decocare.stick $(python -m decocare.scan) >/dev/null || curl -X POST $IFTTT_TRIGGER echo "Carelink Stick OK" # check carelink can talk to pump - if not send notification From ad6a120d7fe85764e7c991aa3c18571617784390 Mon Sep 17 00:00:00 2001 From: Ben West Date: Tue, 13 Oct 2015 02:02:42 -0700 Subject: [PATCH 113/131] fix package --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d224738..abdf4ec 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "oref0-determine-basal": "./bin/oref0-determine-basal.js", "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", "oref0-get-profile": "./bin/oref0-get-profile.js", - "oref0-iftt-notify": "./bin/oref0-iftt-notify", + "oref0-ifttt-notify": "./bin/oref0-ifttt-notify", "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", From 521d40a0455436b49f87459e590dde63ff9fd3f4 Mon Sep 17 00:00:00 2001 From: Ben West Date: Wed, 14 Oct 2015 14:31:34 -0700 Subject: [PATCH 114/131] add fail and warmup utilities --- bin/mm-stick.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/bin/mm-stick.sh b/bin/mm-stick.sh index 00c7bfa..0552985 100755 --- a/bin/mm-stick.sh +++ b/bin/mm-stick.sh @@ -18,15 +18,27 @@ Usage: $0 [{scan,diagnose,help},...] scan - Print the local location of a plugged in stick. diagnose - Run python -m decocare.stick \$(python -m decocare.scan) + warmup - Runs scan and diagnose with no output. + Exits 0 on success, non-zero exit code + otherwise. insert - Insert usbserial kernel module. remove - Remove usbserial kernel module. udev-info - Print udev information about the stick. list-usb - List usb information about the stick. reset-usb - Reset entire usb stack. WARNING, be careful. + fail - Always return a failing exit code. help - This message. EOF } +function print_fail ( ) { + cat < /dev/null + ;; remove) eval modprobe -r usbserial ;; @@ -89,6 +104,10 @@ case $OPERATION in done done ;; + fail) + print_fail $* + exit 1 + ;; *|help) print_help ;; From b50bfad6ac381ba5711dc73001e2497ca80bf78c Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 14 Oct 2015 21:34:05 -0700 Subject: [PATCH 115/131] rm loop.sh and replace with symlink to openaps-sh/loop.sh --- bin/loop.sh | 152 +--------------------------------------------------- 1 file changed, 1 insertion(+), 151 deletions(-) mode change 100755 => 120000 bin/loop.sh diff --git a/bin/loop.sh b/bin/loop.sh deleted file mode 100755 index 7036499..0000000 --- a/bin/loop.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/bash - -# Attempt to read from a Carelink reader, upload data, and calculate the new -# glucose value. -# -# 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. - -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin - -die() { - echo "$@" | tee -a /var/log/openaps/easy.log - exit 1 -} - -# remove any old stale lockfiles -find /tmp/openaps.lock -mmin +10 -exec rm {} \; 2>/dev/null > /dev/null - -# only one process can talk to the pump at a time -ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit - -echo "No lockfile: continuing" -touch /tmp/openaps.lock - -# make sure decocare can talk to the Carelink USB stick -~/decocare/insert.sh 2>/dev/null >/dev/null -python -m decocare.stick $(python -m decocare.scan) >/dev/null && echo "decocare.scan OK" || sudo ~/openaps-js/bin/fix-dead-carelink.sh | tee -a /var/log/openaps/easy.log - -# sometimes git gets stuck -find ~/openaps-dev/.git/index.lock -mmin +5 -exec rm {} \; 2>/dev/null > /dev/null -cd ~/openaps-dev && ( git status > /dev/null || ( mv ~/openaps-dev/.git /tmp/.git-`date +%s`; cd && openaps init openaps-dev && cd openaps-dev ) ) -# sometimes openaps.ini gets truncated -openaps report show > /dev/null || cp openaps.ini.bak openaps.ini - -function finish { - rm /tmp/openaps.lock -} -trap finish EXIT - -# define functions for everything we'll be doing - -# get glucose data, either from attached CGM or from Share -getglucose() { - echo "Querying CGM" - ( ( openaps report invoke glucose.json.new || openaps report invoke glucose.json.new ) && grep -v '"glucose": 5' glucose.json.new | grep glucose ) || share2-bridge file glucose.json.new - if diff -u glucose.json glucose.json.new; then - echo No new glucose data - else - grep glucose glucose.json.new | head -1 | awk '{print $2}' | while read line; do echo -n " $line "; done >> /var/log/openaps/easy.log \ - && rsync -tu glucose.json.new glucose.json \ - && git commit -m"glucose.json has glucose data: committing" glucose.json - fi -} -# get pump status (suspended, etc.) -getpumpstatus() { - echo "Checking pump status" - openaps status || echo -n "!" >> /var/log/openaps/easy.log - grep -q status status.json.new && ( rsync -tu status.json.new status.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log -} -# query pump, and update pump data files if successful -querypump() { - openaps pumpquery || openaps pumpquery || echo -n "!" >> /var/log/openaps/easy.log - findclocknew && grep T clock.json.new && ( rsync -tu clock.json.new clock.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log - grep -q temp currenttemp.json.new && ( rsync -tu currenttemp.json.new currenttemp.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log - grep -q timestamp pumphistory.json.new && ( rsync -tu pumphistory.json.new pumphistory.json && echo -n "." >> /var/log/openaps/easy.log ) || echo -n "!" >> /var/log/openaps/easy.log - upload -} -# try to upload pumphistory data -upload() { - #findpumphistory && ~/bin/openaps-mongo.sh & - ping -c 1 google.com > /dev/null && touch /tmp/openaps.online -} -# if we haven't uploaded successfully in 10m, use offline mode (if no temp running, set current basal as temp to show the loop is working) -suggest() { - openaps suggest || echo -n "!" >> /var/log/openaps/easy.log - grep -q "too old" requestedtemp.online.json || ( find /tmp/openaps.online -mmin -10 | egrep -q '.*' && rsync -tu requestedtemp.online.json requestedtemp.json || rsync -tu requestedtemp.offline.json requestedtemp.json ) -} -# get updated pump settings (basal schedules, targets, ISF, etc.) -getpumpsettings() { ~/openaps-js/bin/pumpsettings.sh; } - -# functions for making sure we have up-to-date data before proceeding -findclocknew() { find clock.json.new -mmin -10 | egrep -q '.*'; } -findglucose() { find glucose.json -mmin -10 | egrep -q '.*'; } -findpumphistory() { find pumphistory.json -mmin -10 | egrep -q '.*'; } -findrequestedtemp() { find requestedtemp.json -mmin -10 | egrep -q '.*'; } -# write out current status to pebble.json -pebble() { ~/openaps-js/bin/pebble.sh; } - - -# main event loop - -getglucose -head -15 glucose.json - -numprocs=$(fuser -n file $(python -m decocare.scan) 2>&1 | wc -l) -if [[ $numprocs -gt 0 ]] ; then - die "Carelink USB already in use or not available." -fi - -getpumpstatus -echo "Querying pump" && querypump - -upload - -# get glucose again in case the pump queries took awhile -getglucose - -# if we're offline, set the clock to the pump/CGM time -~/openaps-js/bin/clockset.sh - -# dump out a "what we're about to try to do" report -suggest && pebble - -tail clock.json -tail currenttemp.json - -# make sure we're not using an old suggestion -rm requestedtemp* -# if we can't run suggest, it might be because our pumpsettings are missing or screwed up" -suggest || ( getpumpsettings && suggest ) || die "Can't calculate IOB or basal" -pebble -tail profile.json -tail iob.json -tail requestedtemp.json - -# don't act on stale glucose data -findglucose && grep -q glucose glucose.json || die "No recent glucose data" -# execute/enact the requested temp -cat requestedtemp.json | json_pp | grep reason >> /var/log/openaps/easy.log -grep -q rate requestedtemp.json && ( openaps enact || openaps enact ) && tail enactedtemp.json && ( echo && cat enactedtemp.json | egrep -i "bg|rate|dur|re|tic|tim" | sort -r ) >> /var/log/openaps/easy.log && cat iob.json | json_pp | grep '"iob' >> /var/log/openaps/easy.log - -echo "Re-querying pump" -query pump - -# unlock in case upload is really slow -rm /tmp/openaps.lock -pebble -upload - -# if another instance didn't start while we were uploading, refresh pump settings -ls /tmp/openaps.lock >/dev/null 2>/dev/null && die "OpenAPS already running: exiting" && exit -touch /tmp/openaps.lock -getpumpsettings diff --git a/bin/loop.sh b/bin/loop.sh new file mode 120000 index 0000000..3efe45d --- /dev/null +++ b/bin/loop.sh @@ -0,0 +1 @@ +../../openaps-sh/loop.sh \ No newline at end of file From b844c0ce542bf0565399ba6ae3932d34cd2672d0 Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 14 Oct 2015 22:00:21 -0700 Subject: [PATCH 116/131] check /sys/devices/platform/bcm2708_usb/buspower and /sys/devices/platform/soc/3f980000.usb/buspower and use whichever exists --- bin/reset-usb.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 bin/reset-usb.sh diff --git a/bin/reset-usb.sh b/bin/reset-usb.sh new file mode 100755 index 0000000..19d5dfe --- /dev/null +++ b/bin/reset-usb.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# Power-cycle the Raspberry Pi USB bus to reset attached USB devices +# +# 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. + +# Raspberry Pi 1 running Raspbian Wheezy +FILE=/sys/devices/platform/bcm2708_usb/buspower +if [ ! -e $FILE ]; then +# Raspberry Pi 2 running Raspbian Jessie + FILE=/sys/devices/platform/soc/3f980000.usb/buspower +fi +if [ -e $FILE ]; then + echo "Power-cycling USB to fix dead Carelink stick" + sleep 0.1 + echo 0 > $FILE + sleep 1 + echo 1 > $FILE + sleep 2 +else + echo "Could not find a known USB power control device. Checking /sys/devices/platform/:" + find /sys/devices/platform/* | grep buspower +fi + From 435c5c2fd2dc45eac3126134e83c86c2349131fc Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Wed, 14 Oct 2015 22:03:07 -0700 Subject: [PATCH 117/131] rename reset-wifi-dongle.sh to reset-usb.sh --- bin/reset-wifi-dongle.sh | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100755 bin/reset-wifi-dongle.sh diff --git a/bin/reset-wifi-dongle.sh b/bin/reset-wifi-dongle.sh deleted file mode 100755 index b728725..0000000 --- a/bin/reset-wifi-dongle.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh - -# Power-cycle the Raspberry Pi USB bus to reset attached USB devices -# -# 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. - -echo "Power-cycling USB to fix dead Carelink stick" -sleep 0.1 -echo 0 > /sys/devices/platform/bcm2708_usb/buspower -sleep 1 -echo 1 > /sys/devices/platform/bcm2708_usb/buspower -sleep 2 From 5dcc09b54bd434b9ef5bb70ea221ef022bdef78a Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 16 Oct 2015 22:30:15 -0700 Subject: [PATCH 118/131] hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong --- bin/oref0-get-profile.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index 8c9d564..3b9771d 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -53,8 +53,9 @@ function bgTargetsLookup(){ break; } } - profile.max_bg = bgTargets.high; - profile.min_bg = bgTargets.low; + // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong + profile.max_bg = max(100,bgTargets.high); + profile.min_bg = max(90,bgTargets.low); } function carbRatioLookup() { From 58aa795acefd726c619002394425b5465bc4208e Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 16 Oct 2015 22:40:17 -0700 Subject: [PATCH 119/131] hard-code upper bound for min_bg in case pump is set too high --- bin/oref0-get-profile.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index 3b9771d..30dbeea 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -56,6 +56,8 @@ function bgTargetsLookup(){ // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong profile.max_bg = max(100,bgTargets.high); profile.min_bg = max(90,bgTargets.low); + // hard-code upper bound for min_bg in case pump is set too high + profile.min_bg = min(200,profile.min_bg); } function carbRatioLookup() { From 513a89ce8b03bb4efd650770dc939cff169abcff Mon Sep 17 00:00:00 2001 From: Scott Leibrand Date: Fri, 16 Oct 2015 22:55:44 -0700 Subject: [PATCH 120/131] this should cause get-profile to fail if bg_target units aren't in mg/dL --- bin/oref0-get-profile.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index 30dbeea..98fa572 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -45,6 +45,11 @@ function bgTargetsLookup(){ var now = new Date(); //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset }); + if (bgtargets_data.units != "mg/dL") { + console.error("bg_target units of " + bgtargets_data.units + " not supported: please use read_bg_targets_mg_dl."); + break; + } + var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1] for (var i = 0; i < bgtargets_data.targets.length - 1; i++) { From 718476bfe4ff5bbb8b8df172cfaa7256277916fc Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 13:31:41 -0700 Subject: [PATCH 121/131] fix js errors, error in case of unexpected units Eliminate illegal js, break keyword is not allowed outside of loops/switches. Cause process to error out in case of mmol. Prevent errors like this: foo$ oref0-get-profile monitor/pump-history.json tagrgets-mm ol.json /usr/local/lib/node_modules/openaps-js/bin/oref0-get-profile.js:50 break; ^^^^^ SyntaxError: Illegal break statement at Module._compile (module.js:439:25) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) at startup (node.js:119:16) at node.js:901:3 bewest@hither:~/Documents/foo$ In favor of errors like this: o$ oref0-get-profile monitor/pump-history.json tagrgets-mmol.json monitor/insulin-sensitivities.json monitor/active-basal-profile.json monitor/carb-ratios.json max_iob.json BG Target data is expected to be expressed in mg/dL. Found mmol/L in tagrgets-mmol.json . bewest@hither:~/Documents/foo$ --- bin/oref0-get-profile.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index 98fa572..85ab779 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -45,10 +45,6 @@ function bgTargetsLookup(){ var now = new Date(); //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset }); - if (bgtargets_data.units != "mg/dL") { - console.error("bg_target units of " + bgtargets_data.units + " not supported: please use read_bg_targets_mg_dl."); - break; - } var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1] @@ -122,6 +118,11 @@ if (!module.parent) { var cwd = process.cwd() var pumpsettings_data = require(cwd + '/' + pumpsettings_input); var bgtargets_data = require(cwd + '/' + bgtargets_input); + if (bgtargets_data.units !== 'mg/dL') { + console.log('BG Target data is expected to be expressed in mg/dL.' + , 'Found', bgtargets_data.units, 'in', bgtargets_input, '.'); + process.exit(2); + } var isf_data = require(cwd + '/' + isf_input); var basalprofile_data = require(cwd + '/' + basalprofile_input); var carbratio_data = require(cwd + '/' + carbratio_input);; From 0644cb1e51d0cda2c8215f4b3624c5fd38ef94f0 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 13:34:14 -0700 Subject: [PATCH 122/131] make sure the package.json matches the actual file If the file names don't match, the package will refuse to install. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index abdf4ec..bef7800 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", "oref0-get-profile": "./bin/oref0-get-profile.js", "oref0-ifttt-notify": "./bin/oref0-ifttt-notify", - "reset-wifi-dongle": "bin/reset-wifi-dongle.sh", + "oref0-reset-usb": "bin/reset-usb.sh", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", "oref0": "./bin/oref0.sh", From eda93d32d566299403a544dd734a5709c84f25d4 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 14:09:08 -0700 Subject: [PATCH 123/131] allow tests to run/pass --- Makefile | 2 +- package.json | 4 ++++ tests/determine-basal.test.js | 4 ++-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index fc6528e..6e0d73e 100644 --- a/Makefile +++ b/Makefile @@ -3,4 +3,4 @@ TESTS=tests/*.js all: test test: - mocha ${TESTS} + ./node_modules/.bin/mocha ${TESTS} diff --git a/package.json b/package.json index bef7800..dc4f2c9 100644 --- a/package.json +++ b/package.json @@ -35,5 +35,9 @@ "homepage": "https://github.com/openaps/openaps-js", "dependencies": { "share2nightscout-bridge": "^0.1.5" + }, + "devDependencies": { + "mocha": "^2.3.3", + "should": "^7.1.0" } } diff --git a/tests/determine-basal.test.js b/tests/determine-basal.test.js index e296b34..f72970e 100644 --- a/tests/determine-basal.test.js +++ b/tests/determine-basal.test.js @@ -3,7 +3,7 @@ require('should'); describe('setTempBasal', function ( ) { - var determinebasal = require('../bin/determine-basal')(); + var determinebasal = require('../bin/oref0-determine-basal')(); //function setTempBasal(rate, duration, profile, requestedTemp) @@ -56,7 +56,7 @@ describe('setTempBasal', function ( ) { }); describe('determine-basal', function ( ) { - var determinebasal = require('../bin/determine-basal')(); + var determinebasal = require('../bin/oref0-determine-basal')(); //function determine_basal(glucose_status, currenttemp, iob_data, profile) From d1abb74df84e53f62deb618f06483e409e843abd Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 15:36:25 -0700 Subject: [PATCH 124/131] name package to oref0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index dc4f2c9..8eb544a 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "openaps-js", + "name": "oref0", "version": "0.0.8", "description": "openaps js plugins", "scripts": { From 609159c1b246eede6660b7d2fb54fb24b72ec2ef Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 15:36:48 -0700 Subject: [PATCH 125/131] just change permission to make it executable --- bin/send-tempbasal-Azure.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 bin/send-tempbasal-Azure.js diff --git a/bin/send-tempbasal-Azure.js b/bin/send-tempbasal-Azure.js old mode 100644 new mode 100755 From 7aaebd3d0b8a20a82e3dcd3ffd9bcca633c8c3cd Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 15:38:36 -0700 Subject: [PATCH 126/131] refactor, reorganize into source modules Make simpler modules that can be require'd, tested, and re-used with ease. --- bin/oref0-get-profile.js | 113 +++++---------------------------------- lib/medtronic-clock.js | 12 +++++ lib/profile/basal.js | 39 ++++++++++++++ lib/profile/carbs.js | 21 ++++++++ lib/profile/index.js | 44 +++++++++++++++ lib/profile/isf.js | 22 ++++++++ lib/profile/targets.js | 42 +++++++++++++++ 7 files changed, 194 insertions(+), 99 deletions(-) create mode 100644 lib/medtronic-clock.js create mode 100644 lib/profile/basal.js create mode 100644 lib/profile/carbs.js create mode 100644 lib/profile/index.js create mode 100644 lib/profile/isf.js create mode 100644 lib/profile/targets.js diff --git a/bin/oref0-get-profile.js b/bin/oref0-get-profile.js index 85ab779..d5df8f3 100755 --- a/bin/oref0-get-profile.js +++ b/bin/oref0-get-profile.js @@ -16,90 +16,7 @@ */ -function getTime(minutes) { - var baseTime = new Date(); - baseTime.setHours('00'); - baseTime.setMinutes('00'); - baseTime.setSeconds('00'); - - return baseTime.getTime() + minutes * 60 * 1000; - -} - -/* Return basal rate(U / hr) at the provided timeOfDay */ - -function basalLookup() { - var now = new Date(); - var basalRate = basalprofile_data[basalprofile_data.length-1].rate - - for (var i = 0; i < basalprofile_data.length - 1; i++) { - if ((now >= getTime(basalprofile_data[i].minutes)) && (now < getTime(basalprofile_data[i + 1].minutes))) { - basalRate = basalprofile_data[i].rate; - break; - } - } - profile.current_basal= Math.round(basalRate*1000)/1000; -} - -function bgTargetsLookup(){ - var now = new Date(); - - //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset }); - - var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1] - - for (var i = 0; i < bgtargets_data.targets.length - 1; i++) { - if ((now >= getTime(bgtargets_data.targets[i].offset)) && (now < getTime(bgtargets_data.targets[i + 1].offset))) { - bgTargets = bgtargets_data.targets[i]; - break; - } - } - // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong - profile.max_bg = max(100,bgTargets.high); - profile.min_bg = max(90,bgTargets.low); - // hard-code upper bound for min_bg in case pump is set too high - profile.min_bg = min(200,profile.min_bg); -} - -function carbRatioLookup() { - var now = new Date(); - //carbratio_data.schedule.sort(function (a, b) { return a.offset > b.offset }); - var carbRatio = carbratio_data.schedule[carbratio_data.schedule.length - 1] - - for (var i = 0; i < carbratio_data.schedule.length - 1; i++) { - if ((now >= getTime(carbratio_data.schedule[i].offset)) && (now < getTime(carbratio_data.schedule[i + 1].offset))) { - carbRatio = carbratio_data.schedule[i]; - break; - } - } - profile.carbratio = carbRatio.ratio; -} - -function isfLookup() { - var now = new Date(); - //isf_data.sensitivities.sort(function (a, b) { return a.offset > b.offset }); - var isfSchedule = isf_data.sensitivities[isf_data.sensitivities.length - 1] - - for (var i = 0; i < isf_data.sensitivities.length - 1; i++) { - if ((now >= getTime(isf_data.sensitivities[i].offset)) && (now < getTime(isf_data.sensitivities[i + 1].offset))) { - isfSchedule = isf_data.sensitivities[i]; - break; - } - } - profile.sens = isfSchedule.sensitivity; -} - -function maxDailyBasal(){ - basalprofile_data.sort(function (a, b) { if (a.rate < b.rate) { return 1 } if (a.rate > b.rate) { return -1; } return 0; }); - profile.max_daily_basal = Math.round( basalprofile_data[0].rate *1000)/1000; -} - -/*Return maximum daily basal rate(U / hr) from profile.basals */ - -function maxBasalLookup() { - - profile.max_basal =pumpsettings_data.maxBasal; -} +var generate = require('oref0/lib/profile/'); if (!module.parent) { @@ -127,23 +44,21 @@ if (!module.parent) { var basalprofile_data = require(cwd + '/' + basalprofile_input); var carbratio_data = require(cwd + '/' + carbratio_input);; - var profile = { - carbs_hr: 28 // TODO: verify this is completely unused and consider removing it if so - , max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have - , dia: pumpsettings_data.insulin_action_curve - , type: "current" - }; - - basalLookup(); - maxDailyBasal(); - maxBasalLookup() - bgTargetsLookup(); - carbRatioLookup(); - isfLookup(); + var maxiob_data = { max_iob: 0 }; if (typeof maxiob_input != 'undefined') { - var maxiob_data = require(cwd + '/' + maxiob_input); - profile.max_iob = maxiob_data.max_iob; + maxiob_data = require(cwd + '/' + maxiob_input); } + var inputs = { + settings: pumpsettings_data + , targets: bgtargets_data + , basals: basalprofile_data + , isf: isf_data + , max_iob: maxiob_data.max_iob || 0 + , carbs: carbratio_data + + }; + + var profile = generate(inputs); console.log(JSON.stringify(profile)); } diff --git a/lib/medtronic-clock.js b/lib/medtronic-clock.js new file mode 100644 index 0000000..5c319b6 --- /dev/null +++ b/lib/medtronic-clock.js @@ -0,0 +1,12 @@ + +function getTime(minutes) { + var baseTime = new Date(); + baseTime.setHours('00'); + baseTime.setMinutes('00'); + baseTime.setSeconds('00'); + + return baseTime.getTime() + minutes * 60 * 1000; +} + +exports = module.exports = getTime; + diff --git a/lib/profile/basal.js b/lib/profile/basal.js new file mode 100644 index 0000000..e53010f --- /dev/null +++ b/lib/profile/basal.js @@ -0,0 +1,39 @@ + +var getTime = require('../medtronic-clock'); + +/* Return basal rate(U / hr) at the provided timeOfDay */ +function basalLookup (schedules) { + basalprofile_data = schedules; + var now = new Date(); + var basalRate = basalprofile_data[basalprofile_data.length-1].rate + + for (var i = 0; i < basalprofile_data.length - 1; i++) { + if ((now >= getTime(basalprofile_data[i].minutes)) && (now < getTime(basalprofile_data[i + 1].minutes))) { + basalRate = basalprofile_data[i].rate; + break; + } + } + // profile.current_basal= Math.round(basalRate*1000)/1000; + return Math.round(basalRate*1000)/1000; +} + + +function maxDailyBasal (inputs) { + var basalprofile_data = inputs.basals; + basalprofile_data.sort(function (a, b) { if (a.rate < b.rate) { return 1 } if (a.rate > b.rate) { return -1; } return 0; }); + return Math.round( basalprofile_data[0].rate *1000)/1000; + profile.max_daily_basal = Math.round( basalprofile_data[0].rate *1000)/1000; +} + +/*Return maximum daily basal rate(U / hr) from profile.basals */ + +function maxBasalLookup (inputs) { + + return inputs.settings.maxBasal; + profile.max_basal = pumpsettings_data.maxBasal; +} + + +exports.maxDailyBasal = maxDailyBasal; +exports.maxBasalLookup = maxBasalLookup; +exports.basalLookup = basalLookup; diff --git a/lib/profile/carbs.js b/lib/profile/carbs.js new file mode 100644 index 0000000..74cc503 --- /dev/null +++ b/lib/profile/carbs.js @@ -0,0 +1,21 @@ + +var getTime = require('../medtronic-clock'); + +function carbRatioLookup (inputs) { + var now = new Date(); + var carbratio_data = inputs.carbs; + //carbratio_data.schedule.sort(function (a, b) { return a.offset > b.offset }); + var carbRatio = carbratio_data.schedule[carbratio_data.schedule.length - 1] + + for (var i = 0; i < carbratio_data.schedule.length - 1; i++) { + if ((now >= getTime(carbratio_data.schedule[i].offset)) && (now < getTime(carbratio_data.schedule[i + 1].offset))) { + carbRatio = carbratio_data.schedule[i]; + break; + } + } + return carbRatio.ratio; + profile.carbratio = carbRatio.ratio; +} + +carbRatioLookup.carbRatioLookup = carbRatioLookup; +exports = module.exports = carbRatioLookup; diff --git a/lib/profile/index.js b/lib/profile/index.js new file mode 100644 index 0000000..4849b13 --- /dev/null +++ b/lib/profile/index.js @@ -0,0 +1,44 @@ + +var basal = require('./basal'); +var targets = require('./targets'); +var carbs = require('./carbs'); +var isf = require('./isf'); + +function defaults ( ) { + var profile = { + carbs_hr: 28 // TODO: verify this is completely unused and consider removing it if so + , max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have + // , dia: pumpsettings_data.insulin_action_curve + , type: "current" + }; + return profile; +} + +function generate (inputs, opts) { + var profile = opts && opts.type ? opts : defaults( ); + + if (inputs.settings.insulin_action_curve) { + profile.dia = pumpsettings_data.insulin_action_curve; + } + + if (inputs.max_iob) { + profile.max_iob = inputs.max_iob; + } + + profile.current_basal = basal.basalLookup(inputs.basals); + profile.max_daily_basal = basal.maxDailyBasal(inputs); + profile.max_basal = basal.maxBasalLookup(inputs); + + var range = targets.bgTargetsLookup(inputs); + profile.min_bg = range.min_bg; + profile.max_bg = range.max_bg; + profile.carbratio = carbs.carbRatioLookup(inputs); + profile.sens = isf.isfLookup(inputs); + + return profile; +} + + +generate.defaults = defaults; +exports = module.exports = generate; + diff --git a/lib/profile/isf.js b/lib/profile/isf.js new file mode 100644 index 0000000..304eb0a --- /dev/null +++ b/lib/profile/isf.js @@ -0,0 +1,22 @@ + +var getTime = require('../medtronic-clock'); + +function isfLookup (inputs) { + var now = new Date(); + var isf_data = inputs.isf; + //isf_data.sensitivities.sort(function (a, b) { return a.offset > b.offset }); + var isfSchedule = isf_data.sensitivities[isf_data.sensitivities.length - 1] + + for (var i = 0; i < isf_data.sensitivities.length - 1; i++) { + if ((now >= getTime(isf_data.sensitivities[i].offset)) && (now < getTime(isf_data.sensitivities[i + 1].offset))) { + isfSchedule = isf_data.sensitivities[i]; + break; + } + } + return isfSchedule.sensitivity; + profile.sens = isfSchedule.sensitivity; +} + +isfLookup.isfLookup = isfLookup; +exports = module.exports = isfLookup; + diff --git a/lib/profile/targets.js b/lib/profile/targets.js new file mode 100644 index 0000000..fefaf35 --- /dev/null +++ b/lib/profile/targets.js @@ -0,0 +1,42 @@ + +var getTime = require('../medtronic-clock'); + +function bgTargetsLookup (inputs) { + return bound_target_range(lookup(inputs)); +} + +function lookup (inputs) { + var bgtargets_data = inputs.targets; + var now = new Date(); + + //bgtargets_data.targets.sort(function (a, b) { return a.offset > b.offset }); + + var bgTargets = bgtargets_data.targets[bgtargets_data.targets.length - 1] + + for (var i = 0; i < bgtargets_data.targets.length - 1; i++) { + if ((now >= getTime(bgtargets_data.targets[i].offset)) && (now < getTime(bgtargets_data.targets[i + 1].offset))) { + bgTargets = bgtargets_data.targets[i]; + break; + } + } + return bgTargets; + // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong + profile.max_bg = max(100,bgTargets.high); + profile.min_bg = max(90,bgTargets.low); + // hard-code upper bound for min_bg in case pump is set too high + profile.min_bg = min(200,profile.min_bg); +} + +function bound_target_range (target) { + target.max_bg = Math.max(100, target.high); + target.min_bg = Math.max(90, target.low); + // hard-code upper bound for min_bg in case pump is set too high + target.min_bg = Math.min(200, target.min_bg); + return target +} + +bgTargetsLookup.bgTargetsLookup = bgTargetsLookup; +bgTargetsLookup.lookup = lookup; +bgTargetsLookup.bound_target_range = bound_target_range; +exports = module.exports = bgTargetsLookup; + From 273bd0efeec55931cef5a3801df514f41ee2ebf8 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 16:58:44 -0700 Subject: [PATCH 127/131] refactor calculate-iob to be more testable/reusable --- bin/oref0-calculate-iob.js | 174 +++---------------------------------- lib/iob/calculate.js | 45 ++++++++++ lib/iob/history.js | 71 +++++++++++++++ lib/iob/index.js | 24 +++++ lib/iob/total.js | 38 ++++++++ package.json | 3 +- 6 files changed, 190 insertions(+), 165 deletions(-) create mode 100644 lib/iob/calculate.js create mode 100644 lib/iob/history.js create mode 100644 lib/iob/index.js create mode 100644 lib/iob/total.js diff --git a/bin/oref0-calculate-iob.js b/bin/oref0-calculate-iob.js index 7e92bc3..1f75a8c 100755 --- a/bin/oref0-calculate-iob.js +++ b/bin/oref0-calculate-iob.js @@ -18,153 +18,7 @@ */ -function iobCalc(treatment, time, dia) { - var diaratio = dia / 3; - var peak = 75 ; - var end = 180 ; - //var sens = profile_data.sens; - if (typeof time === 'undefined') { - var time = new Date(); - } - - if (treatment.insulin) { - var bolusTime=new Date(treatment.date); - var minAgo=(time-bolusTime)/1000/60 * diaratio; - - if (minAgo < 0) { - var iobContrib=0; - var activityContrib=0; - } - else 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; - } - return { - iobContrib: iobContrib, - activityContrib: activityContrib - }; - } - else { - return ''; - } -} -function iobTotal(treatments, time) { - var iob = 0; - var bolusiob = 0; - var activity = 0; - if (!treatments) return {}; - //if (typeof time === 'undefined') { - //var time = new Date(); - //} - - treatments.forEach(function(treatment) { - 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) - //console.log(treatment); - //console.log(bIOB); - if (bIOB && bIOB.iobContrib) bolusiob += bIOB.iobContrib; - } - } - }); - - return { - iob: iob, - activity: activity, - bolusiob: bolusiob - }; -} - -function calcTempTreatments() { - var tempHistory = []; - var tempBoluses = []; - var now = new Date(); - 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) { - if (pumpHistory[i]._type == "Bolus") { - //console.log(pumpHistory[i]); - var temp = {}; - temp.timestamp = current.timestamp; - //temp.started_at = new Date(current.date); - temp.started_at = new Date(current.timestamp + timeZone); - //temp.date = current.date - temp.date = temp.started_at.getTime(); - temp.insulin = current.amount - tempBoluses.push(temp); - } else if (pumpHistory[i]._type == "TempBasal") { - if (current.temp == 'percent') { - continue; - } - var rate = pumpHistory[i].rate; - var date = pumpHistory[i].date; - if (i>0 && pumpHistory[i-1].date == date && pumpHistory[i-1]._type == "TempBasalDuration") { - var duration = pumpHistory[i-1]['duration (min)']; - } else if (i+1 tempHistory[i+1].date) { - tempHistory[i].duration = (tempHistory[i+1].date - tempHistory[i].date)/60/1000; - } - } - var tempBolusSize; - var now = new Date(); - 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; - if (netBasalRate < 0) { tempBolusSize = -0.05; } - else { tempBolusSize = 0.05; } - var netBasalAmount = Math.round(netBasalRate*tempHistory[i].duration*10/6)/100 - var tempBolusCount = Math.round(netBasalAmount / tempBolusSize); - var tempBolusSpacing = tempHistory[i].duration / tempBolusCount; - for (var j=0; j < tempBolusCount; j++) { - var tempBolus = {}; - tempBolus.insulin = tempBolusSize; - tempBolus.date = tempHistory[i].date + j * tempBolusSpacing*60*1000; - tempBolus.created_at = new Date(tempBolus.date); - tempBoluses.push(tempBolus); - } - } - } - return [ ].concat(tempBoluses).concat(tempHistory); - return { - tempBoluses: tempBoluses, - tempHistory: tempHistory - }; - -} +var generate = require('oref0/lib/iob'); if (!module.parent) { var iob_input = process.argv.slice(2, 3).pop() @@ -178,24 +32,16 @@ if (!module.parent) { var all_data = require(cwd + '/' + iob_input); var profile_data = require(cwd + '/' + profile_input); var clock_data = require(cwd + '/' + clock_input); - var pumpHistory = all_data; - pumpHistory.reverse( ); - - var all_treatments = calcTempTreatments( ); - //console.log(all_treatments); - var treatments = all_treatments; // .tempBoluses.concat(all_treatments.tempHistory); - treatments.sort(function (a, b) { return a.date > b.date }); - //var lastTimestamp = new Date(treatments[treatments.length -1].date + 1000 * 60); - //console.log(clock_data); - var now = new Date(); - var timeZone = now.toString().match(/([-\+][0-9]+)\s/)[1] - var clock_iso = clock_data + timeZone; - var clock = new Date(clock_iso); - //console.log(clock); - var iob = iobTotal(treatments, clock); - //var iobs = iobTotal(treatments, lastTimestamp); - // console.log(iobs); + all_data.sort(function (a, b) { return a.date > b.date }); + + var inputs = { + history: all_data + , profile: profile_data + , clock: clock_data + }; + + var iob = generate(inputs); console.log(JSON.stringify(iob)); } diff --git a/lib/iob/calculate.js b/lib/iob/calculate.js new file mode 100644 index 0000000..e1d9ee8 --- /dev/null +++ b/lib/iob/calculate.js @@ -0,0 +1,45 @@ + +function iobCalc(treatment, time, dia) { + var diaratio = dia / 3; + var peak = 75 ; + var end = 180 ; + //var sens = profile_data.sens; + if (typeof time === 'undefined') { + var time = new Date(); + } + + if (treatment.insulin) { + var bolusTime=new Date(treatment.date); + var minAgo=(time-bolusTime)/1000/60 * diaratio; + + if (minAgo < 0) { + var iobContrib=0; + var activityContrib=0; + } + else 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; + } + return { + iobContrib: iobContrib, + activityContrib: activityContrib + }; + } + else { + return ''; + } +} + +exports = module.exports = iobCalc; diff --git a/lib/iob/history.js b/lib/iob/history.js new file mode 100644 index 0000000..70eada2 --- /dev/null +++ b/lib/iob/history.js @@ -0,0 +1,71 @@ + +function calcTempTreatments (inputs) { + var pumpHistory = inputs.history; + var tempHistory = []; + var tempBoluses = []; + var now = new Date(); + 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) { + if (pumpHistory[i]._type == "Bolus") { + //console.log(pumpHistory[i]); + var temp = {}; + temp.timestamp = current.timestamp; + //temp.started_at = new Date(current.date); + temp.started_at = new Date(current.timestamp + timeZone); + //temp.date = current.date + temp.date = temp.started_at.getTime(); + temp.insulin = current.amount + tempBoluses.push(temp); + } else if (pumpHistory[i]._type == "TempBasal") { + if (current.temp == 'percent') { + continue; + } + var rate = pumpHistory[i].rate; + var date = pumpHistory[i].date; + if (i>0 && pumpHistory[i-1].date == date && pumpHistory[i-1]._type == "TempBasalDuration") { + var duration = pumpHistory[i-1]['duration (min)']; + } else if (i+1 tempHistory[i+1].date) { + tempHistory[i].duration = (tempHistory[i+1].date - tempHistory[i].date)/60/1000; + } + } + var tempBolusSize; + var now = new Date(); + 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; + if (netBasalRate < 0) { tempBolusSize = -0.05; } + else { tempBolusSize = 0.05; } + var netBasalAmount = Math.round(netBasalRate*tempHistory[i].duration*10/6)/100 + var tempBolusCount = Math.round(netBasalAmount / tempBolusSize); + var tempBolusSpacing = tempHistory[i].duration / tempBolusCount; + for (var j=0; j < tempBolusCount; j++) { + var tempBolus = {}; + tempBolus.insulin = tempBolusSize; + tempBolus.date = tempHistory[i].date + j * tempBolusSpacing*60*1000; + tempBolus.created_at = new Date(tempBolus.date); + tempBoluses.push(tempBolus); + } + } + } + return [ ].concat(tempBoluses).concat(tempHistory); +} +exports = module.exports = calcTempTreatments; diff --git a/lib/iob/index.js b/lib/iob/index.js new file mode 100644 index 0000000..f89db33 --- /dev/null +++ b/lib/iob/index.js @@ -0,0 +1,24 @@ + +var tz = require('timezone'); +var find_insulin = require('./history'); +var calculate = require('./calculate'); +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 + , profile: inputs.profile + , calculate: calculate + }; + + var clock = new Date(tz(inputs.clock)); + + var iob = sum(opts, clock); + console.log(JSON.stringify(iob)); +} + +exports = module.exports = generate; diff --git a/lib/iob/total.js b/lib/iob/total.js new file mode 100644 index 0000000..eade937 --- /dev/null +++ b/lib/iob/total.js @@ -0,0 +1,38 @@ + +function iobTotal(opts, time) { + var iobCalc = opts.calculate; + var treatments = opts.treatments; + var profile_data = opts.profile; + var iob = 0; + var bolusiob = 0; + var activity = 0; + if (!treatments) return {}; + //if (typeof time === 'undefined') { + //var time = new Date(); + //} + + treatments.forEach(function(treatment) { + 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) + //console.log(treatment); + //console.log(bIOB); + if (bIOB && bIOB.iobContrib) bolusiob += bIOB.iobContrib; + } + } + }); + + return { + iob: iob, + activity: activity, + bolusiob: bolusiob + }; +} + +exports = module.exports = iobTotal; + diff --git a/package.json b/package.json index 8eb544a..8a42f86 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,8 @@ }, "homepage": "https://github.com/openaps/openaps-js", "dependencies": { - "share2nightscout-bridge": "^0.1.5" + "share2nightscout-bridge": "^0.1.5", + "timezone": "0.0.47" }, "devDependencies": { "mocha": "^2.3.3", From 11045cd989045674dec15deb43fa525bccbf9384 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 16:59:37 -0700 Subject: [PATCH 128/131] add .gitignore --- .gitignore | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fcbc57 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +bower_components/ +node_modules/ + + +bundle/bundle.out.js + +.idea/ +*.iml +my.env + +*.env +static/bower_components/ +.*.sw? +.DS_Store + +.vagrant +/iisnode + +# istanbul output +coverage/ + +npm-debug.log From a27b82e91e790cd110560e6d1573b0cfcc6e3e69 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 17:16:19 -0700 Subject: [PATCH 129/131] mostly whitespace tweaks, insert missing var keyword --- bin/oref0-calculate-iob.js | 16 +++++++++------- lib/profile/basal.js | 5 +---- lib/profile/index.js | 19 +++++++++---------- lib/profile/isf.js | 1 - lib/profile/targets.js | 7 ++----- 5 files changed, 21 insertions(+), 27 deletions(-) diff --git a/bin/oref0-calculate-iob.js b/bin/oref0-calculate-iob.js index 1f75a8c..19d21ef 100755 --- a/bin/oref0-calculate-iob.js +++ b/bin/oref0-calculate-iob.js @@ -21,17 +21,19 @@ 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 all_data = require(cwd + '/' + iob_input); - var profile_data = require(cwd + '/' + profile_input); - var clock_data = require(cwd + '/' + clock_input); + + 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); all_data.sort(function (a, b) { return a.date > b.date }); diff --git a/lib/profile/basal.js b/lib/profile/basal.js index e53010f..6cbda11 100644 --- a/lib/profile/basal.js +++ b/lib/profile/basal.js @@ -3,7 +3,7 @@ var getTime = require('../medtronic-clock'); /* Return basal rate(U / hr) at the provided timeOfDay */ function basalLookup (schedules) { - basalprofile_data = schedules; + var basalprofile_data = schedules; var now = new Date(); var basalRate = basalprofile_data[basalprofile_data.length-1].rate @@ -13,7 +13,6 @@ function basalLookup (schedules) { break; } } - // profile.current_basal= Math.round(basalRate*1000)/1000; return Math.round(basalRate*1000)/1000; } @@ -22,7 +21,6 @@ function maxDailyBasal (inputs) { var basalprofile_data = inputs.basals; basalprofile_data.sort(function (a, b) { if (a.rate < b.rate) { return 1 } if (a.rate > b.rate) { return -1; } return 0; }); return Math.round( basalprofile_data[0].rate *1000)/1000; - profile.max_daily_basal = Math.round( basalprofile_data[0].rate *1000)/1000; } /*Return maximum daily basal rate(U / hr) from profile.basals */ @@ -30,7 +28,6 @@ function maxDailyBasal (inputs) { function maxBasalLookup (inputs) { return inputs.settings.maxBasal; - profile.max_basal = pumpsettings_data.maxBasal; } diff --git a/lib/profile/index.js b/lib/profile/index.js index 4849b13..26ae5e9 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -6,7 +6,6 @@ var isf = require('./isf'); function defaults ( ) { var profile = { - carbs_hr: 28 // TODO: verify this is completely unused and consider removing it if so , max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have // , dia: pumpsettings_data.insulin_action_curve , type: "current" @@ -25,17 +24,17 @@ function generate (inputs, opts) { profile.max_iob = inputs.max_iob; } - profile.current_basal = basal.basalLookup(inputs.basals); - profile.max_daily_basal = basal.maxDailyBasal(inputs); - profile.max_basal = basal.maxBasalLookup(inputs); + profile.current_basal = basal.basalLookup(inputs.basals); + profile.max_daily_basal = basal.maxDailyBasal(inputs); + profile.max_basal = basal.maxBasalLookup(inputs); - var range = targets.bgTargetsLookup(inputs); - profile.min_bg = range.min_bg; - profile.max_bg = range.max_bg; - profile.carbratio = carbs.carbRatioLookup(inputs); - profile.sens = isf.isfLookup(inputs); + var range = targets.bgTargetsLookup(inputs); + profile.min_bg = range.min_bg; + profile.max_bg = range.max_bg; + profile.carbratio = carbs.carbRatioLookup(inputs); + profile.sens = isf.isfLookup(inputs); - return profile; + return profile; } diff --git a/lib/profile/isf.js b/lib/profile/isf.js index 304eb0a..e97504f 100644 --- a/lib/profile/isf.js +++ b/lib/profile/isf.js @@ -14,7 +14,6 @@ function isfLookup (inputs) { } } return isfSchedule.sensitivity; - profile.sens = isfSchedule.sensitivity; } isfLookup.isfLookup = isfLookup; diff --git a/lib/profile/targets.js b/lib/profile/targets.js index fefaf35..b3e7a2a 100644 --- a/lib/profile/targets.js +++ b/lib/profile/targets.js @@ -19,15 +19,12 @@ function lookup (inputs) { break; } } + return bgTargets; - // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong - profile.max_bg = max(100,bgTargets.high); - profile.min_bg = max(90,bgTargets.low); - // hard-code upper bound for min_bg in case pump is set too high - profile.min_bg = min(200,profile.min_bg); } function bound_target_range (target) { + // hard-code lower bounds for min_bg and max_bg in case pump is set too low, or units are wrong target.max_bg = Math.max(100, target.high); target.min_bg = Math.max(90, target.low); // hard-code upper bound for min_bg in case pump is set too high From 63dfeae80dcd417070cae609b7317c15e1cc3d57 Mon Sep 17 00:00:00 2001 From: Ben West Date: Sat, 17 Oct 2015 17:22:21 -0700 Subject: [PATCH 130/131] actually return iob result --- lib/iob/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iob/index.js b/lib/iob/index.js index f89db33..e50f4e6 100644 --- a/lib/iob/index.js +++ b/lib/iob/index.js @@ -18,7 +18,7 @@ function generate (inputs) { var clock = new Date(tz(inputs.clock)); var iob = sum(opts, clock); - console.log(JSON.stringify(iob)); + return iob; } exports = module.exports = generate; From 8e71f27da41967921205dfb157d6e5d12f497e0e Mon Sep 17 00:00:00 2001 From: Ben West Date: Sun, 18 Oct 2015 14:13:40 -0700 Subject: [PATCH 131/131] fix syntax error --- lib/profile/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/profile/index.js b/lib/profile/index.js index 26ae5e9..f601b6b 100644 --- a/lib/profile/index.js +++ b/lib/profile/index.js @@ -6,7 +6,7 @@ var isf = require('./isf'); function defaults ( ) { var profile = { - , max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have + max_iob: 0 // if max_iob.json is not profided, never give more insulin than the pump would have // , dia: pumpsettings_data.insulin_action_curve , type: "current" };